1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include "health.hpp" 19 #include "led.hpp" 20 #include "pcie.hpp" 21 #include "redfish_util.hpp" 22 23 #include <boost/container/flat_map.hpp> 24 #include <node.hpp> 25 #include <utils/fw_utils.hpp> 26 #include <utils/json_utils.hpp> 27 28 #include <variant> 29 30 namespace redfish 31 { 32 33 /** 34 * @brief Updates the Functional State of DIMMs 35 * 36 * @param[in] aResp Shared pointer for completing asynchronous calls 37 * @param[in] dimmState Dimm's Functional state, true/false 38 * 39 * @return None. 40 */ 41 inline void updateDimmProperties(std::shared_ptr<AsyncResp> aResp, 42 const std::variant<bool>& dimmState) 43 { 44 const bool* isDimmFunctional = std::get_if<bool>(&dimmState); 45 if (isDimmFunctional == nullptr) 46 { 47 messages::internalError(aResp->res); 48 return; 49 } 50 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 51 52 // Set it as Enabled if at least one DIMM is functional 53 // Update STATE only if previous State was DISABLED and current Dimm is 54 // ENABLED. 55 nlohmann::json& prevMemSummary = 56 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 57 if (prevMemSummary == "Disabled") 58 { 59 if (*isDimmFunctional == true) 60 { 61 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 62 "Enabled"; 63 } 64 } 65 } 66 67 /* 68 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 69 * 70 * @param[in] aResp Shared pointer for completing asynchronous calls 71 * @param[in] cpuPresenceState CPU present or not 72 * 73 * @return None. 74 */ 75 inline void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp, 76 const std::variant<bool>& cpuPresenceState) 77 { 78 const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState); 79 80 if (isCpuPresent == nullptr) 81 { 82 messages::internalError(aResp->res); 83 return; 84 } 85 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 86 87 if (*isCpuPresent == true) 88 { 89 nlohmann::json& procCount = 90 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 91 auto procCountPtr = 92 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 93 if (procCountPtr != nullptr) 94 { 95 // shouldn't be possible to be nullptr 96 *procCountPtr += 1; 97 } 98 } 99 } 100 101 /* 102 * @brief Update "ProcessorSummary" "Status" "State" based on 103 * CPU Functional State 104 * 105 * @param[in] aResp Shared pointer for completing asynchronous calls 106 * @param[in] cpuFunctionalState is CPU functional true/false 107 * 108 * @return None. 109 */ 110 inline void 111 modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp, 112 const std::variant<bool>& cpuFunctionalState) 113 { 114 const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 115 116 if (isCpuFunctional == nullptr) 117 { 118 messages::internalError(aResp->res); 119 return; 120 } 121 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 122 123 nlohmann::json& prevProcState = 124 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 125 126 // Set it as Enabled if at least one CPU is functional 127 // Update STATE only if previous State was Non_Functional and current CPU is 128 // Functional. 129 if (prevProcState == "Disabled") 130 { 131 if (*isCpuFunctional == true) 132 { 133 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 134 "Enabled"; 135 } 136 } 137 } 138 139 /* 140 * @brief Retrieves computer system properties over dbus 141 * 142 * @param[in] aResp Shared pointer for completing asynchronous calls 143 * @param[in] name Computer system name from request 144 * 145 * @return None. 146 */ 147 inline void getComputerSystem(std::shared_ptr<AsyncResp> aResp, 148 std::shared_ptr<HealthPopulate> systemHealth) 149 { 150 BMCWEB_LOG_DEBUG << "Get available system components."; 151 152 crow::connections::systemBus->async_method_call( 153 [aResp, systemHealth]( 154 const boost::system::error_code ec, 155 const std::vector<std::pair< 156 std::string, 157 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 158 subtree) { 159 if (ec) 160 { 161 BMCWEB_LOG_DEBUG << "DBUS response error"; 162 messages::internalError(aResp->res); 163 return; 164 } 165 // Iterate over all retrieved ObjectPaths. 166 for (const std::pair<std::string, 167 std::vector<std::pair< 168 std::string, std::vector<std::string>>>>& 169 object : subtree) 170 { 171 const std::string& path = object.first; 172 BMCWEB_LOG_DEBUG << "Got path: " << path; 173 const std::vector< 174 std::pair<std::string, std::vector<std::string>>>& 175 connectionNames = object.second; 176 if (connectionNames.size() < 1) 177 { 178 continue; 179 } 180 181 auto memoryHealth = std::make_shared<HealthPopulate>( 182 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 183 184 auto cpuHealth = std::make_shared<HealthPopulate>( 185 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 186 187 systemHealth->children.emplace_back(memoryHealth); 188 systemHealth->children.emplace_back(cpuHealth); 189 190 // This is not system, so check if it's cpu, dimm, UUID or 191 // BiosVer 192 for (const auto& connection : connectionNames) 193 { 194 for (const auto& interfaceName : connection.second) 195 { 196 if (interfaceName == 197 "xyz.openbmc_project.Inventory.Item.Dimm") 198 { 199 BMCWEB_LOG_DEBUG 200 << "Found Dimm, now get its properties."; 201 202 crow::connections::systemBus->async_method_call( 203 [aResp, service{connection.first}, 204 path(std::move(path))]( 205 const boost::system::error_code ec, 206 const std::vector< 207 std::pair<std::string, VariantType>>& 208 properties) { 209 if (ec) 210 { 211 BMCWEB_LOG_ERROR 212 << "DBUS response error " << ec; 213 messages::internalError(aResp->res); 214 return; 215 } 216 BMCWEB_LOG_DEBUG << "Got " 217 << properties.size() 218 << " Dimm properties."; 219 220 if (properties.size() > 0) 221 { 222 for (const std::pair<std::string, 223 VariantType>& 224 property : properties) 225 { 226 if (property.first != 227 "MemorySizeInKB") 228 { 229 continue; 230 } 231 const uint32_t* value = 232 std::get_if<uint32_t>( 233 &property.second); 234 if (value == nullptr) 235 { 236 BMCWEB_LOG_DEBUG 237 << "Find incorrect type of " 238 "MemorySize"; 239 continue; 240 } 241 nlohmann::json& totalMemory = 242 aResp->res 243 .jsonValue["MemorySummar" 244 "y"] 245 ["TotalSystemMe" 246 "moryGiB"]; 247 uint64_t* preValue = 248 totalMemory 249 .get_ptr<uint64_t*>(); 250 if (preValue == nullptr) 251 { 252 continue; 253 } 254 aResp->res 255 .jsonValue["MemorySummary"] 256 ["TotalSystemMemoryGi" 257 "B"] = 258 *value / (1024 * 1024) + 259 *preValue; 260 aResp->res 261 .jsonValue["MemorySummary"] 262 ["Status"]["State"] = 263 "Enabled"; 264 } 265 } 266 else 267 { 268 auto getDimmProperties = 269 [aResp]( 270 const boost::system::error_code 271 ec, 272 const std::variant<bool>& 273 dimmState) { 274 if (ec) 275 { 276 BMCWEB_LOG_ERROR 277 << "DBUS response " 278 "error " 279 << ec; 280 return; 281 } 282 updateDimmProperties(aResp, 283 dimmState); 284 }; 285 crow::connections::systemBus 286 ->async_method_call( 287 std::move(getDimmProperties), 288 service, path, 289 "org.freedesktop.DBus." 290 "Properties", 291 "Get", 292 "xyz.openbmc_project.State." 293 "Decorator.OperationalStatus", 294 "Functional"); 295 } 296 }, 297 connection.first, path, 298 "org.freedesktop.DBus.Properties", "GetAll", 299 "xyz.openbmc_project.Inventory.Item.Dimm"); 300 301 memoryHealth->inventory.emplace_back(path); 302 } 303 else if (interfaceName == 304 "xyz.openbmc_project.Inventory.Item.Cpu") 305 { 306 BMCWEB_LOG_DEBUG 307 << "Found Cpu, now get its properties."; 308 309 crow::connections::systemBus->async_method_call( 310 [aResp, service{connection.first}, 311 path(std::move(path))]( 312 const boost::system::error_code ec, 313 const std::vector< 314 std::pair<std::string, VariantType>>& 315 properties) { 316 if (ec) 317 { 318 BMCWEB_LOG_ERROR 319 << "DBUS response error " << ec; 320 messages::internalError(aResp->res); 321 return; 322 } 323 BMCWEB_LOG_DEBUG << "Got " 324 << properties.size() 325 << " Cpu properties."; 326 327 if (properties.size() > 0) 328 { 329 for (const auto& property : properties) 330 { 331 if (property.first == 332 "ProcessorFamily") 333 { 334 const std::string* value = 335 std::get_if<std::string>( 336 &property.second); 337 if (value != nullptr) 338 { 339 nlohmann::json& 340 procSummary = 341 aResp->res.jsonValue 342 ["ProcessorSumm" 343 "ary"]; 344 nlohmann::json& procCount = 345 procSummary["Count"]; 346 347 auto procCountPtr = 348 procCount.get_ptr< 349 nlohmann::json:: 350 number_integer_t*>(); 351 if (procCountPtr != nullptr) 352 { 353 // shouldn't be possible 354 // to be nullptr 355 *procCountPtr += 1; 356 } 357 procSummary["Status"] 358 ["State"] = 359 "Enabled"; 360 procSummary["Model"] = 361 *value; 362 } 363 } 364 } 365 } 366 else 367 { 368 auto getCpuPresenceState = 369 [aResp]( 370 const boost::system::error_code 371 ec, 372 const std::variant<bool>& 373 cpuPresenceCheck) { 374 if (ec) 375 { 376 BMCWEB_LOG_ERROR 377 << "DBUS response " 378 "error " 379 << ec; 380 return; 381 } 382 modifyCpuPresenceState( 383 aResp, cpuPresenceCheck); 384 }; 385 386 auto getCpuFunctionalState = 387 [aResp]( 388 const boost::system::error_code 389 ec, 390 const std::variant<bool>& 391 cpuFunctionalCheck) { 392 if (ec) 393 { 394 BMCWEB_LOG_ERROR 395 << "DBUS response " 396 "error " 397 << ec; 398 return; 399 } 400 modifyCpuFunctionalState( 401 aResp, cpuFunctionalCheck); 402 }; 403 // Get the Presence of CPU 404 crow::connections::systemBus 405 ->async_method_call( 406 std::move(getCpuPresenceState), 407 service, path, 408 "org.freedesktop.DBus." 409 "Properties", 410 "Get", 411 "xyz.openbmc_project.Inventory." 412 "Item", 413 "Present"); 414 415 // Get the Functional State 416 crow::connections::systemBus 417 ->async_method_call( 418 std::move( 419 getCpuFunctionalState), 420 service, path, 421 "org.freedesktop.DBus." 422 "Properties", 423 "Get", 424 "xyz.openbmc_project.State." 425 "Decorator." 426 "OperationalStatus", 427 "Functional"); 428 429 // Get the MODEL from 430 // xyz.openbmc_project.Inventory.Decorator.Asset 431 // support it later as Model is Empty 432 // currently. 433 } 434 }, 435 connection.first, path, 436 "org.freedesktop.DBus.Properties", "GetAll", 437 "xyz.openbmc_project.Inventory.Item.Cpu"); 438 439 cpuHealth->inventory.emplace_back(path); 440 } 441 else if (interfaceName == 442 "xyz.openbmc_project.Common.UUID") 443 { 444 BMCWEB_LOG_DEBUG 445 << "Found UUID, now get its properties."; 446 crow::connections::systemBus->async_method_call( 447 [aResp]( 448 const boost::system::error_code ec, 449 const std::vector< 450 std::pair<std::string, VariantType>>& 451 properties) { 452 if (ec) 453 { 454 BMCWEB_LOG_DEBUG 455 << "DBUS response error " << ec; 456 messages::internalError(aResp->res); 457 return; 458 } 459 BMCWEB_LOG_DEBUG << "Got " 460 << properties.size() 461 << " UUID properties."; 462 for (const std::pair<std::string, 463 VariantType>& 464 property : properties) 465 { 466 if (property.first == "UUID") 467 { 468 const std::string* value = 469 std::get_if<std::string>( 470 &property.second); 471 472 if (value != nullptr) 473 { 474 std::string valueStr = *value; 475 if (valueStr.size() == 32) 476 { 477 valueStr.insert(8, 1, '-'); 478 valueStr.insert(13, 1, '-'); 479 valueStr.insert(18, 1, '-'); 480 valueStr.insert(23, 1, '-'); 481 } 482 BMCWEB_LOG_DEBUG << "UUID = " 483 << valueStr; 484 aResp->res.jsonValue["UUID"] = 485 valueStr; 486 } 487 } 488 } 489 }, 490 connection.first, path, 491 "org.freedesktop.DBus.Properties", "GetAll", 492 "xyz.openbmc_project.Common.UUID"); 493 } 494 else if (interfaceName == 495 "xyz.openbmc_project.Inventory.Item.System") 496 { 497 crow::connections::systemBus->async_method_call( 498 [aResp]( 499 const boost::system::error_code ec, 500 const std::vector< 501 std::pair<std::string, VariantType>>& 502 propertiesList) { 503 if (ec) 504 { 505 // doesn't have to include this 506 // interface 507 return; 508 } 509 BMCWEB_LOG_DEBUG 510 << "Got " << propertiesList.size() 511 << " properties for system"; 512 for (const std::pair<std::string, 513 VariantType>& 514 property : propertiesList) 515 { 516 const std::string& propertyName = 517 property.first; 518 if ((propertyName == "PartNumber") || 519 (propertyName == "SerialNumber") || 520 (propertyName == "Manufacturer") || 521 (propertyName == "Model")) 522 { 523 const std::string* value = 524 std::get_if<std::string>( 525 &property.second); 526 if (value != nullptr) 527 { 528 aResp->res 529 .jsonValue[propertyName] = 530 *value; 531 } 532 } 533 } 534 535 // Grab the bios version 536 fw_util::getActiveFwVersion( 537 aResp, fw_util::biosPurpose, 538 "BiosVersion", false); 539 }, 540 connection.first, path, 541 "org.freedesktop.DBus.Properties", "GetAll", 542 "xyz.openbmc_project.Inventory.Decorator." 543 "Asset"); 544 545 crow::connections::systemBus->async_method_call( 546 [aResp]( 547 const boost::system::error_code ec, 548 const std::variant<std::string>& property) { 549 if (ec) 550 { 551 // doesn't have to include this 552 // interface 553 return; 554 } 555 556 const std::string* value = 557 std::get_if<std::string>(&property); 558 if (value != nullptr) 559 { 560 aResp->res.jsonValue["AssetTag"] = 561 *value; 562 } 563 }, 564 connection.first, path, 565 "org.freedesktop.DBus.Properties", "Get", 566 "xyz.openbmc_project.Inventory.Decorator." 567 "AssetTag", 568 "AssetTag"); 569 } 570 } 571 } 572 } 573 }, 574 "xyz.openbmc_project.ObjectMapper", 575 "/xyz/openbmc_project/object_mapper", 576 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 577 "/xyz/openbmc_project/inventory", int32_t(0), 578 std::array<const char*, 5>{ 579 "xyz.openbmc_project.Inventory.Decorator.Asset", 580 "xyz.openbmc_project.Inventory.Item.Cpu", 581 "xyz.openbmc_project.Inventory.Item.Dimm", 582 "xyz.openbmc_project.Inventory.Item.System", 583 "xyz.openbmc_project.Common.UUID", 584 }); 585 } 586 587 /** 588 * @brief Retrieves host state properties over dbus 589 * 590 * @param[in] aResp Shared pointer for completing asynchronous calls. 591 * 592 * @return None. 593 */ 594 inline void getHostState(std::shared_ptr<AsyncResp> aResp) 595 { 596 BMCWEB_LOG_DEBUG << "Get host information."; 597 crow::connections::systemBus->async_method_call( 598 [aResp](const boost::system::error_code ec, 599 const std::variant<std::string>& hostState) { 600 if (ec) 601 { 602 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 603 messages::internalError(aResp->res); 604 return; 605 } 606 607 const std::string* s = std::get_if<std::string>(&hostState); 608 BMCWEB_LOG_DEBUG << "Host state: " << *s; 609 if (s != nullptr) 610 { 611 // Verify Host State 612 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 613 { 614 aResp->res.jsonValue["PowerState"] = "On"; 615 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 616 } 617 else if (*s == "xyz.openbmc_project.State.Host.HostState." 618 "Quiesced") 619 { 620 aResp->res.jsonValue["PowerState"] = "On"; 621 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 622 } 623 else if (*s == "xyz.openbmc_project.State.Host.HostState." 624 "DiagnosticMode") 625 { 626 aResp->res.jsonValue["PowerState"] = "On"; 627 aResp->res.jsonValue["Status"]["State"] = "InTest"; 628 } 629 else 630 { 631 aResp->res.jsonValue["PowerState"] = "Off"; 632 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 633 } 634 } 635 }, 636 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 637 "org.freedesktop.DBus.Properties", "Get", 638 "xyz.openbmc_project.State.Host", "CurrentHostState"); 639 } 640 641 /** 642 * @brief Translates boot source DBUS property value to redfish. 643 * 644 * @param[in] dbusSource The boot source in DBUS speak. 645 * 646 * @return Returns as a string, the boot source in Redfish terms. If translation 647 * cannot be done, returns an empty string. 648 */ 649 inline std::string dbusToRfBootSource(const std::string& dbusSource) 650 { 651 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 652 { 653 return "None"; 654 } 655 else if (dbusSource == 656 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 657 { 658 return "Hdd"; 659 } 660 else if (dbusSource == 661 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 662 { 663 return "Cd"; 664 } 665 else if (dbusSource == 666 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 667 { 668 return "Pxe"; 669 } 670 else if (dbusSource == 671 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 672 { 673 return "Usb"; 674 } 675 else 676 { 677 return ""; 678 } 679 } 680 681 /** 682 * @brief Translates boot mode DBUS property value to redfish. 683 * 684 * @param[in] dbusMode The boot mode in DBUS speak. 685 * 686 * @return Returns as a string, the boot mode in Redfish terms. If translation 687 * cannot be done, returns an empty string. 688 */ 689 inline std::string dbusToRfBootMode(const std::string& dbusMode) 690 { 691 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 692 { 693 return "None"; 694 } 695 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 696 { 697 return "Diags"; 698 } 699 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 700 { 701 return "BiosSetup"; 702 } 703 else 704 { 705 return ""; 706 } 707 } 708 709 /** 710 * @brief Translates boot source from Redfish to the DBus boot paths. 711 * 712 * @param[in] rfSource The boot source in Redfish. 713 * @param[out] bootSource The DBus source 714 * @param[out] bootMode the DBus boot mode 715 * 716 * @return Integer error code. 717 */ 718 inline int assignBootParameters(std::shared_ptr<AsyncResp> aResp, 719 const std::string& rfSource, 720 std::string& bootSource, std::string& bootMode) 721 { 722 // The caller has initialized the bootSource and bootMode to: 723 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 724 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 725 // Only modify the bootSource/bootMode variable needed to achieve the 726 // desired boot action. 727 728 if (rfSource == "None") 729 { 730 return 0; 731 } 732 else if (rfSource == "Pxe") 733 { 734 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 735 } 736 else if (rfSource == "Hdd") 737 { 738 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 739 } 740 else if (rfSource == "Diags") 741 { 742 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 743 } 744 else if (rfSource == "Cd") 745 { 746 bootSource = 747 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 748 } 749 else if (rfSource == "BiosSetup") 750 { 751 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 752 } 753 else if (rfSource == "Usb") 754 { 755 bootSource = 756 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 757 } 758 else 759 { 760 BMCWEB_LOG_DEBUG << "Invalid property value for " 761 "BootSourceOverrideTarget: " 762 << bootSource; 763 messages::propertyValueNotInList(aResp->res, rfSource, 764 "BootSourceTargetOverride"); 765 return -1; 766 } 767 return 0; 768 } 769 770 /** 771 * @brief Retrieves boot mode over DBUS and fills out the response 772 * 773 * @param[in] aResp Shared pointer for generating response message. 774 * @param[in] bootDbusObj The dbus object to query for boot properties. 775 * 776 * @return None. 777 */ 778 inline void getBootMode(std::shared_ptr<AsyncResp> aResp, 779 std::string bootDbusObj) 780 { 781 crow::connections::systemBus->async_method_call( 782 [aResp](const boost::system::error_code ec, 783 const std::variant<std::string>& bootMode) { 784 if (ec) 785 { 786 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 787 messages::internalError(aResp->res); 788 return; 789 } 790 791 const std::string* bootModeStr = 792 std::get_if<std::string>(&bootMode); 793 794 if (!bootModeStr) 795 { 796 messages::internalError(aResp->res); 797 return; 798 } 799 800 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 801 802 // TODO (Santosh): Do we need to support override mode? 803 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 804 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 805 "AllowableValues"] = { 806 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 807 808 if (*bootModeStr != 809 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 810 { 811 auto rfMode = dbusToRfBootMode(*bootModeStr); 812 if (!rfMode.empty()) 813 { 814 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 815 rfMode; 816 } 817 } 818 819 // If the BootSourceOverrideTarget is still "None" at the end, 820 // reset the BootSourceOverrideEnabled to indicate that 821 // overrides are disabled 822 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 823 "None") 824 { 825 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 826 "Disabled"; 827 } 828 }, 829 "xyz.openbmc_project.Settings", bootDbusObj, 830 "org.freedesktop.DBus.Properties", "Get", 831 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 832 } 833 834 /** 835 * @brief Retrieves boot source over DBUS 836 * 837 * @param[in] aResp Shared pointer for generating response message. 838 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 839 * 840 * @return None. 841 */ 842 inline void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 843 { 844 std::string bootDbusObj = 845 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 846 : "/xyz/openbmc_project/control/host0/boot"; 847 848 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 849 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 850 (oneTimeEnabled) ? "Once" : "Continuous"; 851 852 crow::connections::systemBus->async_method_call( 853 [aResp, bootDbusObj](const boost::system::error_code ec, 854 const std::variant<std::string>& bootSource) { 855 if (ec) 856 { 857 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 858 messages::internalError(aResp->res); 859 return; 860 } 861 862 const std::string* bootSourceStr = 863 std::get_if<std::string>(&bootSource); 864 865 if (!bootSourceStr) 866 { 867 messages::internalError(aResp->res); 868 return; 869 } 870 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 871 872 auto rfSource = dbusToRfBootSource(*bootSourceStr); 873 if (!rfSource.empty()) 874 { 875 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 876 rfSource; 877 } 878 }, 879 "xyz.openbmc_project.Settings", bootDbusObj, 880 "org.freedesktop.DBus.Properties", "Get", 881 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 882 getBootMode(std::move(aResp), std::move(bootDbusObj)); 883 } 884 885 /** 886 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 887 * get boot source and boot mode. 888 * 889 * @param[in] aResp Shared pointer for generating response message. 890 * 891 * @return None. 892 */ 893 inline void getBootProperties(std::shared_ptr<AsyncResp> aResp) 894 { 895 BMCWEB_LOG_DEBUG << "Get boot information."; 896 897 crow::connections::systemBus->async_method_call( 898 [aResp](const boost::system::error_code ec, 899 const std::variant<bool>& oneTime) { 900 if (ec) 901 { 902 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 903 // not an error, don't have to have the interface 904 return; 905 } 906 907 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 908 909 if (!oneTimePtr) 910 { 911 messages::internalError(aResp->res); 912 return; 913 } 914 getBootSource(aResp, *oneTimePtr); 915 }, 916 "xyz.openbmc_project.Settings", 917 "/xyz/openbmc_project/control/host0/boot/one_time", 918 "org.freedesktop.DBus.Properties", "Get", 919 "xyz.openbmc_project.Object.Enable", "Enabled"); 920 } 921 922 /** 923 * @brief Retrieves the Last Reset Time 924 * 925 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 926 * and power off. Even though this is the "system" Redfish object look at the 927 * chassis D-Bus interface for the LastStateChangeTime since this has the 928 * last power operation time. 929 * 930 * @param[in] aResp Shared pointer for generating response message. 931 * 932 * @return None. 933 */ 934 inline void getLastResetTime(std::shared_ptr<AsyncResp> aResp) 935 { 936 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 937 938 crow::connections::systemBus->async_method_call( 939 [aResp](const boost::system::error_code ec, 940 std::variant<uint64_t>& lastResetTime) { 941 if (ec) 942 { 943 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 944 return; 945 } 946 947 const uint64_t* lastResetTimePtr = 948 std::get_if<uint64_t>(&lastResetTime); 949 950 if (!lastResetTimePtr) 951 { 952 messages::internalError(aResp->res); 953 return; 954 } 955 // LastStateChangeTime is epoch time, in milliseconds 956 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 957 time_t lastResetTimeStamp = 958 static_cast<time_t>(*lastResetTimePtr / 1000); 959 960 // Convert to ISO 8601 standard 961 aResp->res.jsonValue["LastResetTime"] = 962 crow::utility::getDateTime(lastResetTimeStamp); 963 }, 964 "xyz.openbmc_project.State.Chassis", 965 "/xyz/openbmc_project/state/chassis0", 966 "org.freedesktop.DBus.Properties", "Get", 967 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 968 } 969 970 /** 971 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 972 * 973 * @param[in] aResp Shared pointer for generating response message. 974 * 975 * @return None. 976 */ 977 inline void getAutomaticRetry(std::shared_ptr<AsyncResp> aResp) 978 { 979 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 980 981 crow::connections::systemBus->async_method_call( 982 [aResp](const boost::system::error_code ec, 983 std::variant<bool>& autoRebootEnabled) { 984 if (ec) 985 { 986 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 987 return; 988 } 989 990 const bool* autoRebootEnabledPtr = 991 std::get_if<bool>(&autoRebootEnabled); 992 993 if (!autoRebootEnabledPtr) 994 { 995 messages::internalError(aResp->res); 996 return; 997 } 998 999 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1000 if (*autoRebootEnabledPtr == true) 1001 { 1002 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1003 "RetryAttempts"; 1004 // If AutomaticRetry (AutoReboot) is enabled see how many 1005 // attempts are left 1006 crow::connections::systemBus->async_method_call( 1007 [aResp](const boost::system::error_code ec, 1008 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1009 if (ec) 1010 { 1011 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1012 return; 1013 } 1014 1015 const uint32_t* autoRebootAttemptsLeftPtr = 1016 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1017 1018 if (!autoRebootAttemptsLeftPtr) 1019 { 1020 messages::internalError(aResp->res); 1021 return; 1022 } 1023 1024 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1025 << *autoRebootAttemptsLeftPtr; 1026 1027 aResp->res 1028 .jsonValue["Boot"] 1029 ["RemainingAutomaticRetryAttempts"] = 1030 *autoRebootAttemptsLeftPtr; 1031 }, 1032 "xyz.openbmc_project.State.Host", 1033 "/xyz/openbmc_project/state/host0", 1034 "org.freedesktop.DBus.Properties", "Get", 1035 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1036 "AttemptsLeft"); 1037 } 1038 else 1039 { 1040 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1041 "Disabled"; 1042 } 1043 1044 // Not on D-Bus. Hardcoded here: 1045 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1046 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1047 1048 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1049 // and RetryAttempts. OpenBMC only supports Disabled and 1050 // RetryAttempts. 1051 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1052 "AllowableValues"] = {"Disabled", 1053 "RetryAttempts"}; 1054 }, 1055 "xyz.openbmc_project.Settings", 1056 "/xyz/openbmc_project/control/host0/auto_reboot", 1057 "org.freedesktop.DBus.Properties", "Get", 1058 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1059 } 1060 1061 /** 1062 * @brief Retrieves power restore policy over DBUS. 1063 * 1064 * @param[in] aResp Shared pointer for generating response message. 1065 * 1066 * @return None. 1067 */ 1068 inline void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp) 1069 { 1070 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1071 1072 crow::connections::systemBus->async_method_call( 1073 [aResp](const boost::system::error_code ec, 1074 std::variant<std::string>& policy) { 1075 if (ec) 1076 { 1077 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1078 return; 1079 } 1080 1081 const boost::container::flat_map<std::string, std::string> 1082 policyMaps = { 1083 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1084 "AlwaysOn", 1085 "AlwaysOn"}, 1086 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1087 "AlwaysOff", 1088 "AlwaysOff"}, 1089 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1090 "LastState", 1091 "LastState"}}; 1092 1093 const std::string* policyPtr = std::get_if<std::string>(&policy); 1094 1095 if (!policyPtr) 1096 { 1097 messages::internalError(aResp->res); 1098 return; 1099 } 1100 1101 auto policyMapsIt = policyMaps.find(*policyPtr); 1102 if (policyMapsIt == policyMaps.end()) 1103 { 1104 messages::internalError(aResp->res); 1105 return; 1106 } 1107 1108 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1109 }, 1110 "xyz.openbmc_project.Settings", 1111 "/xyz/openbmc_project/control/host0/power_restore_policy", 1112 "org.freedesktop.DBus.Properties", "Get", 1113 "xyz.openbmc_project.Control.Power.RestorePolicy", 1114 "PowerRestorePolicy"); 1115 } 1116 1117 /** 1118 * @brief Sets boot properties into DBUS object(s). 1119 * 1120 * @param[in] aResp Shared pointer for generating response message. 1121 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 1122 * @param[in] bootSource The boot source to set. 1123 * @param[in] bootEnable The source override "enable" to set. 1124 * 1125 * @return Integer error code. 1126 */ 1127 inline void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 1128 bool oneTimeEnabled, 1129 std::optional<std::string> bootSource, 1130 std::optional<std::string> bootEnable) 1131 { 1132 std::string bootSourceStr = 1133 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1134 std::string bootModeStr = 1135 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1136 bool oneTimeSetting = oneTimeEnabled; 1137 bool useBootSource = true; 1138 1139 // Validate incoming parameters 1140 if (bootEnable) 1141 { 1142 if (*bootEnable == "Once") 1143 { 1144 oneTimeSetting = true; 1145 } 1146 else if (*bootEnable == "Continuous") 1147 { 1148 oneTimeSetting = false; 1149 } 1150 else if (*bootEnable == "Disabled") 1151 { 1152 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1153 oneTimeSetting = false; 1154 useBootSource = false; 1155 } 1156 else 1157 { 1158 BMCWEB_LOG_DEBUG << "Unsupported value for " 1159 "BootSourceOverrideEnabled: " 1160 << *bootEnable; 1161 messages::propertyValueNotInList(aResp->res, *bootEnable, 1162 "BootSourceOverrideEnabled"); 1163 return; 1164 } 1165 } 1166 1167 if (bootSource && useBootSource) 1168 { 1169 // Source target specified 1170 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1171 // Figure out which DBUS interface and property to use 1172 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1173 bootModeStr)) 1174 { 1175 BMCWEB_LOG_DEBUG 1176 << "Invalid property value for BootSourceOverrideTarget: " 1177 << *bootSource; 1178 messages::propertyValueNotInList(aResp->res, *bootSource, 1179 "BootSourceTargetOverride"); 1180 return; 1181 } 1182 } 1183 1184 // Act on validated parameters 1185 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1186 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1187 const char* bootObj = 1188 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1189 : "/xyz/openbmc_project/control/host0/boot"; 1190 1191 crow::connections::systemBus->async_method_call( 1192 [aResp](const boost::system::error_code ec) { 1193 if (ec) 1194 { 1195 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1196 messages::internalError(aResp->res); 1197 return; 1198 } 1199 BMCWEB_LOG_DEBUG << "Boot source update done."; 1200 }, 1201 "xyz.openbmc_project.Settings", bootObj, 1202 "org.freedesktop.DBus.Properties", "Set", 1203 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1204 std::variant<std::string>(bootSourceStr)); 1205 1206 crow::connections::systemBus->async_method_call( 1207 [aResp](const boost::system::error_code ec) { 1208 if (ec) 1209 { 1210 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1211 messages::internalError(aResp->res); 1212 return; 1213 } 1214 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1215 }, 1216 "xyz.openbmc_project.Settings", bootObj, 1217 "org.freedesktop.DBus.Properties", "Set", 1218 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1219 std::variant<std::string>(bootModeStr)); 1220 1221 crow::connections::systemBus->async_method_call( 1222 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1223 if (ec) 1224 { 1225 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1226 messages::internalError(aResp->res); 1227 return; 1228 } 1229 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1230 }, 1231 "xyz.openbmc_project.Settings", 1232 "/xyz/openbmc_project/control/host0/boot/one_time", 1233 "org.freedesktop.DBus.Properties", "Set", 1234 "xyz.openbmc_project.Object.Enable", "Enabled", 1235 std::variant<bool>(oneTimeSetting)); 1236 } 1237 1238 /** 1239 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1240 * set boot source/boot mode properties. 1241 * 1242 * @param[in] aResp Shared pointer for generating response message. 1243 * @param[in] bootSource The boot source from incoming RF request. 1244 * @param[in] bootEnable The boot override enable from incoming RF request. 1245 * 1246 * @return Integer error code. 1247 */ 1248 inline void setBootSourceProperties(std::shared_ptr<AsyncResp> aResp, 1249 std::optional<std::string> bootSource, 1250 std::optional<std::string> bootEnable) 1251 { 1252 BMCWEB_LOG_DEBUG << "Set boot information."; 1253 1254 crow::connections::systemBus->async_method_call( 1255 [aResp, bootSource{std::move(bootSource)}, 1256 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1257 const std::variant<bool>& oneTime) { 1258 if (ec) 1259 { 1260 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1261 messages::internalError(aResp->res); 1262 return; 1263 } 1264 1265 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1266 1267 if (!oneTimePtr) 1268 { 1269 messages::internalError(aResp->res); 1270 return; 1271 } 1272 1273 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1274 1275 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 1276 std::move(bootEnable)); 1277 }, 1278 "xyz.openbmc_project.Settings", 1279 "/xyz/openbmc_project/control/host0/boot/one_time", 1280 "org.freedesktop.DBus.Properties", "Get", 1281 "xyz.openbmc_project.Object.Enable", "Enabled"); 1282 } 1283 1284 /** 1285 * @brief Sets automaticRetry (Auto Reboot) 1286 * 1287 * @param[in] aResp Shared pointer for generating response message. 1288 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1289 * 1290 * @return None. 1291 */ 1292 inline void setAutomaticRetry(std::shared_ptr<AsyncResp> aResp, 1293 const std::string&& automaticRetryConfig) 1294 { 1295 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1296 1297 // OpenBMC only supports "Disabled" and "RetryAttempts". 1298 bool autoRebootEnabled; 1299 1300 if (automaticRetryConfig == "Disabled") 1301 { 1302 autoRebootEnabled = false; 1303 } 1304 else if (automaticRetryConfig == "RetryAttempts") 1305 { 1306 autoRebootEnabled = true; 1307 } 1308 else 1309 { 1310 BMCWEB_LOG_DEBUG << "Invalid property value for " 1311 "AutomaticRetryConfig: " 1312 << automaticRetryConfig; 1313 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1314 "AutomaticRetryConfig"); 1315 return; 1316 } 1317 1318 crow::connections::systemBus->async_method_call( 1319 [aResp](const boost::system::error_code ec) { 1320 if (ec) 1321 { 1322 messages::internalError(aResp->res); 1323 return; 1324 } 1325 }, 1326 "xyz.openbmc_project.Settings", 1327 "/xyz/openbmc_project/control/host0/auto_reboot", 1328 "org.freedesktop.DBus.Properties", "Set", 1329 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1330 std::variant<bool>(autoRebootEnabled)); 1331 } 1332 1333 /** 1334 * @brief Sets power restore policy properties. 1335 * 1336 * @param[in] aResp Shared pointer for generating response message. 1337 * @param[in] policy power restore policy properties from request. 1338 * 1339 * @return None. 1340 */ 1341 inline void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp, 1342 std::optional<std::string> policy) 1343 { 1344 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1345 1346 const boost::container::flat_map<std::string, std::string> policyMaps = { 1347 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1348 "AlwaysOn"}, 1349 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1350 "AlwaysOff"}, 1351 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1352 "LastState"}}; 1353 1354 std::string powerRestorPolicy; 1355 1356 auto policyMapsIt = policyMaps.find(*policy); 1357 if (policyMapsIt == policyMaps.end()) 1358 { 1359 messages::internalError(aResp->res); 1360 return; 1361 } 1362 1363 powerRestorPolicy = policyMapsIt->second; 1364 1365 crow::connections::systemBus->async_method_call( 1366 [aResp](const boost::system::error_code ec) { 1367 if (ec) 1368 { 1369 messages::internalError(aResp->res); 1370 return; 1371 } 1372 }, 1373 "xyz.openbmc_project.Settings", 1374 "/xyz/openbmc_project/control/host0/power_restore_policy", 1375 "org.freedesktop.DBus.Properties", "Set", 1376 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1377 std::variant<std::string>(powerRestorPolicy)); 1378 } 1379 1380 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1381 /** 1382 * @brief Retrieves provisioning status 1383 * 1384 * @param[in] aResp Shared pointer for completing asynchronous calls. 1385 * 1386 * @return None. 1387 */ 1388 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1389 { 1390 BMCWEB_LOG_DEBUG << "Get OEM information."; 1391 crow::connections::systemBus->async_method_call( 1392 [aResp](const boost::system::error_code ec, 1393 const std::vector<std::pair<std::string, VariantType>>& 1394 propertiesList) { 1395 nlohmann::json& oemPFR = 1396 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1397 if (ec) 1398 { 1399 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1400 // not an error, don't have to have the interface 1401 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1402 return; 1403 } 1404 1405 const bool* provState = nullptr; 1406 const bool* lockState = nullptr; 1407 for (const std::pair<std::string, VariantType>& property : 1408 propertiesList) 1409 { 1410 if (property.first == "UfmProvisioned") 1411 { 1412 provState = std::get_if<bool>(&property.second); 1413 } 1414 else if (property.first == "UfmLocked") 1415 { 1416 lockState = std::get_if<bool>(&property.second); 1417 } 1418 } 1419 1420 if ((provState == nullptr) || (lockState == nullptr)) 1421 { 1422 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1423 messages::internalError(aResp->res); 1424 return; 1425 } 1426 1427 if (*provState == true) 1428 { 1429 if (*lockState == true) 1430 { 1431 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1432 } 1433 else 1434 { 1435 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1436 } 1437 } 1438 else 1439 { 1440 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1441 } 1442 }, 1443 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1444 "org.freedesktop.DBus.Properties", "GetAll", 1445 "xyz.openbmc_project.PFR.Attributes"); 1446 } 1447 #endif 1448 1449 /** 1450 * @brief Translates watchdog timeout action DBUS property value to redfish. 1451 * 1452 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1453 * 1454 * @return Returns as a string, the timeout action in Redfish terms. If 1455 * translation cannot be done, returns an empty string. 1456 */ 1457 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 1458 { 1459 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1460 { 1461 return "None"; 1462 } 1463 else if (dbusAction == 1464 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1465 { 1466 return "ResetSystem"; 1467 } 1468 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1469 { 1470 return "PowerDown"; 1471 } 1472 else if (dbusAction == 1473 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1474 { 1475 return "PowerCycle"; 1476 } 1477 1478 return ""; 1479 } 1480 1481 /** 1482 *@brief Translates timeout action from Redfish to DBUS property value. 1483 * 1484 *@param[in] rfAction The timeout action in Redfish. 1485 * 1486 *@return Returns as a string, the time_out action as expected by DBUS. 1487 *If translation cannot be done, returns an empty string. 1488 */ 1489 1490 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 1491 { 1492 if (rfAction == "None") 1493 { 1494 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1495 } 1496 else if (rfAction == "PowerCycle") 1497 { 1498 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1499 } 1500 else if (rfAction == "PowerDown") 1501 { 1502 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1503 } 1504 else if (rfAction == "ResetSystem") 1505 { 1506 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1507 } 1508 1509 return ""; 1510 } 1511 1512 /** 1513 * @brief Retrieves host watchdog timer properties over DBUS 1514 * 1515 * @param[in] aResp Shared pointer for completing asynchronous calls. 1516 * 1517 * @return None. 1518 */ 1519 inline void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1520 { 1521 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1522 crow::connections::systemBus->async_method_call( 1523 [aResp](const boost::system::error_code ec, 1524 PropertiesType& properties) { 1525 if (ec) 1526 { 1527 // watchdog service is stopped 1528 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1529 return; 1530 } 1531 1532 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1533 1534 nlohmann::json& hostWatchdogTimer = 1535 aResp->res.jsonValue["HostWatchdogTimer"]; 1536 1537 // watchdog service is running/enabled 1538 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1539 1540 for (const auto& property : properties) 1541 { 1542 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1543 if (property.first == "Enabled") 1544 { 1545 const bool* state = std::get_if<bool>(&property.second); 1546 1547 if (!state) 1548 { 1549 messages::internalError(aResp->res); 1550 continue; 1551 } 1552 1553 hostWatchdogTimer["FunctionEnabled"] = *state; 1554 } 1555 else if (property.first == "ExpireAction") 1556 { 1557 const std::string* s = 1558 std::get_if<std::string>(&property.second); 1559 if (!s) 1560 { 1561 messages::internalError(aResp->res); 1562 continue; 1563 } 1564 1565 std::string action = dbusToRfWatchdogAction(*s); 1566 if (action.empty()) 1567 { 1568 messages::internalError(aResp->res); 1569 continue; 1570 } 1571 hostWatchdogTimer["TimeoutAction"] = action; 1572 } 1573 } 1574 }, 1575 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1576 "org.freedesktop.DBus.Properties", "GetAll", 1577 "xyz.openbmc_project.State.Watchdog"); 1578 } 1579 1580 /** 1581 * @brief Sets Host WatchDog Timer properties. 1582 * 1583 * @param[in] aResp Shared pointer for generating response message. 1584 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1585 * RF request. 1586 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1587 * 1588 * @return None. 1589 */ 1590 inline void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1591 const std::optional<bool> wdtEnable, 1592 const std::optional<std::string>& wdtTimeOutAction) 1593 { 1594 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1595 1596 if (wdtTimeOutAction) 1597 { 1598 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1599 // check if TimeOut Action is Valid 1600 if (wdtTimeOutActStr.empty()) 1601 { 1602 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1603 << *wdtTimeOutAction; 1604 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1605 "TimeoutAction"); 1606 return; 1607 } 1608 1609 crow::connections::systemBus->async_method_call( 1610 [aResp](const boost::system::error_code ec) { 1611 if (ec) 1612 { 1613 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1614 messages::internalError(aResp->res); 1615 return; 1616 } 1617 }, 1618 "xyz.openbmc_project.Watchdog", 1619 "/xyz/openbmc_project/watchdog/host0", 1620 "org.freedesktop.DBus.Properties", "Set", 1621 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1622 std::variant<std::string>(wdtTimeOutActStr)); 1623 } 1624 1625 if (wdtEnable) 1626 { 1627 crow::connections::systemBus->async_method_call( 1628 [aResp](const boost::system::error_code ec) { 1629 if (ec) 1630 { 1631 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1632 messages::internalError(aResp->res); 1633 return; 1634 } 1635 }, 1636 "xyz.openbmc_project.Watchdog", 1637 "/xyz/openbmc_project/watchdog/host0", 1638 "org.freedesktop.DBus.Properties", "Set", 1639 "xyz.openbmc_project.State.Watchdog", "Enabled", 1640 std::variant<bool>(*wdtEnable)); 1641 } 1642 } 1643 1644 /** 1645 * SystemsCollection derived class for delivering ComputerSystems Collection 1646 * Schema 1647 */ 1648 class SystemsCollection : public Node 1649 { 1650 public: 1651 SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/") 1652 { 1653 entityPrivileges = { 1654 {boost::beast::http::verb::get, {{"Login"}}}, 1655 {boost::beast::http::verb::head, {{"Login"}}}, 1656 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1657 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1658 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1659 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1660 } 1661 1662 private: 1663 void doGet(crow::Response& res, const crow::Request& req, 1664 const std::vector<std::string>& params) override 1665 { 1666 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1667 res.jsonValue["@odata.type"] = 1668 "#ComputerSystemCollection.ComputerSystemCollection"; 1669 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1670 res.jsonValue["Name"] = "Computer System Collection"; 1671 1672 crow::connections::systemBus->async_method_call( 1673 [asyncResp](const boost::system::error_code ec, 1674 const std::variant<std::string>& hostName) { 1675 nlohmann::json& iface_array = 1676 asyncResp->res.jsonValue["Members"]; 1677 iface_array = nlohmann::json::array(); 1678 auto& count = asyncResp->res.jsonValue["Members@odata.count"]; 1679 count = 0; 1680 if (ec) 1681 { 1682 iface_array.push_back( 1683 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1684 count = iface_array.size(); 1685 return; 1686 } 1687 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1688 iface_array.push_back( 1689 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1690 iface_array.push_back( 1691 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1692 count = iface_array.size(); 1693 }, 1694 "xyz.openbmc_project.Settings", 1695 "/xyz/openbmc_project/network/hypervisor", 1696 "org.freedesktop.DBus.Properties", "Get", 1697 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1698 } 1699 }; 1700 1701 /** 1702 * SystemActionsReset class supports handle POST method for Reset action. 1703 * The class retrieves and sends data directly to D-Bus. 1704 */ 1705 class SystemActionsReset : public Node 1706 { 1707 public: 1708 SystemActionsReset(App& app) : 1709 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1710 { 1711 entityPrivileges = { 1712 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1713 } 1714 1715 private: 1716 /** 1717 * Function handles POST method request. 1718 * Analyzes POST body message before sends Reset request data to D-Bus. 1719 */ 1720 void doPost(crow::Response& res, const crow::Request& req, 1721 const std::vector<std::string>& params) override 1722 { 1723 auto asyncResp = std::make_shared<AsyncResp>(res); 1724 1725 std::string resetType; 1726 if (!json_util::readJson(req, res, "ResetType", resetType)) 1727 { 1728 return; 1729 } 1730 1731 // Get the command and host vs. chassis 1732 std::string command; 1733 bool hostCommand; 1734 if (resetType == "On") 1735 { 1736 command = "xyz.openbmc_project.State.Host.Transition.On"; 1737 hostCommand = true; 1738 } 1739 else if (resetType == "ForceOff") 1740 { 1741 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1742 hostCommand = false; 1743 } 1744 else if (resetType == "ForceOn") 1745 { 1746 command = "xyz.openbmc_project.State.Host.Transition.On"; 1747 hostCommand = true; 1748 } 1749 else if (resetType == "ForceRestart") 1750 { 1751 command = 1752 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1753 hostCommand = true; 1754 } 1755 else if (resetType == "GracefulShutdown") 1756 { 1757 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1758 hostCommand = true; 1759 } 1760 else if (resetType == "GracefulRestart") 1761 { 1762 command = 1763 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1764 hostCommand = true; 1765 } 1766 else if (resetType == "PowerCycle") 1767 { 1768 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1769 hostCommand = true; 1770 } 1771 else if (resetType == "Nmi") 1772 { 1773 doNMI(asyncResp); 1774 return; 1775 } 1776 else 1777 { 1778 messages::actionParameterUnknown(res, "Reset", resetType); 1779 return; 1780 } 1781 1782 if (hostCommand) 1783 { 1784 crow::connections::systemBus->async_method_call( 1785 [asyncResp, resetType](const boost::system::error_code ec) { 1786 if (ec) 1787 { 1788 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1789 if (ec.value() == boost::asio::error::invalid_argument) 1790 { 1791 messages::actionParameterNotSupported( 1792 asyncResp->res, resetType, "Reset"); 1793 } 1794 else 1795 { 1796 messages::internalError(asyncResp->res); 1797 } 1798 return; 1799 } 1800 messages::success(asyncResp->res); 1801 }, 1802 "xyz.openbmc_project.State.Host", 1803 "/xyz/openbmc_project/state/host0", 1804 "org.freedesktop.DBus.Properties", "Set", 1805 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1806 std::variant<std::string>{command}); 1807 } 1808 else 1809 { 1810 crow::connections::systemBus->async_method_call( 1811 [asyncResp, resetType](const boost::system::error_code ec) { 1812 if (ec) 1813 { 1814 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1815 if (ec.value() == boost::asio::error::invalid_argument) 1816 { 1817 messages::actionParameterNotSupported( 1818 asyncResp->res, resetType, "Reset"); 1819 } 1820 else 1821 { 1822 messages::internalError(asyncResp->res); 1823 } 1824 return; 1825 } 1826 messages::success(asyncResp->res); 1827 }, 1828 "xyz.openbmc_project.State.Chassis", 1829 "/xyz/openbmc_project/state/chassis0", 1830 "org.freedesktop.DBus.Properties", "Set", 1831 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1832 std::variant<std::string>{command}); 1833 } 1834 } 1835 /** 1836 * Function transceives data with dbus directly. 1837 */ 1838 void doNMI(const std::shared_ptr<AsyncResp>& asyncResp) 1839 { 1840 constexpr char const* serviceName = 1841 "xyz.openbmc_project.Control.Host.NMI"; 1842 constexpr char const* objectPath = 1843 "/xyz/openbmc_project/control/host0/nmi"; 1844 constexpr char const* interfaceName = 1845 "xyz.openbmc_project.Control.Host.NMI"; 1846 constexpr char const* method = "NMI"; 1847 1848 crow::connections::systemBus->async_method_call( 1849 [asyncResp](const boost::system::error_code ec) { 1850 if (ec) 1851 { 1852 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 1853 messages::internalError(asyncResp->res); 1854 return; 1855 } 1856 messages::success(asyncResp->res); 1857 }, 1858 serviceName, objectPath, interfaceName, method); 1859 } 1860 }; 1861 1862 /** 1863 * Systems derived class for delivering Computer Systems Schema. 1864 */ 1865 class Systems : public Node 1866 { 1867 public: 1868 /* 1869 * Default Constructor 1870 */ 1871 Systems(App& app) : Node(app, "/redfish/v1/Systems/system/") 1872 { 1873 entityPrivileges = { 1874 {boost::beast::http::verb::get, {{"Login"}}}, 1875 {boost::beast::http::verb::head, {{"Login"}}}, 1876 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1877 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1878 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1879 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1880 } 1881 1882 private: 1883 /** 1884 * Functions triggers appropriate requests on DBus 1885 */ 1886 void doGet(crow::Response& res, const crow::Request& req, 1887 const std::vector<std::string>& params) override 1888 { 1889 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_12_0.ComputerSystem"; 1890 res.jsonValue["Name"] = "system"; 1891 res.jsonValue["Id"] = "system"; 1892 res.jsonValue["SystemType"] = "Physical"; 1893 res.jsonValue["Description"] = "Computer System"; 1894 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1895 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1896 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 1897 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1898 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1899 1900 res.jsonValue["Processors"] = { 1901 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1902 res.jsonValue["Memory"] = { 1903 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1904 res.jsonValue["Storage"] = { 1905 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 1906 1907 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1908 {"target", 1909 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1910 {"@Redfish.ActionInfo", 1911 "/redfish/v1/Systems/system/ResetActionInfo"}}; 1912 1913 res.jsonValue["LogServices"] = { 1914 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1915 1916 res.jsonValue["Bios"] = { 1917 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1918 1919 res.jsonValue["Links"]["ManagedBy"] = { 1920 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1921 1922 res.jsonValue["Status"] = { 1923 {"Health", "OK"}, 1924 {"State", "Enabled"}, 1925 }; 1926 auto asyncResp = std::make_shared<AsyncResp>(res); 1927 1928 constexpr const std::array<const char*, 4> inventoryForSystems = { 1929 "xyz.openbmc_project.Inventory.Item.Dimm", 1930 "xyz.openbmc_project.Inventory.Item.Cpu", 1931 "xyz.openbmc_project.Inventory.Item.Drive", 1932 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1933 1934 auto health = std::make_shared<HealthPopulate>(asyncResp); 1935 crow::connections::systemBus->async_method_call( 1936 [health](const boost::system::error_code ec, 1937 std::vector<std::string>& resp) { 1938 if (ec) 1939 { 1940 // no inventory 1941 return; 1942 } 1943 1944 health->inventory = std::move(resp); 1945 }, 1946 "xyz.openbmc_project.ObjectMapper", 1947 "/xyz/openbmc_project/object_mapper", 1948 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1949 int32_t(0), inventoryForSystems); 1950 1951 health->populate(); 1952 1953 getMainChassisId(asyncResp, [](const std::string& chassisId, 1954 std::shared_ptr<AsyncResp> aRsp) { 1955 aRsp->res.jsonValue["Links"]["Chassis"] = { 1956 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1957 }); 1958 1959 getIndicatorLedState(asyncResp); 1960 getComputerSystem(asyncResp, health); 1961 getHostState(asyncResp); 1962 getBootProperties(asyncResp); 1963 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1964 getHostWatchdogTimer(asyncResp); 1965 getPowerRestorePolicy(asyncResp); 1966 getAutomaticRetry(asyncResp); 1967 getLastResetTime(asyncResp); 1968 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1969 getProvisioningStatus(asyncResp); 1970 #endif 1971 } 1972 1973 void doPatch(crow::Response& res, const crow::Request& req, 1974 const std::vector<std::string>& params) override 1975 { 1976 std::optional<std::string> indicatorLed; 1977 std::optional<nlohmann::json> bootProps; 1978 std::optional<nlohmann::json> wdtTimerProps; 1979 std::optional<std::string> powerRestorePolicy; 1980 auto asyncResp = std::make_shared<AsyncResp>(res); 1981 1982 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1983 bootProps, "WatchdogTimer", wdtTimerProps, 1984 "PowerRestorePolicy", powerRestorePolicy)) 1985 { 1986 return; 1987 } 1988 1989 res.result(boost::beast::http::status::no_content); 1990 1991 if (wdtTimerProps) 1992 { 1993 std::optional<bool> wdtEnable; 1994 std::optional<std::string> wdtTimeOutAction; 1995 1996 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1997 "FunctionEnabled", wdtEnable, 1998 "TimeoutAction", wdtTimeOutAction)) 1999 { 2000 return; 2001 } 2002 setWDTProperties(asyncResp, std::move(wdtEnable), 2003 std::move(wdtTimeOutAction)); 2004 } 2005 2006 if (bootProps) 2007 { 2008 std::optional<std::string> bootSource; 2009 std::optional<std::string> bootEnable; 2010 std::optional<std::string> automaticRetryConfig; 2011 2012 if (!json_util::readJson( 2013 *bootProps, asyncResp->res, "BootSourceOverrideTarget", 2014 bootSource, "BootSourceOverrideEnabled", bootEnable, 2015 "AutomaticRetryConfig", automaticRetryConfig)) 2016 { 2017 return; 2018 } 2019 if (bootSource || bootEnable) 2020 { 2021 setBootSourceProperties(asyncResp, std::move(bootSource), 2022 std::move(bootEnable)); 2023 } 2024 if (automaticRetryConfig) 2025 { 2026 setAutomaticRetry(asyncResp, std::move(*automaticRetryConfig)); 2027 } 2028 } 2029 2030 if (indicatorLed) 2031 { 2032 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 2033 } 2034 2035 if (powerRestorePolicy) 2036 { 2037 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 2038 } 2039 } 2040 }; 2041 2042 /** 2043 * SystemResetActionInfo derived class for delivering Computer Systems 2044 * ResetType AllowableValues using ResetInfo schema. 2045 */ 2046 class SystemResetActionInfo : public Node 2047 { 2048 public: 2049 /* 2050 * Default Constructor 2051 */ 2052 SystemResetActionInfo(App& app) : 2053 Node(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2054 { 2055 entityPrivileges = { 2056 {boost::beast::http::verb::get, {{"Login"}}}, 2057 {boost::beast::http::verb::head, {{"Login"}}}, 2058 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2059 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2060 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2061 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2062 } 2063 2064 private: 2065 /** 2066 * Functions triggers appropriate requests on DBus 2067 */ 2068 void doGet(crow::Response& res, const crow::Request& req, 2069 const std::vector<std::string>& params) override 2070 { 2071 res.jsonValue = { 2072 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2073 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2074 {"Name", "Reset Action Info"}, 2075 {"Id", "ResetActionInfo"}, 2076 {"Parameters", 2077 {{{"Name", "ResetType"}, 2078 {"Required", true}, 2079 {"DataType", "String"}, 2080 {"AllowableValues", 2081 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 2082 "GracefulShutdown", "PowerCycle", "Nmi"}}}}}}; 2083 res.end(); 2084 } 2085 }; 2086 } // namespace redfish 2087