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 <app.hpp> 24 #include <boost/container/flat_map.hpp> 25 #include <registries/privilege_registry.hpp> 26 #include <utils/fw_utils.hpp> 27 #include <utils/json_utils.hpp> 28 29 #include <variant> 30 31 namespace redfish 32 { 33 34 /** 35 * @brief Updates the Functional State of DIMMs 36 * 37 * @param[in] aResp Shared pointer for completing asynchronous calls 38 * @param[in] dimmState Dimm's Functional state, true/false 39 * 40 * @return None. 41 */ 42 inline void 43 updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 44 const std::variant<bool>& dimmState) 45 { 46 const bool* isDimmFunctional = std::get_if<bool>(&dimmState); 47 if (isDimmFunctional == nullptr) 48 { 49 messages::internalError(aResp->res); 50 return; 51 } 52 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 53 54 // Set it as Enabled if at least one DIMM is functional 55 // Update STATE only if previous State was DISABLED and current Dimm is 56 // ENABLED. 57 nlohmann::json& prevMemSummary = 58 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 59 if (prevMemSummary == "Disabled") 60 { 61 if (*isDimmFunctional == true) 62 { 63 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 64 "Enabled"; 65 } 66 } 67 } 68 69 /* 70 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 71 * 72 * @param[in] aResp Shared pointer for completing asynchronous calls 73 * @param[in] cpuPresenceState CPU present or not 74 * 75 * @return None. 76 */ 77 inline void 78 modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 79 const std::variant<bool>& cpuPresenceState) 80 { 81 const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState); 82 83 if (isCpuPresent == nullptr) 84 { 85 messages::internalError(aResp->res); 86 return; 87 } 88 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 89 90 if (*isCpuPresent == true) 91 { 92 nlohmann::json& procCount = 93 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 94 auto procCountPtr = 95 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 96 if (procCountPtr != nullptr) 97 { 98 // shouldn't be possible to be nullptr 99 *procCountPtr += 1; 100 } 101 } 102 } 103 104 /* 105 * @brief Update "ProcessorSummary" "Status" "State" based on 106 * CPU Functional State 107 * 108 * @param[in] aResp Shared pointer for completing asynchronous calls 109 * @param[in] cpuFunctionalState is CPU functional true/false 110 * 111 * @return None. 112 */ 113 inline void 114 modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 115 const std::variant<bool>& cpuFunctionalState) 116 { 117 const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 118 119 if (isCpuFunctional == nullptr) 120 { 121 messages::internalError(aResp->res); 122 return; 123 } 124 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 125 126 nlohmann::json& prevProcState = 127 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 128 129 // Set it as Enabled if at least one CPU is functional 130 // Update STATE only if previous State was Non_Functional and current CPU is 131 // Functional. 132 if (prevProcState == "Disabled") 133 { 134 if (*isCpuFunctional == true) 135 { 136 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 137 "Enabled"; 138 } 139 } 140 } 141 142 /* 143 * @brief Retrieves computer system properties over dbus 144 * 145 * @param[in] aResp Shared pointer for completing asynchronous calls 146 * @param[in] systemHealth Shared HealthPopulate pointer 147 * 148 * @return None. 149 */ 150 inline void 151 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 152 const std::shared_ptr<HealthPopulate>& systemHealth) 153 { 154 BMCWEB_LOG_DEBUG << "Get available system components."; 155 156 crow::connections::systemBus->async_method_call( 157 [aResp, systemHealth]( 158 const boost::system::error_code ec, 159 const std::vector<std::pair< 160 std::string, 161 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 162 subtree) { 163 if (ec) 164 { 165 BMCWEB_LOG_DEBUG << "DBUS response error"; 166 messages::internalError(aResp->res); 167 return; 168 } 169 // Iterate over all retrieved ObjectPaths. 170 for (const std::pair<std::string, 171 std::vector<std::pair< 172 std::string, std::vector<std::string>>>>& 173 object : subtree) 174 { 175 const std::string& path = object.first; 176 BMCWEB_LOG_DEBUG << "Got path: " << path; 177 const std::vector< 178 std::pair<std::string, std::vector<std::string>>>& 179 connectionNames = object.second; 180 if (connectionNames.size() < 1) 181 { 182 continue; 183 } 184 185 auto memoryHealth = std::make_shared<HealthPopulate>( 186 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 187 188 auto cpuHealth = std::make_shared<HealthPopulate>( 189 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 190 191 systemHealth->children.emplace_back(memoryHealth); 192 systemHealth->children.emplace_back(cpuHealth); 193 194 // This is not system, so check if it's cpu, dimm, UUID or 195 // BiosVer 196 for (const auto& connection : connectionNames) 197 { 198 for (const auto& interfaceName : connection.second) 199 { 200 if (interfaceName == 201 "xyz.openbmc_project.Inventory.Item.Dimm") 202 { 203 BMCWEB_LOG_DEBUG 204 << "Found Dimm, now get its properties."; 205 206 crow::connections::systemBus->async_method_call( 207 [aResp, service{connection.first}, 208 path](const boost::system::error_code ec2, 209 const std::vector< 210 std::pair<std::string, VariantType>>& 211 properties) { 212 if (ec2) 213 { 214 BMCWEB_LOG_ERROR 215 << "DBUS response error " << ec2; 216 messages::internalError(aResp->res); 217 return; 218 } 219 BMCWEB_LOG_DEBUG << "Got " 220 << properties.size() 221 << " Dimm properties."; 222 223 if (properties.size() > 0) 224 { 225 for (const std::pair<std::string, 226 VariantType>& 227 property : properties) 228 { 229 if (property.first != 230 "MemorySizeInKB") 231 { 232 continue; 233 } 234 const uint32_t* value = 235 std::get_if<uint32_t>( 236 &property.second); 237 if (value == nullptr) 238 { 239 BMCWEB_LOG_DEBUG 240 << "Find incorrect type of " 241 "MemorySize"; 242 continue; 243 } 244 nlohmann::json& totalMemory = 245 aResp->res 246 .jsonValue["MemorySummar" 247 "y"] 248 ["TotalSystemMe" 249 "moryGiB"]; 250 uint64_t* preValue = 251 totalMemory 252 .get_ptr<uint64_t*>(); 253 if (preValue == nullptr) 254 { 255 continue; 256 } 257 aResp->res 258 .jsonValue["MemorySummary"] 259 ["TotalSystemMemoryGi" 260 "B"] = 261 *value / (1024 * 1024) + 262 *preValue; 263 aResp->res 264 .jsonValue["MemorySummary"] 265 ["Status"]["State"] = 266 "Enabled"; 267 } 268 } 269 else 270 { 271 auto getDimmProperties = 272 [aResp]( 273 const boost::system::error_code 274 ec3, 275 const std::variant<bool>& 276 dimmState) { 277 if (ec3) 278 { 279 BMCWEB_LOG_ERROR 280 << "DBUS response " 281 "error " 282 << ec3; 283 return; 284 } 285 updateDimmProperties(aResp, 286 dimmState); 287 }; 288 crow::connections::systemBus 289 ->async_method_call( 290 std::move(getDimmProperties), 291 service, path, 292 "org.freedesktop.DBus." 293 "Properties", 294 "Get", 295 "xyz.openbmc_project.State." 296 "Decorator.OperationalStatus", 297 "Functional"); 298 } 299 }, 300 connection.first, path, 301 "org.freedesktop.DBus.Properties", "GetAll", 302 "xyz.openbmc_project.Inventory.Item.Dimm"); 303 304 memoryHealth->inventory.emplace_back(path); 305 } 306 else if (interfaceName == 307 "xyz.openbmc_project.Inventory.Item.Cpu") 308 { 309 BMCWEB_LOG_DEBUG 310 << "Found Cpu, now get its properties."; 311 312 crow::connections::systemBus->async_method_call( 313 [aResp, service{connection.first}, 314 path](const boost::system::error_code ec2, 315 const std::vector< 316 std::pair<std::string, VariantType>>& 317 properties) { 318 if (ec2) 319 { 320 BMCWEB_LOG_ERROR 321 << "DBUS response error " << ec2; 322 messages::internalError(aResp->res); 323 return; 324 } 325 BMCWEB_LOG_DEBUG << "Got " 326 << properties.size() 327 << " Cpu properties."; 328 329 if (properties.size() > 0) 330 { 331 const uint64_t* processorId = nullptr; 332 const std::string* procFamily = nullptr; 333 nlohmann::json& procSummary = 334 aResp->res.jsonValue["ProcessorSumm" 335 "ary"]; 336 nlohmann::json& procCount = 337 procSummary["Count"]; 338 339 auto procCountPtr = procCount.get_ptr< 340 nlohmann::json:: 341 number_integer_t*>(); 342 if (procCountPtr == nullptr) 343 { 344 messages::internalError(aResp->res); 345 return; 346 } 347 for (const auto& property : properties) 348 { 349 350 if (property.first == "Id") 351 { 352 processorId = 353 std::get_if<uint64_t>( 354 &property.second); 355 if (nullptr != procFamily) 356 { 357 break; 358 } 359 continue; 360 } 361 362 if (property.first == "Family") 363 { 364 procFamily = 365 std::get_if<std::string>( 366 &property.second); 367 if (nullptr != processorId) 368 { 369 break; 370 } 371 continue; 372 } 373 } 374 375 if (procFamily != nullptr && 376 processorId != nullptr) 377 { 378 if (procCountPtr != nullptr && 379 *processorId != 0) 380 { 381 *procCountPtr += 1; 382 procSummary["Status"]["State"] = 383 "Enabled"; 384 385 procSummary["Model"] = 386 *procFamily; 387 } 388 } 389 } 390 else 391 { 392 auto getCpuPresenceState = 393 [aResp]( 394 const boost::system::error_code 395 ec3, 396 const std::variant<bool>& 397 cpuPresenceCheck) { 398 if (ec3) 399 { 400 BMCWEB_LOG_ERROR 401 << "DBUS response " 402 "error " 403 << ec3; 404 return; 405 } 406 modifyCpuPresenceState( 407 aResp, cpuPresenceCheck); 408 }; 409 410 auto getCpuFunctionalState = 411 [aResp]( 412 const boost::system::error_code 413 ec3, 414 const std::variant<bool>& 415 cpuFunctionalCheck) { 416 if (ec3) 417 { 418 BMCWEB_LOG_ERROR 419 << "DBUS response " 420 "error " 421 << ec3; 422 return; 423 } 424 modifyCpuFunctionalState( 425 aResp, cpuFunctionalCheck); 426 }; 427 // Get the Presence of CPU 428 crow::connections::systemBus 429 ->async_method_call( 430 std::move(getCpuPresenceState), 431 service, path, 432 "org.freedesktop.DBus." 433 "Properties", 434 "Get", 435 "xyz.openbmc_project.Inventory." 436 "Item", 437 "Present"); 438 439 // Get the Functional State 440 crow::connections::systemBus 441 ->async_method_call( 442 std::move( 443 getCpuFunctionalState), 444 service, path, 445 "org.freedesktop.DBus." 446 "Properties", 447 "Get", 448 "xyz.openbmc_project.State." 449 "Decorator." 450 "OperationalStatus", 451 "Functional"); 452 453 // Get the MODEL from 454 // xyz.openbmc_project.Inventory.Decorator.Asset 455 // support it later as Model is Empty 456 // currently. 457 } 458 }, 459 connection.first, path, 460 "org.freedesktop.DBus.Properties", "GetAll", 461 "xyz.openbmc_project.Inventory.Item.Cpu"); 462 463 cpuHealth->inventory.emplace_back(path); 464 } 465 else if (interfaceName == 466 "xyz.openbmc_project.Common.UUID") 467 { 468 BMCWEB_LOG_DEBUG 469 << "Found UUID, now get its properties."; 470 crow::connections::systemBus->async_method_call( 471 [aResp]( 472 const boost::system::error_code ec3, 473 const std::vector< 474 std::pair<std::string, VariantType>>& 475 properties) { 476 if (ec3) 477 { 478 BMCWEB_LOG_DEBUG 479 << "DBUS response error " << ec3; 480 messages::internalError(aResp->res); 481 return; 482 } 483 BMCWEB_LOG_DEBUG << "Got " 484 << properties.size() 485 << " UUID properties."; 486 for (const std::pair<std::string, 487 VariantType>& 488 property : properties) 489 { 490 if (property.first == "UUID") 491 { 492 const std::string* value = 493 std::get_if<std::string>( 494 &property.second); 495 496 if (value != nullptr) 497 { 498 std::string valueStr = *value; 499 if (valueStr.size() == 32) 500 { 501 valueStr.insert(8, 1, '-'); 502 valueStr.insert(13, 1, '-'); 503 valueStr.insert(18, 1, '-'); 504 valueStr.insert(23, 1, '-'); 505 } 506 BMCWEB_LOG_DEBUG << "UUID = " 507 << valueStr; 508 aResp->res.jsonValue["UUID"] = 509 valueStr; 510 } 511 } 512 } 513 }, 514 connection.first, path, 515 "org.freedesktop.DBus.Properties", "GetAll", 516 "xyz.openbmc_project.Common.UUID"); 517 } 518 else if (interfaceName == 519 "xyz.openbmc_project.Inventory.Item.System") 520 { 521 crow::connections::systemBus->async_method_call( 522 [aResp]( 523 const boost::system::error_code ec2, 524 const std::vector< 525 std::pair<std::string, VariantType>>& 526 propertiesList) { 527 if (ec2) 528 { 529 // doesn't have to include this 530 // interface 531 return; 532 } 533 BMCWEB_LOG_DEBUG 534 << "Got " << propertiesList.size() 535 << " properties for system"; 536 for (const std::pair<std::string, 537 VariantType>& 538 property : propertiesList) 539 { 540 const std::string& propertyName = 541 property.first; 542 if ((propertyName == "PartNumber") || 543 (propertyName == "SerialNumber") || 544 (propertyName == "Manufacturer") || 545 (propertyName == "Model") || 546 (propertyName == "SubModel")) 547 { 548 const std::string* value = 549 std::get_if<std::string>( 550 &property.second); 551 if (value != nullptr) 552 { 553 aResp->res 554 .jsonValue[propertyName] = 555 *value; 556 } 557 } 558 } 559 560 // Grab the bios version 561 fw_util::populateFirmwareInformation( 562 aResp, fw_util::biosPurpose, 563 "BiosVersion", false); 564 }, 565 connection.first, path, 566 "org.freedesktop.DBus.Properties", "GetAll", 567 "xyz.openbmc_project.Inventory.Decorator." 568 "Asset"); 569 570 crow::connections::systemBus->async_method_call( 571 [aResp]( 572 const boost::system::error_code ec2, 573 const std::variant<std::string>& property) { 574 if (ec2) 575 { 576 // doesn't have to include this 577 // interface 578 return; 579 } 580 581 const std::string* value = 582 std::get_if<std::string>(&property); 583 if (value != nullptr) 584 { 585 aResp->res.jsonValue["AssetTag"] = 586 *value; 587 } 588 }, 589 connection.first, path, 590 "org.freedesktop.DBus.Properties", "Get", 591 "xyz.openbmc_project.Inventory.Decorator." 592 "AssetTag", 593 "AssetTag"); 594 } 595 } 596 } 597 } 598 }, 599 "xyz.openbmc_project.ObjectMapper", 600 "/xyz/openbmc_project/object_mapper", 601 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 602 "/xyz/openbmc_project/inventory", int32_t(0), 603 std::array<const char*, 5>{ 604 "xyz.openbmc_project.Inventory.Decorator.Asset", 605 "xyz.openbmc_project.Inventory.Item.Cpu", 606 "xyz.openbmc_project.Inventory.Item.Dimm", 607 "xyz.openbmc_project.Inventory.Item.System", 608 "xyz.openbmc_project.Common.UUID", 609 }); 610 } 611 612 /** 613 * @brief Retrieves host state properties over dbus 614 * 615 * @param[in] aResp Shared pointer for completing asynchronous calls. 616 * 617 * @return None. 618 */ 619 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 620 { 621 BMCWEB_LOG_DEBUG << "Get host information."; 622 crow::connections::systemBus->async_method_call( 623 [aResp](const boost::system::error_code ec, 624 const std::variant<std::string>& hostState) { 625 if (ec) 626 { 627 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 628 messages::internalError(aResp->res); 629 return; 630 } 631 632 const std::string* s = std::get_if<std::string>(&hostState); 633 BMCWEB_LOG_DEBUG << "Host state: " << *s; 634 if (s != nullptr) 635 { 636 // Verify Host State 637 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 638 { 639 aResp->res.jsonValue["PowerState"] = "On"; 640 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 641 } 642 else if (*s == "xyz.openbmc_project.State.Host.HostState." 643 "Quiesced") 644 { 645 aResp->res.jsonValue["PowerState"] = "On"; 646 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 647 } 648 else if (*s == "xyz.openbmc_project.State.Host.HostState." 649 "DiagnosticMode") 650 { 651 aResp->res.jsonValue["PowerState"] = "On"; 652 aResp->res.jsonValue["Status"]["State"] = "InTest"; 653 } 654 else if (*s == "xyz.openbmc_project.State.Host.HostState." 655 "TransitioningToRunning") 656 { 657 aResp->res.jsonValue["PowerState"] = "PoweringOn"; 658 aResp->res.jsonValue["Status"]["State"] = "Starting"; 659 } 660 else if (*s == "xyz.openbmc_project.State.Host.HostState." 661 "TransitioningToOff") 662 { 663 aResp->res.jsonValue["PowerState"] = "PoweringOff"; 664 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 665 } 666 else 667 { 668 aResp->res.jsonValue["PowerState"] = "Off"; 669 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 670 } 671 } 672 }, 673 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 674 "org.freedesktop.DBus.Properties", "Get", 675 "xyz.openbmc_project.State.Host", "CurrentHostState"); 676 } 677 678 /** 679 * @brief Translates boot source DBUS property value to redfish. 680 * 681 * @param[in] dbusSource The boot source in DBUS speak. 682 * 683 * @return Returns as a string, the boot source in Redfish terms. If translation 684 * cannot be done, returns an empty string. 685 */ 686 inline std::string dbusToRfBootSource(const std::string& dbusSource) 687 { 688 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 689 { 690 return "None"; 691 } 692 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 693 { 694 return "Hdd"; 695 } 696 if (dbusSource == 697 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 698 { 699 return "Cd"; 700 } 701 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 702 { 703 return "Pxe"; 704 } 705 if (dbusSource == 706 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 707 { 708 return "Usb"; 709 } 710 return ""; 711 } 712 713 /** 714 * @brief Translates boot type DBUS property value to redfish. 715 * 716 * @param[in] dbusType The boot type in DBUS speak. 717 * 718 * @return Returns as a string, the boot type in Redfish terms. If translation 719 * cannot be done, returns an empty string. 720 */ 721 inline std::string dbusToRfBootType(const std::string& dbusType) 722 { 723 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy") 724 { 725 return "Legacy"; 726 } 727 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI") 728 { 729 return "UEFI"; 730 } 731 return ""; 732 } 733 734 /** 735 * @brief Translates boot mode DBUS property value to redfish. 736 * 737 * @param[in] dbusMode The boot mode in DBUS speak. 738 * 739 * @return Returns as a string, the boot mode in Redfish terms. If translation 740 * cannot be done, returns an empty string. 741 */ 742 inline std::string dbusToRfBootMode(const std::string& dbusMode) 743 { 744 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 745 { 746 return "None"; 747 } 748 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 749 { 750 return "Diags"; 751 } 752 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 753 { 754 return "BiosSetup"; 755 } 756 return ""; 757 } 758 759 /** 760 * @brief Translates boot source from Redfish to the DBus boot paths. 761 * 762 * @param[in] rfSource The boot source in Redfish. 763 * @param[out] bootSource The DBus source 764 * @param[out] bootMode the DBus boot mode 765 * 766 * @return Integer error code. 767 */ 768 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 769 const std::string& rfSource, 770 std::string& bootSource, std::string& bootMode) 771 { 772 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 773 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 774 775 if (rfSource == "None") 776 { 777 return 0; 778 } 779 if (rfSource == "Pxe") 780 { 781 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 782 } 783 else if (rfSource == "Hdd") 784 { 785 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 786 } 787 else if (rfSource == "Diags") 788 { 789 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 790 } 791 else if (rfSource == "Cd") 792 { 793 bootSource = 794 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 795 } 796 else if (rfSource == "BiosSetup") 797 { 798 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 799 } 800 else if (rfSource == "Usb") 801 { 802 bootSource = 803 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 804 } 805 else 806 { 807 BMCWEB_LOG_DEBUG << "Invalid property value for " 808 "BootSourceOverrideTarget: " 809 << bootSource; 810 messages::propertyValueNotInList(aResp->res, rfSource, 811 "BootSourceTargetOverride"); 812 return -1; 813 } 814 return 0; 815 } 816 817 /** 818 * @brief Retrieves boot progress of the system 819 * 820 * @param[in] aResp Shared pointer for generating response message. 821 * 822 * @return None. 823 */ 824 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 825 { 826 crow::connections::systemBus->async_method_call( 827 [aResp](const boost::system::error_code ec, 828 const std::variant<std::string>& bootProgress) { 829 if (ec) 830 { 831 // BootProgress is an optional object so just do nothing if 832 // not found 833 return; 834 } 835 836 const std::string* bootProgressStr = 837 std::get_if<std::string>(&bootProgress); 838 839 if (!bootProgressStr) 840 { 841 // Interface implemented but property not found, return error 842 // for that 843 messages::internalError(aResp->res); 844 return; 845 } 846 847 BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr; 848 849 // Now convert the D-Bus BootProgress to the appropriate Redfish 850 // enum 851 std::string rfBpLastState = "None"; 852 if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress." 853 "ProgressStages.Unspecified") 854 { 855 rfBpLastState = "None"; 856 } 857 else if (*bootProgressStr == 858 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 859 "PrimaryProcInit") 860 { 861 rfBpLastState = "PrimaryProcessorInitializationStarted"; 862 } 863 else if (*bootProgressStr == 864 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 865 "BusInit") 866 { 867 rfBpLastState = "BusInitializationStarted"; 868 } 869 else if (*bootProgressStr == 870 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 871 "MemoryInit") 872 { 873 rfBpLastState = "MemoryInitializationStarted"; 874 } 875 else if (*bootProgressStr == 876 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 877 "SecondaryProcInit") 878 { 879 rfBpLastState = "SecondaryProcessorInitializationStarted"; 880 } 881 else if (*bootProgressStr == 882 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 883 "PCIInit") 884 { 885 rfBpLastState = "PCIResourceConfigStarted"; 886 } 887 else if (*bootProgressStr == 888 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 889 "SystemInitComplete") 890 { 891 rfBpLastState = "SystemHardwareInitializationComplete"; 892 } 893 else if (*bootProgressStr == 894 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 895 "OSStart") 896 { 897 rfBpLastState = "OSBootStarted"; 898 } 899 else if (*bootProgressStr == 900 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 901 "OSRunning") 902 { 903 rfBpLastState = "OSRunning"; 904 } 905 else 906 { 907 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 908 << *bootProgressStr; 909 // Just return the default 910 } 911 912 aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState; 913 }, 914 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 915 "org.freedesktop.DBus.Properties", "Get", 916 "xyz.openbmc_project.State.Boot.Progress", "BootProgress"); 917 } 918 919 /** 920 * @brief Retrieves boot override type over DBUS and fills out the response 921 * 922 * @param[in] aResp Shared pointer for generating response message. 923 * 924 * @return None. 925 */ 926 927 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 928 { 929 crow::connections::systemBus->async_method_call( 930 [aResp](const boost::system::error_code ec, 931 const std::variant<std::string>& bootType) { 932 if (ec) 933 { 934 // not an error, don't have to have the interface 935 return; 936 } 937 938 const std::string* bootTypeStr = 939 std::get_if<std::string>(&bootType); 940 941 if (!bootTypeStr) 942 { 943 messages::internalError(aResp->res); 944 return; 945 } 946 947 BMCWEB_LOG_DEBUG << "Boot type: " << *bootTypeStr; 948 949 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode@Redfish." 950 "AllowableValues"] = {"Legacy", 951 "UEFI"}; 952 953 auto rfType = dbusToRfBootType(*bootTypeStr); 954 if (rfType.empty()) 955 { 956 messages::internalError(aResp->res); 957 return; 958 } 959 960 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType; 961 }, 962 "xyz.openbmc_project.Settings", 963 "/xyz/openbmc_project/control/host0/boot", 964 "org.freedesktop.DBus.Properties", "Get", 965 "xyz.openbmc_project.Control.Boot.Type", "BootType"); 966 } 967 968 /** 969 * @brief Retrieves boot override mode over DBUS and fills out the response 970 * 971 * @param[in] aResp Shared pointer for generating response message. 972 * 973 * @return None. 974 */ 975 976 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 977 { 978 crow::connections::systemBus->async_method_call( 979 [aResp](const boost::system::error_code ec, 980 const std::variant<std::string>& bootMode) { 981 if (ec) 982 { 983 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 984 messages::internalError(aResp->res); 985 return; 986 } 987 988 const std::string* bootModeStr = 989 std::get_if<std::string>(&bootMode); 990 991 if (!bootModeStr) 992 { 993 messages::internalError(aResp->res); 994 return; 995 } 996 997 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 998 999 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 1000 "AllowableValues"] = { 1001 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 1002 1003 if (*bootModeStr != 1004 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 1005 { 1006 auto rfMode = dbusToRfBootMode(*bootModeStr); 1007 if (!rfMode.empty()) 1008 { 1009 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1010 rfMode; 1011 } 1012 } 1013 }, 1014 "xyz.openbmc_project.Settings", 1015 "/xyz/openbmc_project/control/host0/boot", 1016 "org.freedesktop.DBus.Properties", "Get", 1017 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 1018 } 1019 1020 /** 1021 * @brief Retrieves boot override source over DBUS 1022 * 1023 * @param[in] aResp Shared pointer for generating response message. 1024 * 1025 * @return None. 1026 */ 1027 1028 inline void 1029 getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1030 { 1031 crow::connections::systemBus->async_method_call( 1032 [aResp](const boost::system::error_code ec, 1033 const std::variant<std::string>& bootSource) { 1034 if (ec) 1035 { 1036 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1037 messages::internalError(aResp->res); 1038 return; 1039 } 1040 1041 const std::string* bootSourceStr = 1042 std::get_if<std::string>(&bootSource); 1043 1044 if (!bootSourceStr) 1045 { 1046 messages::internalError(aResp->res); 1047 return; 1048 } 1049 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 1050 1051 auto rfSource = dbusToRfBootSource(*bootSourceStr); 1052 if (!rfSource.empty()) 1053 { 1054 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1055 rfSource; 1056 } 1057 1058 // Get BootMode as BootSourceOverrideTarget is constructed 1059 // from both BootSource and BootMode 1060 getBootOverrideMode(aResp); 1061 }, 1062 "xyz.openbmc_project.Settings", 1063 "/xyz/openbmc_project/control/host0/boot", 1064 "org.freedesktop.DBus.Properties", "Get", 1065 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 1066 } 1067 1068 /** 1069 * @brief This functions abstracts all the logic behind getting a 1070 * "BootSourceOverrideEnabled" property from an overall boot override enable 1071 * state 1072 * 1073 * @param[in] aResp Shared pointer for generating response message. 1074 * 1075 * @return None. 1076 */ 1077 1078 inline void 1079 processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1080 const bool bootOverrideEnableSetting) 1081 { 1082 if (!bootOverrideEnableSetting) 1083 { 1084 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled"; 1085 return; 1086 } 1087 1088 // If boot source override is enabled, we need to check 'one_time' 1089 // property to set a correct value for the "BootSourceOverrideEnabled" 1090 crow::connections::systemBus->async_method_call( 1091 [aResp](const boost::system::error_code ec, 1092 const std::variant<bool>& oneTime) { 1093 if (ec) 1094 { 1095 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1096 messages::internalError(aResp->res); 1097 return; 1098 } 1099 1100 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1101 1102 if (!oneTimePtr) 1103 { 1104 messages::internalError(aResp->res); 1105 return; 1106 } 1107 1108 bool oneTimeSetting = *oneTimePtr; 1109 1110 if (oneTimeSetting) 1111 { 1112 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1113 "Once"; 1114 } 1115 else 1116 { 1117 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1118 "Continuous"; 1119 } 1120 }, 1121 "xyz.openbmc_project.Settings", 1122 "/xyz/openbmc_project/control/host0/boot/one_time", 1123 "org.freedesktop.DBus.Properties", "Get", 1124 "xyz.openbmc_project.Object.Enable", "Enabled"); 1125 } 1126 1127 /** 1128 * @brief Retrieves boot override enable over DBUS 1129 * 1130 * @param[in] aResp Shared pointer for generating response message. 1131 * 1132 * @return None. 1133 */ 1134 1135 inline void 1136 getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1137 { 1138 crow::connections::systemBus->async_method_call( 1139 [aResp](const boost::system::error_code ec, 1140 const std::variant<bool>& bootOverrideEnable) { 1141 if (ec) 1142 { 1143 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1144 messages::internalError(aResp->res); 1145 return; 1146 } 1147 1148 const bool* bootOverrideEnablePtr = 1149 std::get_if<bool>(&bootOverrideEnable); 1150 1151 if (!bootOverrideEnablePtr) 1152 { 1153 messages::internalError(aResp->res); 1154 return; 1155 } 1156 1157 processBootOverrideEnable(aResp, *bootOverrideEnablePtr); 1158 }, 1159 "xyz.openbmc_project.Settings", 1160 "/xyz/openbmc_project/control/host0/boot", 1161 "org.freedesktop.DBus.Properties", "Get", 1162 "xyz.openbmc_project.Object.Enable", "Enabled"); 1163 } 1164 1165 /** 1166 * @brief Retrieves boot source override properties 1167 * 1168 * @param[in] aResp Shared pointer for generating response message. 1169 * 1170 * @return None. 1171 */ 1172 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1173 { 1174 BMCWEB_LOG_DEBUG << "Get boot information."; 1175 1176 getBootOverrideSource(aResp); 1177 getBootOverrideType(aResp); 1178 getBootOverrideEnable(aResp); 1179 } 1180 1181 /** 1182 * @brief Retrieves the Last Reset Time 1183 * 1184 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1185 * and power off. Even though this is the "system" Redfish object look at the 1186 * chassis D-Bus interface for the LastStateChangeTime since this has the 1187 * last power operation time. 1188 * 1189 * @param[in] aResp Shared pointer for generating response message. 1190 * 1191 * @return None. 1192 */ 1193 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1194 { 1195 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1196 1197 crow::connections::systemBus->async_method_call( 1198 [aResp](const boost::system::error_code ec, 1199 std::variant<uint64_t>& lastResetTime) { 1200 if (ec) 1201 { 1202 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1203 return; 1204 } 1205 1206 const uint64_t* lastResetTimePtr = 1207 std::get_if<uint64_t>(&lastResetTime); 1208 1209 if (!lastResetTimePtr) 1210 { 1211 messages::internalError(aResp->res); 1212 return; 1213 } 1214 // LastStateChangeTime is epoch time, in milliseconds 1215 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1216 time_t lastResetTimeStamp = 1217 static_cast<time_t>(*lastResetTimePtr / 1000); 1218 1219 // Convert to ISO 8601 standard 1220 aResp->res.jsonValue["LastResetTime"] = 1221 crow::utility::getDateTime(lastResetTimeStamp); 1222 }, 1223 "xyz.openbmc_project.State.Chassis", 1224 "/xyz/openbmc_project/state/chassis0", 1225 "org.freedesktop.DBus.Properties", "Get", 1226 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1227 } 1228 1229 /** 1230 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1231 * 1232 * @param[in] aResp Shared pointer for generating response message. 1233 * 1234 * @return None. 1235 */ 1236 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1237 { 1238 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1239 1240 crow::connections::systemBus->async_method_call( 1241 [aResp](const boost::system::error_code ec, 1242 std::variant<bool>& autoRebootEnabled) { 1243 if (ec) 1244 { 1245 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1246 return; 1247 } 1248 1249 const bool* autoRebootEnabledPtr = 1250 std::get_if<bool>(&autoRebootEnabled); 1251 1252 if (!autoRebootEnabledPtr) 1253 { 1254 messages::internalError(aResp->res); 1255 return; 1256 } 1257 1258 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1259 if (*autoRebootEnabledPtr == true) 1260 { 1261 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1262 "RetryAttempts"; 1263 // If AutomaticRetry (AutoReboot) is enabled see how many 1264 // attempts are left 1265 crow::connections::systemBus->async_method_call( 1266 [aResp](const boost::system::error_code ec2, 1267 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1268 if (ec2) 1269 { 1270 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1271 return; 1272 } 1273 1274 const uint32_t* autoRebootAttemptsLeftPtr = 1275 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1276 1277 if (!autoRebootAttemptsLeftPtr) 1278 { 1279 messages::internalError(aResp->res); 1280 return; 1281 } 1282 1283 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1284 << *autoRebootAttemptsLeftPtr; 1285 1286 aResp->res 1287 .jsonValue["Boot"] 1288 ["RemainingAutomaticRetryAttempts"] = 1289 *autoRebootAttemptsLeftPtr; 1290 }, 1291 "xyz.openbmc_project.State.Host", 1292 "/xyz/openbmc_project/state/host0", 1293 "org.freedesktop.DBus.Properties", "Get", 1294 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1295 "AttemptsLeft"); 1296 } 1297 else 1298 { 1299 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1300 "Disabled"; 1301 } 1302 1303 // Not on D-Bus. Hardcoded here: 1304 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1305 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1306 1307 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1308 // and RetryAttempts. OpenBMC only supports Disabled and 1309 // RetryAttempts. 1310 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1311 "AllowableValues"] = {"Disabled", 1312 "RetryAttempts"}; 1313 }, 1314 "xyz.openbmc_project.Settings", 1315 "/xyz/openbmc_project/control/host0/auto_reboot", 1316 "org.freedesktop.DBus.Properties", "Get", 1317 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1318 } 1319 1320 /** 1321 * @brief Retrieves power restore policy over DBUS. 1322 * 1323 * @param[in] aResp Shared pointer for generating response message. 1324 * 1325 * @return None. 1326 */ 1327 inline void 1328 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1329 { 1330 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1331 1332 crow::connections::systemBus->async_method_call( 1333 [aResp](const boost::system::error_code ec, 1334 std::variant<std::string>& policy) { 1335 if (ec) 1336 { 1337 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1338 return; 1339 } 1340 1341 const boost::container::flat_map<std::string, std::string> 1342 policyMaps = { 1343 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1344 "AlwaysOn", 1345 "AlwaysOn"}, 1346 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1347 "AlwaysOff", 1348 "AlwaysOff"}, 1349 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1350 "Restore", 1351 "LastState"}}; 1352 1353 const std::string* policyPtr = std::get_if<std::string>(&policy); 1354 1355 if (!policyPtr) 1356 { 1357 messages::internalError(aResp->res); 1358 return; 1359 } 1360 1361 auto policyMapsIt = policyMaps.find(*policyPtr); 1362 if (policyMapsIt == policyMaps.end()) 1363 { 1364 messages::internalError(aResp->res); 1365 return; 1366 } 1367 1368 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1369 }, 1370 "xyz.openbmc_project.Settings", 1371 "/xyz/openbmc_project/control/host0/power_restore_policy", 1372 "org.freedesktop.DBus.Properties", "Get", 1373 "xyz.openbmc_project.Control.Power.RestorePolicy", 1374 "PowerRestorePolicy"); 1375 } 1376 1377 /** 1378 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1379 * TPM is required for booting the host. 1380 * 1381 * @param[in] aResp Shared pointer for generating response message. 1382 * 1383 * @return None. 1384 */ 1385 inline void getTrustedModuleRequiredToBoot( 1386 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1387 { 1388 BMCWEB_LOG_DEBUG << "Get TPM required to boot."; 1389 1390 crow::connections::systemBus->async_method_call( 1391 [aResp]( 1392 const boost::system::error_code ec, 1393 std::vector<std::pair< 1394 std::string, 1395 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1396 subtree) { 1397 if (ec) 1398 { 1399 BMCWEB_LOG_DEBUG 1400 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1401 // This is an optional D-Bus object so just return if 1402 // error occurs 1403 return; 1404 } 1405 if (subtree.size() == 0) 1406 { 1407 // As noted above, this is an optional interface so just return 1408 // if there is no instance found 1409 return; 1410 } 1411 1412 /* When there is more than one TPMEnable object... */ 1413 if (subtree.size() > 1) 1414 { 1415 BMCWEB_LOG_DEBUG 1416 << "DBUS response has more than 1 TPM Enable object:" 1417 << subtree.size(); 1418 // Throw an internal Error and return 1419 messages::internalError(aResp->res); 1420 return; 1421 } 1422 1423 // Make sure the Dbus response map has a service and objectPath 1424 // field 1425 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1426 { 1427 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1428 messages::internalError(aResp->res); 1429 return; 1430 } 1431 1432 const std::string& path = subtree[0].first; 1433 const std::string& serv = subtree[0].second.begin()->first; 1434 1435 // Valid TPM Enable object found, now reading the current value 1436 crow::connections::systemBus->async_method_call( 1437 [aResp](const boost::system::error_code ec, 1438 std::variant<bool>& tpmRequired) { 1439 if (ec) 1440 { 1441 BMCWEB_LOG_DEBUG 1442 << "D-BUS response error on TPM.Policy Get" << ec; 1443 messages::internalError(aResp->res); 1444 return; 1445 } 1446 1447 const bool* tpmRequiredVal = 1448 std::get_if<bool>(&tpmRequired); 1449 1450 if (!tpmRequiredVal) 1451 { 1452 messages::internalError(aResp->res); 1453 return; 1454 } 1455 1456 if (*tpmRequiredVal == true) 1457 { 1458 aResp->res 1459 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1460 "Required"; 1461 } 1462 else 1463 { 1464 aResp->res 1465 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1466 "Disabled"; 1467 } 1468 }, 1469 serv, path, "org.freedesktop.DBus.Properties", "Get", 1470 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable"); 1471 }, 1472 "xyz.openbmc_project.ObjectMapper", 1473 "/xyz/openbmc_project/object_mapper", 1474 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1475 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1476 } 1477 1478 /** 1479 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1480 * TPM is required for booting the host. 1481 * 1482 * @param[in] aResp Shared pointer for generating response message. 1483 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1484 * 1485 * @return None. 1486 */ 1487 inline void setTrustedModuleRequiredToBoot( 1488 const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired) 1489 { 1490 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot."; 1491 1492 crow::connections::systemBus->async_method_call( 1493 [aResp, tpmRequired]( 1494 const boost::system::error_code ec, 1495 std::vector<std::pair< 1496 std::string, 1497 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1498 subtree) { 1499 if (ec) 1500 { 1501 BMCWEB_LOG_DEBUG 1502 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1503 messages::internalError(aResp->res); 1504 return; 1505 } 1506 if (subtree.size() == 0) 1507 { 1508 messages::propertyValueNotInList(aResp->res, "ComputerSystem", 1509 "TrustedModuleRequiredToBoot"); 1510 return; 1511 } 1512 1513 /* When there is more than one TPMEnable object... */ 1514 if (subtree.size() > 1) 1515 { 1516 BMCWEB_LOG_DEBUG 1517 << "DBUS response has more than 1 TPM Enable object:" 1518 << subtree.size(); 1519 // Throw an internal Error and return 1520 messages::internalError(aResp->res); 1521 return; 1522 } 1523 1524 // Make sure the Dbus response map has a service and objectPath 1525 // field 1526 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1527 { 1528 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1529 messages::internalError(aResp->res); 1530 return; 1531 } 1532 1533 const std::string& path = subtree[0].first; 1534 const std::string& serv = subtree[0].second.begin()->first; 1535 1536 if (serv.empty()) 1537 { 1538 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!"; 1539 messages::internalError(aResp->res); 1540 return; 1541 } 1542 1543 // Valid TPM Enable object found, now setting the value 1544 crow::connections::systemBus->async_method_call( 1545 [aResp](const boost::system::error_code ec) { 1546 if (ec) 1547 { 1548 BMCWEB_LOG_DEBUG << "DBUS response error: Set " 1549 "TrustedModuleRequiredToBoot" 1550 << ec; 1551 messages::internalError(aResp->res); 1552 return; 1553 } 1554 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done."; 1555 }, 1556 serv, path, "org.freedesktop.DBus.Properties", "Set", 1557 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1558 std::variant<bool>(tpmRequired)); 1559 }, 1560 "xyz.openbmc_project.ObjectMapper", 1561 "/xyz/openbmc_project/object_mapper", 1562 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1563 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1564 } 1565 1566 /** 1567 * @brief Sets boot properties into DBUS object(s). 1568 * 1569 * @param[in] aResp Shared pointer for generating response message. 1570 * @param[in] bootType The boot type to set. 1571 * @return Integer error code. 1572 */ 1573 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1574 const std::optional<std::string>& bootType) 1575 { 1576 std::string bootTypeStr; 1577 1578 if (!bootType) 1579 { 1580 return; 1581 } 1582 1583 // Source target specified 1584 BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; 1585 // Figure out which DBUS interface and property to use 1586 if (*bootType == "Legacy") 1587 { 1588 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1589 } 1590 else if (*bootType == "UEFI") 1591 { 1592 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1593 } 1594 else 1595 { 1596 BMCWEB_LOG_DEBUG << "Invalid property value for " 1597 "BootSourceOverrideMode: " 1598 << *bootType; 1599 messages::propertyValueNotInList(aResp->res, *bootType, 1600 "BootSourceOverrideMode"); 1601 return; 1602 } 1603 1604 // Act on validated parameters 1605 BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; 1606 1607 crow::connections::systemBus->async_method_call( 1608 [aResp](const boost::system::error_code ec) { 1609 if (ec) 1610 { 1611 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1612 if (ec.value() == boost::asio::error::host_unreachable) 1613 { 1614 messages::resourceNotFound(aResp->res, "Set", "BootType"); 1615 return; 1616 } 1617 messages::internalError(aResp->res); 1618 return; 1619 } 1620 BMCWEB_LOG_DEBUG << "Boot type update done."; 1621 }, 1622 "xyz.openbmc_project.Settings", 1623 "/xyz/openbmc_project/control/host0/boot", 1624 "org.freedesktop.DBus.Properties", "Set", 1625 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1626 std::variant<std::string>(bootTypeStr)); 1627 } 1628 1629 /** 1630 * @brief Sets boot properties into DBUS object(s). 1631 * 1632 * @param[in] aResp Shared pointer for generating response message. 1633 * @param[in] bootType The boot type to set. 1634 * @return Integer error code. 1635 */ 1636 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1637 const std::optional<std::string>& bootEnable) 1638 { 1639 if (!bootEnable) 1640 { 1641 return; 1642 } 1643 // Source target specified 1644 BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable; 1645 1646 bool bootOverrideEnable = false; 1647 bool bootOverridePersistent = false; 1648 // Figure out which DBUS interface and property to use 1649 if (*bootEnable == "Disabled") 1650 { 1651 bootOverrideEnable = false; 1652 } 1653 else if (*bootEnable == "Once") 1654 { 1655 bootOverrideEnable = true; 1656 bootOverridePersistent = false; 1657 } 1658 else if (*bootEnable == "Continuous") 1659 { 1660 bootOverrideEnable = true; 1661 bootOverridePersistent = true; 1662 } 1663 else 1664 { 1665 BMCWEB_LOG_DEBUG << "Invalid property value for " 1666 "BootSourceOverrideEnabled: " 1667 << *bootEnable; 1668 messages::propertyValueNotInList(aResp->res, *bootEnable, 1669 "BootSourceOverrideEnabled"); 1670 return; 1671 } 1672 1673 // Act on validated parameters 1674 BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable; 1675 1676 crow::connections::systemBus->async_method_call( 1677 [aResp](const boost::system::error_code ec) { 1678 if (ec) 1679 { 1680 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1681 messages::internalError(aResp->res); 1682 return; 1683 } 1684 BMCWEB_LOG_DEBUG << "Boot override enable update done."; 1685 }, 1686 "xyz.openbmc_project.Settings", 1687 "/xyz/openbmc_project/control/host0/boot", 1688 "org.freedesktop.DBus.Properties", "Set", 1689 "xyz.openbmc_project.Object.Enable", "Enabled", 1690 std::variant<bool>(bootOverrideEnable)); 1691 1692 if (!bootOverrideEnable) 1693 { 1694 return; 1695 } 1696 1697 // In case boot override is enabled we need to set correct value for the 1698 // 'one_time' enable DBus interface 1699 BMCWEB_LOG_DEBUG << "DBUS boot override persistent: " 1700 << bootOverridePersistent; 1701 1702 crow::connections::systemBus->async_method_call( 1703 [aResp](const boost::system::error_code ec) { 1704 if (ec) 1705 { 1706 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1707 messages::internalError(aResp->res); 1708 return; 1709 } 1710 BMCWEB_LOG_DEBUG << "Boot one_time update done."; 1711 }, 1712 "xyz.openbmc_project.Settings", 1713 "/xyz/openbmc_project/control/host0/boot/one_time", 1714 "org.freedesktop.DBus.Properties", "Set", 1715 "xyz.openbmc_project.Object.Enable", "Enabled", 1716 std::variant<bool>(!bootOverridePersistent)); 1717 } 1718 1719 /** 1720 * @brief Sets boot properties into DBUS object(s). 1721 * 1722 * @param[in] aResp Shared pointer for generating response message. 1723 * @param[in] bootSource The boot source to set. 1724 * 1725 * @return Integer error code. 1726 */ 1727 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1728 const std::optional<std::string>& bootSource) 1729 { 1730 std::string bootSourceStr; 1731 std::string bootModeStr; 1732 1733 if (!bootSource) 1734 { 1735 return; 1736 } 1737 1738 // Source target specified 1739 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1740 // Figure out which DBUS interface and property to use 1741 if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr)) 1742 { 1743 BMCWEB_LOG_DEBUG 1744 << "Invalid property value for BootSourceOverrideTarget: " 1745 << *bootSource; 1746 messages::propertyValueNotInList(aResp->res, *bootSource, 1747 "BootSourceTargetOverride"); 1748 return; 1749 } 1750 1751 // Act on validated parameters 1752 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1753 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1754 1755 crow::connections::systemBus->async_method_call( 1756 [aResp](const boost::system::error_code ec) { 1757 if (ec) 1758 { 1759 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1760 messages::internalError(aResp->res); 1761 return; 1762 } 1763 BMCWEB_LOG_DEBUG << "Boot source update done."; 1764 }, 1765 "xyz.openbmc_project.Settings", 1766 "/xyz/openbmc_project/control/host0/boot", 1767 "org.freedesktop.DBus.Properties", "Set", 1768 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1769 std::variant<std::string>(bootSourceStr)); 1770 1771 crow::connections::systemBus->async_method_call( 1772 [aResp](const boost::system::error_code ec) { 1773 if (ec) 1774 { 1775 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1776 messages::internalError(aResp->res); 1777 return; 1778 } 1779 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1780 }, 1781 "xyz.openbmc_project.Settings", 1782 "/xyz/openbmc_project/control/host0/boot", 1783 "org.freedesktop.DBus.Properties", "Set", 1784 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1785 std::variant<std::string>(bootModeStr)); 1786 } 1787 1788 /** 1789 * @brief Sets Boot source override properties. 1790 * 1791 * @param[in] aResp Shared pointer for generating response message. 1792 * @param[in] bootSource The boot source from incoming RF request. 1793 * @param[in] bootType The boot type from incoming RF request. 1794 * @param[in] bootEnable The boot override enable from incoming RF request. 1795 * 1796 * @return Integer error code. 1797 */ 1798 1799 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1800 const std::optional<std::string>& bootSource, 1801 const std::optional<std::string>& bootType, 1802 const std::optional<std::string>& bootEnable) 1803 { 1804 BMCWEB_LOG_DEBUG << "Set boot information."; 1805 1806 setBootModeOrSource(aResp, bootSource); 1807 setBootType(aResp, bootType); 1808 setBootEnable(aResp, bootEnable); 1809 } 1810 1811 /** 1812 * @brief Sets AssetTag 1813 * 1814 * @param[in] aResp Shared pointer for generating response message. 1815 * @param[in] assetTag "AssetTag" from request. 1816 * 1817 * @return None. 1818 */ 1819 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1820 const std::string& assetTag) 1821 { 1822 crow::connections::systemBus->async_method_call( 1823 [aResp, assetTag]( 1824 const boost::system::error_code ec, 1825 const std::vector<std::pair< 1826 std::string, 1827 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1828 subtree) { 1829 if (ec) 1830 { 1831 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1832 messages::internalError(aResp->res); 1833 return; 1834 } 1835 if (subtree.size() == 0) 1836 { 1837 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1838 messages::internalError(aResp->res); 1839 return; 1840 } 1841 // Assume only 1 system D-Bus object 1842 // Throw an error if there is more than 1 1843 if (subtree.size() > 1) 1844 { 1845 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1846 messages::internalError(aResp->res); 1847 return; 1848 } 1849 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1850 { 1851 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1852 messages::internalError(aResp->res); 1853 return; 1854 } 1855 1856 const std::string& path = subtree[0].first; 1857 const std::string& service = subtree[0].second.begin()->first; 1858 1859 if (service.empty()) 1860 { 1861 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1862 messages::internalError(aResp->res); 1863 return; 1864 } 1865 1866 crow::connections::systemBus->async_method_call( 1867 [aResp](const boost::system::error_code ec2) { 1868 if (ec2) 1869 { 1870 BMCWEB_LOG_DEBUG 1871 << "D-Bus response error on AssetTag Set " << ec2; 1872 messages::internalError(aResp->res); 1873 return; 1874 } 1875 }, 1876 service, path, "org.freedesktop.DBus.Properties", "Set", 1877 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1878 std::variant<std::string>(assetTag)); 1879 }, 1880 "xyz.openbmc_project.ObjectMapper", 1881 "/xyz/openbmc_project/object_mapper", 1882 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1883 "/xyz/openbmc_project/inventory", int32_t(0), 1884 std::array<const char*, 1>{ 1885 "xyz.openbmc_project.Inventory.Item.System"}); 1886 } 1887 1888 /** 1889 * @brief Sets automaticRetry (Auto Reboot) 1890 * 1891 * @param[in] aResp Shared pointer for generating response message. 1892 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1893 * 1894 * @return None. 1895 */ 1896 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1897 const std::string& automaticRetryConfig) 1898 { 1899 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1900 1901 // OpenBMC only supports "Disabled" and "RetryAttempts". 1902 bool autoRebootEnabled; 1903 1904 if (automaticRetryConfig == "Disabled") 1905 { 1906 autoRebootEnabled = false; 1907 } 1908 else if (automaticRetryConfig == "RetryAttempts") 1909 { 1910 autoRebootEnabled = true; 1911 } 1912 else 1913 { 1914 BMCWEB_LOG_DEBUG << "Invalid property value for " 1915 "AutomaticRetryConfig: " 1916 << automaticRetryConfig; 1917 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1918 "AutomaticRetryConfig"); 1919 return; 1920 } 1921 1922 crow::connections::systemBus->async_method_call( 1923 [aResp](const boost::system::error_code ec) { 1924 if (ec) 1925 { 1926 messages::internalError(aResp->res); 1927 return; 1928 } 1929 }, 1930 "xyz.openbmc_project.Settings", 1931 "/xyz/openbmc_project/control/host0/auto_reboot", 1932 "org.freedesktop.DBus.Properties", "Set", 1933 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1934 std::variant<bool>(autoRebootEnabled)); 1935 } 1936 1937 /** 1938 * @brief Sets power restore policy properties. 1939 * 1940 * @param[in] aResp Shared pointer for generating response message. 1941 * @param[in] policy power restore policy properties from request. 1942 * 1943 * @return None. 1944 */ 1945 inline void 1946 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1947 const std::string& policy) 1948 { 1949 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1950 1951 const boost::container::flat_map<std::string, std::string> policyMaps = { 1952 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1953 "AlwaysOn"}, 1954 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1955 "AlwaysOff"}, 1956 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1957 "Restore"}}; 1958 1959 std::string powerRestorPolicy; 1960 1961 auto policyMapsIt = policyMaps.find(policy); 1962 if (policyMapsIt == policyMaps.end()) 1963 { 1964 messages::propertyValueNotInList(aResp->res, policy, 1965 "PowerRestorePolicy"); 1966 return; 1967 } 1968 1969 powerRestorPolicy = policyMapsIt->second; 1970 1971 crow::connections::systemBus->async_method_call( 1972 [aResp](const boost::system::error_code ec) { 1973 if (ec) 1974 { 1975 messages::internalError(aResp->res); 1976 return; 1977 } 1978 }, 1979 "xyz.openbmc_project.Settings", 1980 "/xyz/openbmc_project/control/host0/power_restore_policy", 1981 "org.freedesktop.DBus.Properties", "Set", 1982 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1983 std::variant<std::string>(powerRestorPolicy)); 1984 } 1985 1986 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1987 /** 1988 * @brief Retrieves provisioning status 1989 * 1990 * @param[in] aResp Shared pointer for completing asynchronous calls. 1991 * 1992 * @return None. 1993 */ 1994 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1995 { 1996 BMCWEB_LOG_DEBUG << "Get OEM information."; 1997 crow::connections::systemBus->async_method_call( 1998 [aResp](const boost::system::error_code ec, 1999 const std::vector<std::pair<std::string, VariantType>>& 2000 propertiesList) { 2001 nlohmann::json& oemPFR = 2002 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 2003 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 2004 "#OemComputerSystem.OpenBmc"; 2005 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 2006 2007 if (ec) 2008 { 2009 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2010 // not an error, don't have to have the interface 2011 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2012 return; 2013 } 2014 2015 const bool* provState = nullptr; 2016 const bool* lockState = nullptr; 2017 for (const std::pair<std::string, VariantType>& property : 2018 propertiesList) 2019 { 2020 if (property.first == "UfmProvisioned") 2021 { 2022 provState = std::get_if<bool>(&property.second); 2023 } 2024 else if (property.first == "UfmLocked") 2025 { 2026 lockState = std::get_if<bool>(&property.second); 2027 } 2028 } 2029 2030 if ((provState == nullptr) || (lockState == nullptr)) 2031 { 2032 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 2033 messages::internalError(aResp->res); 2034 return; 2035 } 2036 2037 if (*provState == true) 2038 { 2039 if (*lockState == true) 2040 { 2041 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 2042 } 2043 else 2044 { 2045 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 2046 } 2047 } 2048 else 2049 { 2050 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2051 } 2052 }, 2053 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 2054 "org.freedesktop.DBus.Properties", "GetAll", 2055 "xyz.openbmc_project.PFR.Attributes"); 2056 } 2057 #endif 2058 2059 /** 2060 * @brief Translate the PowerMode to a response message. 2061 * 2062 * @param[in] aResp Shared pointer for generating response message. 2063 * @param[in] modeValue PowerMode value to be translated 2064 * 2065 * @return None. 2066 */ 2067 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2068 const std::string& modeValue) 2069 { 2070 std::string modeString; 2071 2072 if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 2073 "PowerMode.Static") 2074 { 2075 aResp->res.jsonValue["PowerMode"] = "Static"; 2076 } 2077 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 2078 "PowerMode.MaximumPerformance") 2079 { 2080 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 2081 } 2082 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 2083 "PowerMode.PowerSaving") 2084 { 2085 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 2086 } 2087 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 2088 "PowerMode.OEM") 2089 { 2090 aResp->res.jsonValue["PowerMode"] = "OEM"; 2091 } 2092 else 2093 { 2094 // Any other values would be invalid 2095 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 2096 messages::internalError(aResp->res); 2097 } 2098 } 2099 2100 /** 2101 * @brief Retrieves system power mode 2102 * 2103 * @param[in] aResp Shared pointer for generating response message. 2104 * 2105 * @return None. 2106 */ 2107 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2108 { 2109 BMCWEB_LOG_DEBUG << "Get power mode."; 2110 2111 // Get Power Mode object path: 2112 crow::connections::systemBus->async_method_call( 2113 [aResp]( 2114 const boost::system::error_code ec, 2115 const std::vector<std::pair< 2116 std::string, 2117 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2118 subtree) { 2119 if (ec) 2120 { 2121 BMCWEB_LOG_DEBUG 2122 << "DBUS response error on Power.Mode GetSubTree " << ec; 2123 // This is an optional D-Bus object so just return if 2124 // error occurs 2125 return; 2126 } 2127 if (subtree.empty()) 2128 { 2129 // As noted above, this is an optional interface so just return 2130 // if there is no instance found 2131 return; 2132 } 2133 if (subtree.size() > 1) 2134 { 2135 // More then one PowerMode object is not supported and is an 2136 // error 2137 BMCWEB_LOG_DEBUG 2138 << "Found more than 1 system D-Bus Power.Mode objects: " 2139 << subtree.size(); 2140 messages::internalError(aResp->res); 2141 return; 2142 } 2143 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2144 { 2145 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2146 messages::internalError(aResp->res); 2147 return; 2148 } 2149 const std::string& path = subtree[0].first; 2150 const std::string& service = subtree[0].second.begin()->first; 2151 if (service.empty()) 2152 { 2153 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2154 messages::internalError(aResp->res); 2155 return; 2156 } 2157 // Valid Power Mode object found, now read the current value 2158 crow::connections::systemBus->async_method_call( 2159 [aResp](const boost::system::error_code ec, 2160 const std::variant<std::string>& pmode) { 2161 if (ec) 2162 { 2163 BMCWEB_LOG_DEBUG 2164 << "DBUS response error on PowerMode Get: " << ec; 2165 messages::internalError(aResp->res); 2166 return; 2167 } 2168 2169 const std::string* s = std::get_if<std::string>(&pmode); 2170 if (s == nullptr) 2171 { 2172 BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; 2173 messages::internalError(aResp->res); 2174 return; 2175 } 2176 2177 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2178 {"Static", "MaximumPerformance", "PowerSaving"}; 2179 2180 BMCWEB_LOG_DEBUG << "Current power mode: " << *s; 2181 translatePowerMode(aResp, *s); 2182 }, 2183 service, path, "org.freedesktop.DBus.Properties", "Get", 2184 "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); 2185 }, 2186 "xyz.openbmc_project.ObjectMapper", 2187 "/xyz/openbmc_project/object_mapper", 2188 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2189 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2190 } 2191 2192 /** 2193 * @brief Validate the specified mode is valid and return the PowerMode 2194 * name associated with that string 2195 * 2196 * @param[in] aResp Shared pointer for generating response message. 2197 * @param[in] modeString String representing the desired PowerMode 2198 * 2199 * @return PowerMode value or empty string if mode is not valid 2200 */ 2201 inline std::string 2202 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2203 const std::string& modeString) 2204 { 2205 std::string mode; 2206 2207 if (modeString == "Static") 2208 { 2209 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2210 } 2211 else if (modeString == "MaximumPerformance") 2212 { 2213 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode." 2214 "MaximumPerformance"; 2215 } 2216 else if (modeString == "PowerSaving") 2217 { 2218 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2219 } 2220 else 2221 { 2222 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2223 } 2224 return mode; 2225 } 2226 2227 /** 2228 * @brief Sets system power mode. 2229 * 2230 * @param[in] aResp Shared pointer for generating response message. 2231 * @param[in] pmode System power mode from request. 2232 * 2233 * @return None. 2234 */ 2235 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2236 const std::string& pmode) 2237 { 2238 BMCWEB_LOG_DEBUG << "Set power mode."; 2239 2240 std::string powerMode = validatePowerMode(aResp, pmode); 2241 if (powerMode.empty()) 2242 { 2243 return; 2244 } 2245 2246 // Get Power Mode object path: 2247 crow::connections::systemBus->async_method_call( 2248 [aResp, powerMode]( 2249 const boost::system::error_code ec, 2250 const std::vector<std::pair< 2251 std::string, 2252 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2253 subtree) { 2254 if (ec) 2255 { 2256 BMCWEB_LOG_DEBUG 2257 << "DBUS response error on Power.Mode GetSubTree " << ec; 2258 // This is an optional D-Bus object, but user attempted to patch 2259 messages::internalError(aResp->res); 2260 return; 2261 } 2262 if (subtree.empty()) 2263 { 2264 // This is an optional D-Bus object, but user attempted to patch 2265 messages::resourceNotFound(aResp->res, "ComputerSystem", 2266 "PowerMode"); 2267 return; 2268 } 2269 if (subtree.size() > 1) 2270 { 2271 // More then one PowerMode object is not supported and is an 2272 // error 2273 BMCWEB_LOG_DEBUG 2274 << "Found more than 1 system D-Bus Power.Mode objects: " 2275 << subtree.size(); 2276 messages::internalError(aResp->res); 2277 return; 2278 } 2279 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2280 { 2281 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2282 messages::internalError(aResp->res); 2283 return; 2284 } 2285 const std::string& path = subtree[0].first; 2286 const std::string& service = subtree[0].second.begin()->first; 2287 if (service.empty()) 2288 { 2289 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2290 messages::internalError(aResp->res); 2291 return; 2292 } 2293 2294 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2295 << path; 2296 2297 // Set the Power Mode property 2298 crow::connections::systemBus->async_method_call( 2299 [aResp](const boost::system::error_code ec) { 2300 if (ec) 2301 { 2302 messages::internalError(aResp->res); 2303 return; 2304 } 2305 }, 2306 service, path, "org.freedesktop.DBus.Properties", "Set", 2307 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2308 std::variant<std::string>(powerMode)); 2309 }, 2310 "xyz.openbmc_project.ObjectMapper", 2311 "/xyz/openbmc_project/object_mapper", 2312 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2313 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2314 } 2315 2316 /** 2317 * @brief Translates watchdog timeout action DBUS property value to redfish. 2318 * 2319 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2320 * 2321 * @return Returns as a string, the timeout action in Redfish terms. If 2322 * translation cannot be done, returns an empty string. 2323 */ 2324 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2325 { 2326 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2327 { 2328 return "None"; 2329 } 2330 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2331 { 2332 return "ResetSystem"; 2333 } 2334 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2335 { 2336 return "PowerDown"; 2337 } 2338 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2339 { 2340 return "PowerCycle"; 2341 } 2342 2343 return ""; 2344 } 2345 2346 /** 2347 *@brief Translates timeout action from Redfish to DBUS property value. 2348 * 2349 *@param[in] rfAction The timeout action in Redfish. 2350 * 2351 *@return Returns as a string, the time_out action as expected by DBUS. 2352 *If translation cannot be done, returns an empty string. 2353 */ 2354 2355 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2356 { 2357 if (rfAction == "None") 2358 { 2359 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2360 } 2361 if (rfAction == "PowerCycle") 2362 { 2363 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2364 } 2365 if (rfAction == "PowerDown") 2366 { 2367 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2368 } 2369 if (rfAction == "ResetSystem") 2370 { 2371 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2372 } 2373 2374 return ""; 2375 } 2376 2377 /** 2378 * @brief Retrieves host watchdog timer properties over DBUS 2379 * 2380 * @param[in] aResp Shared pointer for completing asynchronous calls. 2381 * 2382 * @return None. 2383 */ 2384 inline void 2385 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2386 { 2387 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2388 crow::connections::systemBus->async_method_call( 2389 [aResp](const boost::system::error_code ec, 2390 PropertiesType& properties) { 2391 if (ec) 2392 { 2393 // watchdog service is stopped 2394 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2395 return; 2396 } 2397 2398 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2399 2400 nlohmann::json& hostWatchdogTimer = 2401 aResp->res.jsonValue["HostWatchdogTimer"]; 2402 2403 // watchdog service is running/enabled 2404 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2405 2406 for (const auto& property : properties) 2407 { 2408 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2409 if (property.first == "Enabled") 2410 { 2411 const bool* state = std::get_if<bool>(&property.second); 2412 2413 if (!state) 2414 { 2415 messages::internalError(aResp->res); 2416 return; 2417 } 2418 2419 hostWatchdogTimer["FunctionEnabled"] = *state; 2420 } 2421 else if (property.first == "ExpireAction") 2422 { 2423 const std::string* s = 2424 std::get_if<std::string>(&property.second); 2425 if (!s) 2426 { 2427 messages::internalError(aResp->res); 2428 return; 2429 } 2430 2431 std::string action = dbusToRfWatchdogAction(*s); 2432 if (action.empty()) 2433 { 2434 messages::internalError(aResp->res); 2435 return; 2436 } 2437 hostWatchdogTimer["TimeoutAction"] = action; 2438 } 2439 } 2440 }, 2441 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2442 "org.freedesktop.DBus.Properties", "GetAll", 2443 "xyz.openbmc_project.State.Watchdog"); 2444 } 2445 2446 /** 2447 * @brief Sets Host WatchDog Timer properties. 2448 * 2449 * @param[in] aResp Shared pointer for generating response message. 2450 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2451 * RF request. 2452 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2453 * 2454 * @return None. 2455 */ 2456 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2457 const std::optional<bool> wdtEnable, 2458 const std::optional<std::string>& wdtTimeOutAction) 2459 { 2460 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2461 2462 if (wdtTimeOutAction) 2463 { 2464 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2465 // check if TimeOut Action is Valid 2466 if (wdtTimeOutActStr.empty()) 2467 { 2468 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2469 << *wdtTimeOutAction; 2470 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2471 "TimeoutAction"); 2472 return; 2473 } 2474 2475 crow::connections::systemBus->async_method_call( 2476 [aResp](const boost::system::error_code ec) { 2477 if (ec) 2478 { 2479 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2480 messages::internalError(aResp->res); 2481 return; 2482 } 2483 }, 2484 "xyz.openbmc_project.Watchdog", 2485 "/xyz/openbmc_project/watchdog/host0", 2486 "org.freedesktop.DBus.Properties", "Set", 2487 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2488 std::variant<std::string>(wdtTimeOutActStr)); 2489 } 2490 2491 if (wdtEnable) 2492 { 2493 crow::connections::systemBus->async_method_call( 2494 [aResp](const boost::system::error_code ec) { 2495 if (ec) 2496 { 2497 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2498 messages::internalError(aResp->res); 2499 return; 2500 } 2501 }, 2502 "xyz.openbmc_project.Watchdog", 2503 "/xyz/openbmc_project/watchdog/host0", 2504 "org.freedesktop.DBus.Properties", "Set", 2505 "xyz.openbmc_project.State.Watchdog", "Enabled", 2506 std::variant<bool>(*wdtEnable)); 2507 } 2508 } 2509 2510 /** 2511 * SystemsCollection derived class for delivering ComputerSystems Collection 2512 * Schema 2513 */ 2514 inline void requestRoutesSystemsCollection(App& app) 2515 { 2516 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2517 .privileges(redfish::privileges::getComputerSystemCollection) 2518 .methods(boost::beast::http::verb::get)( 2519 [](const crow::Request& /*req*/, 2520 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2521 asyncResp->res.jsonValue["@odata.type"] = 2522 "#ComputerSystemCollection.ComputerSystemCollection"; 2523 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2524 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2525 2526 crow::connections::systemBus->async_method_call( 2527 [asyncResp](const boost::system::error_code ec, 2528 const std::variant<std::string>& /*hostName*/) { 2529 nlohmann::json& ifaceArray = 2530 asyncResp->res.jsonValue["Members"]; 2531 ifaceArray = nlohmann::json::array(); 2532 auto& count = 2533 asyncResp->res.jsonValue["Members@odata.count"]; 2534 ifaceArray.push_back( 2535 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2536 count = ifaceArray.size(); 2537 if (!ec) 2538 { 2539 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2540 ifaceArray.push_back( 2541 {{"@odata.id", 2542 "/redfish/v1/Systems/hypervisor"}}); 2543 count = ifaceArray.size(); 2544 } 2545 }, 2546 "xyz.openbmc_project.Settings", 2547 "/xyz/openbmc_project/network/hypervisor", 2548 "org.freedesktop.DBus.Properties", "Get", 2549 "xyz.openbmc_project.Network.SystemConfiguration", 2550 "HostName"); 2551 }); 2552 } 2553 2554 /** 2555 * Function transceives data with dbus directly. 2556 */ 2557 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2558 { 2559 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2560 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2561 constexpr char const* interfaceName = 2562 "xyz.openbmc_project.Control.Host.NMI"; 2563 constexpr char const* method = "NMI"; 2564 2565 crow::connections::systemBus->async_method_call( 2566 [asyncResp](const boost::system::error_code ec) { 2567 if (ec) 2568 { 2569 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2570 messages::internalError(asyncResp->res); 2571 return; 2572 } 2573 messages::success(asyncResp->res); 2574 }, 2575 serviceName, objectPath, interfaceName, method); 2576 } 2577 2578 /** 2579 * SystemActionsReset class supports handle POST method for Reset action. 2580 * The class retrieves and sends data directly to D-Bus. 2581 */ 2582 inline void requestRoutesSystemActionsReset(App& app) 2583 { 2584 /** 2585 * Function handles POST method request. 2586 * Analyzes POST body message before sends Reset request data to D-Bus. 2587 */ 2588 BMCWEB_ROUTE(app, 2589 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2590 .privileges(redfish::privileges::postComputerSystem) 2591 .methods( 2592 boost::beast::http::verb:: 2593 post)([](const crow::Request& req, 2594 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2595 std::string resetType; 2596 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2597 resetType)) 2598 { 2599 return; 2600 } 2601 2602 // Get the command and host vs. chassis 2603 std::string command; 2604 bool hostCommand; 2605 if ((resetType == "On") || (resetType == "ForceOn")) 2606 { 2607 command = "xyz.openbmc_project.State.Host.Transition.On"; 2608 hostCommand = true; 2609 } 2610 else if (resetType == "ForceOff") 2611 { 2612 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2613 hostCommand = false; 2614 } 2615 else if (resetType == "ForceRestart") 2616 { 2617 command = 2618 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2619 hostCommand = true; 2620 } 2621 else if (resetType == "GracefulShutdown") 2622 { 2623 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2624 hostCommand = true; 2625 } 2626 else if (resetType == "GracefulRestart") 2627 { 2628 command = "xyz.openbmc_project.State.Host.Transition." 2629 "GracefulWarmReboot"; 2630 hostCommand = true; 2631 } 2632 else if (resetType == "PowerCycle") 2633 { 2634 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2635 hostCommand = true; 2636 } 2637 else if (resetType == "Nmi") 2638 { 2639 doNMI(asyncResp); 2640 return; 2641 } 2642 else 2643 { 2644 messages::actionParameterUnknown(asyncResp->res, "Reset", 2645 resetType); 2646 return; 2647 } 2648 2649 if (hostCommand) 2650 { 2651 crow::connections::systemBus->async_method_call( 2652 [asyncResp, resetType](const boost::system::error_code ec) { 2653 if (ec) 2654 { 2655 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2656 if (ec.value() == 2657 boost::asio::error::invalid_argument) 2658 { 2659 messages::actionParameterNotSupported( 2660 asyncResp->res, resetType, "Reset"); 2661 } 2662 else 2663 { 2664 messages::internalError(asyncResp->res); 2665 } 2666 return; 2667 } 2668 messages::success(asyncResp->res); 2669 }, 2670 "xyz.openbmc_project.State.Host", 2671 "/xyz/openbmc_project/state/host0", 2672 "org.freedesktop.DBus.Properties", "Set", 2673 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2674 std::variant<std::string>{command}); 2675 } 2676 else 2677 { 2678 crow::connections::systemBus->async_method_call( 2679 [asyncResp, resetType](const boost::system::error_code ec) { 2680 if (ec) 2681 { 2682 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2683 if (ec.value() == 2684 boost::asio::error::invalid_argument) 2685 { 2686 messages::actionParameterNotSupported( 2687 asyncResp->res, resetType, "Reset"); 2688 } 2689 else 2690 { 2691 messages::internalError(asyncResp->res); 2692 } 2693 return; 2694 } 2695 messages::success(asyncResp->res); 2696 }, 2697 "xyz.openbmc_project.State.Chassis", 2698 "/xyz/openbmc_project/state/chassis0", 2699 "org.freedesktop.DBus.Properties", "Set", 2700 "xyz.openbmc_project.State.Chassis", 2701 "RequestedPowerTransition", 2702 std::variant<std::string>{command}); 2703 } 2704 }); 2705 } 2706 2707 /** 2708 * Systems derived class for delivering Computer Systems Schema. 2709 */ 2710 inline void requestRoutesSystems(App& app) 2711 { 2712 2713 /** 2714 * Functions triggers appropriate requests on DBus 2715 */ 2716 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2717 .privileges(redfish::privileges::getComputerSystem) 2718 .methods( 2719 boost::beast::http::verb:: 2720 get)([](const crow::Request&, 2721 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2722 asyncResp->res.jsonValue["@odata.type"] = 2723 "#ComputerSystem.v1_15_0.ComputerSystem"; 2724 asyncResp->res.jsonValue["Name"] = "system"; 2725 asyncResp->res.jsonValue["Id"] = "system"; 2726 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2727 asyncResp->res.jsonValue["Description"] = "Computer System"; 2728 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2729 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2730 "Disabled"; 2731 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2732 uint64_t(0); 2733 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2734 "Disabled"; 2735 asyncResp->res.jsonValue["@odata.id"] = 2736 "/redfish/v1/Systems/system"; 2737 2738 asyncResp->res.jsonValue["Processors"] = { 2739 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2740 asyncResp->res.jsonValue["Memory"] = { 2741 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2742 asyncResp->res.jsonValue["Storage"] = { 2743 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2744 2745 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2746 {"target", 2747 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2748 {"@Redfish.ActionInfo", 2749 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2750 2751 asyncResp->res.jsonValue["LogServices"] = { 2752 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2753 2754 asyncResp->res.jsonValue["Bios"] = { 2755 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2756 2757 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2758 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2759 2760 asyncResp->res.jsonValue["Status"] = { 2761 {"Health", "OK"}, 2762 {"State", "Enabled"}, 2763 }; 2764 2765 // Fill in SerialConsole info 2766 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2767 15; 2768 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2769 {"ServiceEnabled", true}, 2770 }; 2771 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2772 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2773 {"ServiceEnabled", true}, 2774 {"Port", 2200}, 2775 // https://github.com/openbmc/docs/blob/master/console.md 2776 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2777 }; 2778 2779 #ifdef BMCWEB_ENABLE_KVM 2780 // Fill in GraphicalConsole info 2781 asyncResp->res.jsonValue["GraphicalConsole"] = { 2782 {"ServiceEnabled", true}, 2783 {"MaxConcurrentSessions", 4}, 2784 {"ConnectTypesSupported", {"KVMIP"}}, 2785 }; 2786 #endif // BMCWEB_ENABLE_KVM 2787 constexpr const std::array<const char*, 4> inventoryForSystems = { 2788 "xyz.openbmc_project.Inventory.Item.Dimm", 2789 "xyz.openbmc_project.Inventory.Item.Cpu", 2790 "xyz.openbmc_project.Inventory.Item.Drive", 2791 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2792 2793 auto health = std::make_shared<HealthPopulate>(asyncResp); 2794 crow::connections::systemBus->async_method_call( 2795 [health](const boost::system::error_code ec, 2796 std::vector<std::string>& resp) { 2797 if (ec) 2798 { 2799 // no inventory 2800 return; 2801 } 2802 2803 health->inventory = std::move(resp); 2804 }, 2805 "xyz.openbmc_project.ObjectMapper", 2806 "/xyz/openbmc_project/object_mapper", 2807 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2808 int32_t(0), inventoryForSystems); 2809 2810 health->populate(); 2811 2812 getMainChassisId( 2813 asyncResp, [](const std::string& chassisId, 2814 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2815 aRsp->res.jsonValue["Links"]["Chassis"] = { 2816 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2817 }); 2818 2819 getLocationIndicatorActive(asyncResp); 2820 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2821 getIndicatorLedState(asyncResp); 2822 getComputerSystem(asyncResp, health); 2823 getHostState(asyncResp); 2824 getBootProperties(asyncResp); 2825 getBootProgress(asyncResp); 2826 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2827 getHostWatchdogTimer(asyncResp); 2828 getPowerRestorePolicy(asyncResp); 2829 getAutomaticRetry(asyncResp); 2830 getLastResetTime(asyncResp); 2831 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2832 getProvisioningStatus(asyncResp); 2833 #endif 2834 getTrustedModuleRequiredToBoot(asyncResp); 2835 getPowerMode(asyncResp); 2836 }); 2837 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2838 .privileges(redfish::privileges::patchComputerSystem) 2839 .methods(boost::beast::http::verb::patch)( 2840 [](const crow::Request& req, 2841 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2842 std::optional<bool> locationIndicatorActive; 2843 std::optional<std::string> indicatorLed; 2844 std::optional<nlohmann::json> bootProps; 2845 std::optional<nlohmann::json> wdtTimerProps; 2846 std::optional<std::string> assetTag; 2847 std::optional<std::string> powerRestorePolicy; 2848 std::optional<std::string> powerMode; 2849 std::optional<bool> trustedModuleRequiredToBoot; 2850 if (!json_util::readJson( 2851 req, asyncResp->res, "IndicatorLED", indicatorLed, 2852 "LocationIndicatorActive", locationIndicatorActive, 2853 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2854 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2855 assetTag, "PowerMode", powerMode, 2856 "TrustedModuleRequiredToBoot", 2857 trustedModuleRequiredToBoot)) 2858 { 2859 return; 2860 } 2861 2862 asyncResp->res.result(boost::beast::http::status::no_content); 2863 2864 if (assetTag) 2865 { 2866 setAssetTag(asyncResp, *assetTag); 2867 } 2868 2869 if (wdtTimerProps) 2870 { 2871 std::optional<bool> wdtEnable; 2872 std::optional<std::string> wdtTimeOutAction; 2873 2874 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2875 "FunctionEnabled", wdtEnable, 2876 "TimeoutAction", wdtTimeOutAction)) 2877 { 2878 return; 2879 } 2880 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2881 } 2882 2883 if (bootProps) 2884 { 2885 std::optional<std::string> bootSource; 2886 std::optional<std::string> bootType; 2887 std::optional<std::string> bootEnable; 2888 std::optional<std::string> automaticRetryConfig; 2889 2890 if (!json_util::readJson( 2891 *bootProps, asyncResp->res, 2892 "BootSourceOverrideTarget", bootSource, 2893 "BootSourceOverrideMode", bootType, 2894 "BootSourceOverrideEnabled", bootEnable, 2895 "AutomaticRetryConfig", automaticRetryConfig)) 2896 { 2897 return; 2898 } 2899 2900 if (bootSource || bootType || bootEnable) 2901 { 2902 setBootProperties(asyncResp, bootSource, bootType, 2903 bootEnable); 2904 } 2905 if (automaticRetryConfig) 2906 { 2907 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2908 } 2909 } 2910 2911 if (locationIndicatorActive) 2912 { 2913 setLocationIndicatorActive(asyncResp, 2914 *locationIndicatorActive); 2915 } 2916 2917 // TODO (Gunnar): Remove IndicatorLED after enough time has 2918 // passed 2919 if (indicatorLed) 2920 { 2921 setIndicatorLedState(asyncResp, *indicatorLed); 2922 asyncResp->res.addHeader( 2923 boost::beast::http::field::warning, 2924 "299 - \"IndicatorLED is deprecated. Use " 2925 "LocationIndicatorActive instead.\""); 2926 } 2927 2928 if (powerRestorePolicy) 2929 { 2930 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2931 } 2932 2933 if (powerMode) 2934 { 2935 setPowerMode(asyncResp, *powerMode); 2936 } 2937 2938 if (trustedModuleRequiredToBoot) 2939 { 2940 setTrustedModuleRequiredToBoot( 2941 asyncResp, *trustedModuleRequiredToBoot); 2942 } 2943 }); 2944 } 2945 2946 /** 2947 * SystemResetActionInfo derived class for delivering Computer Systems 2948 * ResetType AllowableValues using ResetInfo schema. 2949 */ 2950 inline void requestRoutesSystemResetActionInfo(App& app) 2951 { 2952 2953 /** 2954 * Functions triggers appropriate requests on DBus 2955 */ 2956 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2957 .privileges(redfish::privileges::getActionInfo) 2958 .methods(boost::beast::http::verb::get)( 2959 [](const crow::Request&, 2960 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2961 asyncResp->res.jsonValue = { 2962 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2963 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2964 {"Name", "Reset Action Info"}, 2965 {"Id", "ResetActionInfo"}, 2966 {"Parameters", 2967 {{{"Name", "ResetType"}, 2968 {"Required", true}, 2969 {"DataType", "String"}, 2970 {"AllowableValues", 2971 {"On", "ForceOff", "ForceOn", "ForceRestart", 2972 "GracefulRestart", "GracefulShutdown", "PowerCycle", 2973 "Nmi"}}}}}}; 2974 }); 2975 } 2976 } // namespace redfish 2977