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 Sets boot properties into DBUS object(s). 1480 * 1481 * @param[in] aResp Shared pointer for generating response message. 1482 * @param[in] bootType The boot type to set. 1483 * @return Integer error code. 1484 */ 1485 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1486 const std::optional<std::string>& bootType) 1487 { 1488 std::string bootTypeStr; 1489 1490 if (!bootType) 1491 { 1492 return; 1493 } 1494 1495 // Source target specified 1496 BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; 1497 // Figure out which DBUS interface and property to use 1498 if (*bootType == "Legacy") 1499 { 1500 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1501 } 1502 else if (*bootType == "UEFI") 1503 { 1504 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1505 } 1506 else 1507 { 1508 BMCWEB_LOG_DEBUG << "Invalid property value for " 1509 "BootSourceOverrideMode: " 1510 << *bootType; 1511 messages::propertyValueNotInList(aResp->res, *bootType, 1512 "BootSourceOverrideMode"); 1513 return; 1514 } 1515 1516 // Act on validated parameters 1517 BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; 1518 1519 crow::connections::systemBus->async_method_call( 1520 [aResp](const boost::system::error_code ec) { 1521 if (ec) 1522 { 1523 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1524 if (ec.value() == boost::asio::error::host_unreachable) 1525 { 1526 messages::resourceNotFound(aResp->res, "Set", "BootType"); 1527 return; 1528 } 1529 messages::internalError(aResp->res); 1530 return; 1531 } 1532 BMCWEB_LOG_DEBUG << "Boot type update done."; 1533 }, 1534 "xyz.openbmc_project.Settings", 1535 "/xyz/openbmc_project/control/host0/boot", 1536 "org.freedesktop.DBus.Properties", "Set", 1537 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1538 std::variant<std::string>(bootTypeStr)); 1539 } 1540 1541 /** 1542 * @brief Sets boot properties into DBUS object(s). 1543 * 1544 * @param[in] aResp Shared pointer for generating response message. 1545 * @param[in] bootType The boot type to set. 1546 * @return Integer error code. 1547 */ 1548 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1549 const std::optional<std::string>& bootEnable) 1550 { 1551 if (!bootEnable) 1552 { 1553 return; 1554 } 1555 // Source target specified 1556 BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable; 1557 1558 bool bootOverrideEnable = false; 1559 bool bootOverridePersistent = false; 1560 // Figure out which DBUS interface and property to use 1561 if (*bootEnable == "Disabled") 1562 { 1563 bootOverrideEnable = false; 1564 } 1565 else if (*bootEnable == "Once") 1566 { 1567 bootOverrideEnable = true; 1568 bootOverridePersistent = false; 1569 } 1570 else if (*bootEnable == "Continuous") 1571 { 1572 bootOverrideEnable = true; 1573 bootOverridePersistent = true; 1574 } 1575 else 1576 { 1577 BMCWEB_LOG_DEBUG << "Invalid property value for " 1578 "BootSourceOverrideEnabled: " 1579 << *bootEnable; 1580 messages::propertyValueNotInList(aResp->res, *bootEnable, 1581 "BootSourceOverrideEnabled"); 1582 return; 1583 } 1584 1585 // Act on validated parameters 1586 BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable; 1587 1588 crow::connections::systemBus->async_method_call( 1589 [aResp](const boost::system::error_code ec) { 1590 if (ec) 1591 { 1592 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1593 messages::internalError(aResp->res); 1594 return; 1595 } 1596 BMCWEB_LOG_DEBUG << "Boot override enable update done."; 1597 }, 1598 "xyz.openbmc_project.Settings", 1599 "/xyz/openbmc_project/control/host0/boot", 1600 "org.freedesktop.DBus.Properties", "Set", 1601 "xyz.openbmc_project.Object.Enable", "Enabled", 1602 std::variant<bool>(bootOverrideEnable)); 1603 1604 if (!bootOverrideEnable) 1605 { 1606 return; 1607 } 1608 1609 // In case boot override is enabled we need to set correct value for the 1610 // 'one_time' enable DBus interface 1611 BMCWEB_LOG_DEBUG << "DBUS boot override persistent: " 1612 << bootOverridePersistent; 1613 1614 crow::connections::systemBus->async_method_call( 1615 [aResp](const boost::system::error_code ec) { 1616 if (ec) 1617 { 1618 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1619 messages::internalError(aResp->res); 1620 return; 1621 } 1622 BMCWEB_LOG_DEBUG << "Boot one_time update done."; 1623 }, 1624 "xyz.openbmc_project.Settings", 1625 "/xyz/openbmc_project/control/host0/boot/one_time", 1626 "org.freedesktop.DBus.Properties", "Set", 1627 "xyz.openbmc_project.Object.Enable", "Enabled", 1628 std::variant<bool>(!bootOverridePersistent)); 1629 } 1630 1631 /** 1632 * @brief Sets boot properties into DBUS object(s). 1633 * 1634 * @param[in] aResp Shared pointer for generating response message. 1635 * @param[in] bootSource The boot source to set. 1636 * 1637 * @return Integer error code. 1638 */ 1639 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1640 const std::optional<std::string>& bootSource) 1641 { 1642 std::string bootSourceStr; 1643 std::string bootModeStr; 1644 1645 if (!bootSource) 1646 { 1647 return; 1648 } 1649 1650 // Source target specified 1651 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1652 // Figure out which DBUS interface and property to use 1653 if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr)) 1654 { 1655 BMCWEB_LOG_DEBUG 1656 << "Invalid property value for BootSourceOverrideTarget: " 1657 << *bootSource; 1658 messages::propertyValueNotInList(aResp->res, *bootSource, 1659 "BootSourceTargetOverride"); 1660 return; 1661 } 1662 1663 // Act on validated parameters 1664 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1665 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1666 1667 crow::connections::systemBus->async_method_call( 1668 [aResp](const boost::system::error_code ec) { 1669 if (ec) 1670 { 1671 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1672 messages::internalError(aResp->res); 1673 return; 1674 } 1675 BMCWEB_LOG_DEBUG << "Boot source update done."; 1676 }, 1677 "xyz.openbmc_project.Settings", 1678 "/xyz/openbmc_project/control/host0/boot", 1679 "org.freedesktop.DBus.Properties", "Set", 1680 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1681 std::variant<std::string>(bootSourceStr)); 1682 1683 crow::connections::systemBus->async_method_call( 1684 [aResp](const boost::system::error_code ec) { 1685 if (ec) 1686 { 1687 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1688 messages::internalError(aResp->res); 1689 return; 1690 } 1691 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1692 }, 1693 "xyz.openbmc_project.Settings", 1694 "/xyz/openbmc_project/control/host0/boot", 1695 "org.freedesktop.DBus.Properties", "Set", 1696 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1697 std::variant<std::string>(bootModeStr)); 1698 } 1699 1700 /** 1701 * @brief Sets Boot source override properties. 1702 * 1703 * @param[in] aResp Shared pointer for generating response message. 1704 * @param[in] bootSource The boot source from incoming RF request. 1705 * @param[in] bootType The boot type from incoming RF request. 1706 * @param[in] bootEnable The boot override enable from incoming RF request. 1707 * 1708 * @return Integer error code. 1709 */ 1710 1711 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1712 const std::optional<std::string>& bootSource, 1713 const std::optional<std::string>& bootType, 1714 const std::optional<std::string>& bootEnable) 1715 { 1716 BMCWEB_LOG_DEBUG << "Set boot information."; 1717 1718 setBootModeOrSource(aResp, bootSource); 1719 setBootType(aResp, bootType); 1720 setBootEnable(aResp, bootEnable); 1721 } 1722 1723 /** 1724 * @brief Sets AssetTag 1725 * 1726 * @param[in] aResp Shared pointer for generating response message. 1727 * @param[in] assetTag "AssetTag" from request. 1728 * 1729 * @return None. 1730 */ 1731 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1732 const std::string& assetTag) 1733 { 1734 crow::connections::systemBus->async_method_call( 1735 [aResp, assetTag]( 1736 const boost::system::error_code ec, 1737 const std::vector<std::pair< 1738 std::string, 1739 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1740 subtree) { 1741 if (ec) 1742 { 1743 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1744 messages::internalError(aResp->res); 1745 return; 1746 } 1747 if (subtree.size() == 0) 1748 { 1749 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1750 messages::internalError(aResp->res); 1751 return; 1752 } 1753 // Assume only 1 system D-Bus object 1754 // Throw an error if there is more than 1 1755 if (subtree.size() > 1) 1756 { 1757 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1758 messages::internalError(aResp->res); 1759 return; 1760 } 1761 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1762 { 1763 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1764 messages::internalError(aResp->res); 1765 return; 1766 } 1767 1768 const std::string& path = subtree[0].first; 1769 const std::string& service = subtree[0].second.begin()->first; 1770 1771 if (service.empty()) 1772 { 1773 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1774 messages::internalError(aResp->res); 1775 return; 1776 } 1777 1778 crow::connections::systemBus->async_method_call( 1779 [aResp](const boost::system::error_code ec2) { 1780 if (ec2) 1781 { 1782 BMCWEB_LOG_DEBUG 1783 << "D-Bus response error on AssetTag Set " << ec2; 1784 messages::internalError(aResp->res); 1785 return; 1786 } 1787 }, 1788 service, path, "org.freedesktop.DBus.Properties", "Set", 1789 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1790 std::variant<std::string>(assetTag)); 1791 }, 1792 "xyz.openbmc_project.ObjectMapper", 1793 "/xyz/openbmc_project/object_mapper", 1794 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1795 "/xyz/openbmc_project/inventory", int32_t(0), 1796 std::array<const char*, 1>{ 1797 "xyz.openbmc_project.Inventory.Item.System"}); 1798 } 1799 1800 /** 1801 * @brief Sets automaticRetry (Auto Reboot) 1802 * 1803 * @param[in] aResp Shared pointer for generating response message. 1804 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1805 * 1806 * @return None. 1807 */ 1808 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1809 const std::string& automaticRetryConfig) 1810 { 1811 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1812 1813 // OpenBMC only supports "Disabled" and "RetryAttempts". 1814 bool autoRebootEnabled; 1815 1816 if (automaticRetryConfig == "Disabled") 1817 { 1818 autoRebootEnabled = false; 1819 } 1820 else if (automaticRetryConfig == "RetryAttempts") 1821 { 1822 autoRebootEnabled = true; 1823 } 1824 else 1825 { 1826 BMCWEB_LOG_DEBUG << "Invalid property value for " 1827 "AutomaticRetryConfig: " 1828 << automaticRetryConfig; 1829 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1830 "AutomaticRetryConfig"); 1831 return; 1832 } 1833 1834 crow::connections::systemBus->async_method_call( 1835 [aResp](const boost::system::error_code ec) { 1836 if (ec) 1837 { 1838 messages::internalError(aResp->res); 1839 return; 1840 } 1841 }, 1842 "xyz.openbmc_project.Settings", 1843 "/xyz/openbmc_project/control/host0/auto_reboot", 1844 "org.freedesktop.DBus.Properties", "Set", 1845 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1846 std::variant<bool>(autoRebootEnabled)); 1847 } 1848 1849 /** 1850 * @brief Sets power restore policy properties. 1851 * 1852 * @param[in] aResp Shared pointer for generating response message. 1853 * @param[in] policy power restore policy properties from request. 1854 * 1855 * @return None. 1856 */ 1857 inline void 1858 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1859 const std::string& policy) 1860 { 1861 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1862 1863 const boost::container::flat_map<std::string, std::string> policyMaps = { 1864 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1865 "AlwaysOn"}, 1866 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1867 "AlwaysOff"}, 1868 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1869 "Restore"}}; 1870 1871 std::string powerRestorPolicy; 1872 1873 auto policyMapsIt = policyMaps.find(policy); 1874 if (policyMapsIt == policyMaps.end()) 1875 { 1876 messages::propertyValueNotInList(aResp->res, policy, 1877 "PowerRestorePolicy"); 1878 return; 1879 } 1880 1881 powerRestorPolicy = policyMapsIt->second; 1882 1883 crow::connections::systemBus->async_method_call( 1884 [aResp](const boost::system::error_code ec) { 1885 if (ec) 1886 { 1887 messages::internalError(aResp->res); 1888 return; 1889 } 1890 }, 1891 "xyz.openbmc_project.Settings", 1892 "/xyz/openbmc_project/control/host0/power_restore_policy", 1893 "org.freedesktop.DBus.Properties", "Set", 1894 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1895 std::variant<std::string>(powerRestorPolicy)); 1896 } 1897 1898 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1899 /** 1900 * @brief Retrieves provisioning status 1901 * 1902 * @param[in] aResp Shared pointer for completing asynchronous calls. 1903 * 1904 * @return None. 1905 */ 1906 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1907 { 1908 BMCWEB_LOG_DEBUG << "Get OEM information."; 1909 crow::connections::systemBus->async_method_call( 1910 [aResp](const boost::system::error_code ec, 1911 const std::vector<std::pair<std::string, VariantType>>& 1912 propertiesList) { 1913 nlohmann::json& oemPFR = 1914 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1915 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1916 "#OemComputerSystem.OpenBmc"; 1917 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1918 1919 if (ec) 1920 { 1921 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1922 // not an error, don't have to have the interface 1923 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1924 return; 1925 } 1926 1927 const bool* provState = nullptr; 1928 const bool* lockState = nullptr; 1929 for (const std::pair<std::string, VariantType>& property : 1930 propertiesList) 1931 { 1932 if (property.first == "UfmProvisioned") 1933 { 1934 provState = std::get_if<bool>(&property.second); 1935 } 1936 else if (property.first == "UfmLocked") 1937 { 1938 lockState = std::get_if<bool>(&property.second); 1939 } 1940 } 1941 1942 if ((provState == nullptr) || (lockState == nullptr)) 1943 { 1944 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1945 messages::internalError(aResp->res); 1946 return; 1947 } 1948 1949 if (*provState == true) 1950 { 1951 if (*lockState == true) 1952 { 1953 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1954 } 1955 else 1956 { 1957 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1958 } 1959 } 1960 else 1961 { 1962 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1963 } 1964 }, 1965 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1966 "org.freedesktop.DBus.Properties", "GetAll", 1967 "xyz.openbmc_project.PFR.Attributes"); 1968 } 1969 #endif 1970 1971 /** 1972 * @brief Translate the PowerMode to a response message. 1973 * 1974 * @param[in] aResp Shared pointer for generating response message. 1975 * @param[in] modeValue PowerMode value to be translated 1976 * 1977 * @return None. 1978 */ 1979 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1980 const std::string& modeValue) 1981 { 1982 std::string modeString; 1983 1984 if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1985 "PowerMode.Static") 1986 { 1987 aResp->res.jsonValue["PowerMode"] = "Static"; 1988 } 1989 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1990 "PowerMode.MaximumPerformance") 1991 { 1992 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1993 } 1994 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1995 "PowerMode.PowerSaving") 1996 { 1997 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1998 } 1999 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 2000 "PowerMode.OEM") 2001 { 2002 aResp->res.jsonValue["PowerMode"] = "OEM"; 2003 } 2004 else 2005 { 2006 // Any other values would be invalid 2007 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 2008 messages::internalError(aResp->res); 2009 } 2010 } 2011 2012 /** 2013 * @brief Retrieves system power mode 2014 * 2015 * @param[in] aResp Shared pointer for generating response message. 2016 * 2017 * @return None. 2018 */ 2019 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2020 { 2021 BMCWEB_LOG_DEBUG << "Get power mode."; 2022 2023 // Get Power Mode object path: 2024 crow::connections::systemBus->async_method_call( 2025 [aResp]( 2026 const boost::system::error_code ec, 2027 const std::vector<std::pair< 2028 std::string, 2029 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2030 subtree) { 2031 if (ec) 2032 { 2033 BMCWEB_LOG_DEBUG 2034 << "DBUS response error on Power.Mode GetSubTree " << ec; 2035 // This is an optional D-Bus object so just return if 2036 // error occurs 2037 return; 2038 } 2039 if (subtree.empty()) 2040 { 2041 // As noted above, this is an optional interface so just return 2042 // if there is no instance found 2043 return; 2044 } 2045 if (subtree.size() > 1) 2046 { 2047 // More then one PowerMode object is not supported and is an 2048 // error 2049 BMCWEB_LOG_DEBUG 2050 << "Found more than 1 system D-Bus Power.Mode objects: " 2051 << subtree.size(); 2052 messages::internalError(aResp->res); 2053 return; 2054 } 2055 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2056 { 2057 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2058 messages::internalError(aResp->res); 2059 return; 2060 } 2061 const std::string& path = subtree[0].first; 2062 const std::string& service = subtree[0].second.begin()->first; 2063 if (service.empty()) 2064 { 2065 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2066 messages::internalError(aResp->res); 2067 return; 2068 } 2069 // Valid Power Mode object found, now read the current value 2070 crow::connections::systemBus->async_method_call( 2071 [aResp](const boost::system::error_code ec, 2072 const std::variant<std::string>& pmode) { 2073 if (ec) 2074 { 2075 BMCWEB_LOG_DEBUG 2076 << "DBUS response error on PowerMode Get: " << ec; 2077 messages::internalError(aResp->res); 2078 return; 2079 } 2080 2081 const std::string* s = std::get_if<std::string>(&pmode); 2082 if (s == nullptr) 2083 { 2084 BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; 2085 messages::internalError(aResp->res); 2086 return; 2087 } 2088 2089 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2090 {"Static", "MaximumPerformance", "PowerSaving"}; 2091 2092 BMCWEB_LOG_DEBUG << "Current power mode: " << *s; 2093 translatePowerMode(aResp, *s); 2094 }, 2095 service, path, "org.freedesktop.DBus.Properties", "Get", 2096 "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); 2097 }, 2098 "xyz.openbmc_project.ObjectMapper", 2099 "/xyz/openbmc_project/object_mapper", 2100 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2101 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2102 } 2103 2104 /** 2105 * @brief Validate the specified mode is valid and return the PowerMode 2106 * name associated with that string 2107 * 2108 * @param[in] aResp Shared pointer for generating response message. 2109 * @param[in] modeString String representing the desired PowerMode 2110 * 2111 * @return PowerMode value or empty string if mode is not valid 2112 */ 2113 inline std::string 2114 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2115 const std::string& modeString) 2116 { 2117 std::string mode; 2118 2119 if (modeString == "Static") 2120 { 2121 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2122 } 2123 else if (modeString == "MaximumPerformance") 2124 { 2125 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode." 2126 "MaximumPerformance"; 2127 } 2128 else if (modeString == "PowerSaving") 2129 { 2130 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2131 } 2132 else 2133 { 2134 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2135 } 2136 return mode; 2137 } 2138 2139 /** 2140 * @brief Sets system power mode. 2141 * 2142 * @param[in] aResp Shared pointer for generating response message. 2143 * @param[in] pmode System power mode from request. 2144 * 2145 * @return None. 2146 */ 2147 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2148 const std::string& pmode) 2149 { 2150 BMCWEB_LOG_DEBUG << "Set power mode."; 2151 2152 std::string powerMode = validatePowerMode(aResp, pmode); 2153 if (powerMode.empty()) 2154 { 2155 return; 2156 } 2157 2158 // Get Power Mode object path: 2159 crow::connections::systemBus->async_method_call( 2160 [aResp, powerMode]( 2161 const boost::system::error_code ec, 2162 const std::vector<std::pair< 2163 std::string, 2164 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2165 subtree) { 2166 if (ec) 2167 { 2168 BMCWEB_LOG_DEBUG 2169 << "DBUS response error on Power.Mode GetSubTree " << ec; 2170 // This is an optional D-Bus object, but user attempted to patch 2171 messages::internalError(aResp->res); 2172 return; 2173 } 2174 if (subtree.empty()) 2175 { 2176 // This is an optional D-Bus object, but user attempted to patch 2177 messages::resourceNotFound(aResp->res, "ComputerSystem", 2178 "PowerMode"); 2179 return; 2180 } 2181 if (subtree.size() > 1) 2182 { 2183 // More then one PowerMode object is not supported and is an 2184 // error 2185 BMCWEB_LOG_DEBUG 2186 << "Found more than 1 system D-Bus Power.Mode objects: " 2187 << subtree.size(); 2188 messages::internalError(aResp->res); 2189 return; 2190 } 2191 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2192 { 2193 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2194 messages::internalError(aResp->res); 2195 return; 2196 } 2197 const std::string& path = subtree[0].first; 2198 const std::string& service = subtree[0].second.begin()->first; 2199 if (service.empty()) 2200 { 2201 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2202 messages::internalError(aResp->res); 2203 return; 2204 } 2205 2206 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2207 << path; 2208 2209 // Set the Power Mode property 2210 crow::connections::systemBus->async_method_call( 2211 [aResp](const boost::system::error_code ec) { 2212 if (ec) 2213 { 2214 messages::internalError(aResp->res); 2215 return; 2216 } 2217 }, 2218 service, path, "org.freedesktop.DBus.Properties", "Set", 2219 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2220 std::variant<std::string>(powerMode)); 2221 }, 2222 "xyz.openbmc_project.ObjectMapper", 2223 "/xyz/openbmc_project/object_mapper", 2224 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2225 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2226 } 2227 2228 /** 2229 * @brief Translates watchdog timeout action DBUS property value to redfish. 2230 * 2231 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2232 * 2233 * @return Returns as a string, the timeout action in Redfish terms. If 2234 * translation cannot be done, returns an empty string. 2235 */ 2236 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2237 { 2238 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2239 { 2240 return "None"; 2241 } 2242 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2243 { 2244 return "ResetSystem"; 2245 } 2246 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2247 { 2248 return "PowerDown"; 2249 } 2250 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2251 { 2252 return "PowerCycle"; 2253 } 2254 2255 return ""; 2256 } 2257 2258 /** 2259 *@brief Translates timeout action from Redfish to DBUS property value. 2260 * 2261 *@param[in] rfAction The timeout action in Redfish. 2262 * 2263 *@return Returns as a string, the time_out action as expected by DBUS. 2264 *If translation cannot be done, returns an empty string. 2265 */ 2266 2267 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2268 { 2269 if (rfAction == "None") 2270 { 2271 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2272 } 2273 if (rfAction == "PowerCycle") 2274 { 2275 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2276 } 2277 if (rfAction == "PowerDown") 2278 { 2279 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2280 } 2281 if (rfAction == "ResetSystem") 2282 { 2283 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2284 } 2285 2286 return ""; 2287 } 2288 2289 /** 2290 * @brief Retrieves host watchdog timer properties over DBUS 2291 * 2292 * @param[in] aResp Shared pointer for completing asynchronous calls. 2293 * 2294 * @return None. 2295 */ 2296 inline void 2297 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2298 { 2299 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2300 crow::connections::systemBus->async_method_call( 2301 [aResp](const boost::system::error_code ec, 2302 PropertiesType& properties) { 2303 if (ec) 2304 { 2305 // watchdog service is stopped 2306 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2307 return; 2308 } 2309 2310 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2311 2312 nlohmann::json& hostWatchdogTimer = 2313 aResp->res.jsonValue["HostWatchdogTimer"]; 2314 2315 // watchdog service is running/enabled 2316 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2317 2318 for (const auto& property : properties) 2319 { 2320 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2321 if (property.first == "Enabled") 2322 { 2323 const bool* state = std::get_if<bool>(&property.second); 2324 2325 if (!state) 2326 { 2327 messages::internalError(aResp->res); 2328 return; 2329 } 2330 2331 hostWatchdogTimer["FunctionEnabled"] = *state; 2332 } 2333 else if (property.first == "ExpireAction") 2334 { 2335 const std::string* s = 2336 std::get_if<std::string>(&property.second); 2337 if (!s) 2338 { 2339 messages::internalError(aResp->res); 2340 return; 2341 } 2342 2343 std::string action = dbusToRfWatchdogAction(*s); 2344 if (action.empty()) 2345 { 2346 messages::internalError(aResp->res); 2347 return; 2348 } 2349 hostWatchdogTimer["TimeoutAction"] = action; 2350 } 2351 } 2352 }, 2353 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2354 "org.freedesktop.DBus.Properties", "GetAll", 2355 "xyz.openbmc_project.State.Watchdog"); 2356 } 2357 2358 /** 2359 * @brief Sets Host WatchDog Timer properties. 2360 * 2361 * @param[in] aResp Shared pointer for generating response message. 2362 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2363 * RF request. 2364 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2365 * 2366 * @return None. 2367 */ 2368 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2369 const std::optional<bool> wdtEnable, 2370 const std::optional<std::string>& wdtTimeOutAction) 2371 { 2372 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2373 2374 if (wdtTimeOutAction) 2375 { 2376 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2377 // check if TimeOut Action is Valid 2378 if (wdtTimeOutActStr.empty()) 2379 { 2380 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2381 << *wdtTimeOutAction; 2382 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2383 "TimeoutAction"); 2384 return; 2385 } 2386 2387 crow::connections::systemBus->async_method_call( 2388 [aResp](const boost::system::error_code ec) { 2389 if (ec) 2390 { 2391 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2392 messages::internalError(aResp->res); 2393 return; 2394 } 2395 }, 2396 "xyz.openbmc_project.Watchdog", 2397 "/xyz/openbmc_project/watchdog/host0", 2398 "org.freedesktop.DBus.Properties", "Set", 2399 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2400 std::variant<std::string>(wdtTimeOutActStr)); 2401 } 2402 2403 if (wdtEnable) 2404 { 2405 crow::connections::systemBus->async_method_call( 2406 [aResp](const boost::system::error_code ec) { 2407 if (ec) 2408 { 2409 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2410 messages::internalError(aResp->res); 2411 return; 2412 } 2413 }, 2414 "xyz.openbmc_project.Watchdog", 2415 "/xyz/openbmc_project/watchdog/host0", 2416 "org.freedesktop.DBus.Properties", "Set", 2417 "xyz.openbmc_project.State.Watchdog", "Enabled", 2418 std::variant<bool>(*wdtEnable)); 2419 } 2420 } 2421 2422 /** 2423 * SystemsCollection derived class for delivering ComputerSystems Collection 2424 * Schema 2425 */ 2426 inline void requestRoutesSystemsCollection(App& app) 2427 { 2428 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2429 .privileges(redfish::privileges::getComputerSystemCollection) 2430 .methods(boost::beast::http::verb::get)( 2431 [](const crow::Request& /*req*/, 2432 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2433 asyncResp->res.jsonValue["@odata.type"] = 2434 "#ComputerSystemCollection.ComputerSystemCollection"; 2435 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2436 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2437 2438 crow::connections::systemBus->async_method_call( 2439 [asyncResp](const boost::system::error_code ec, 2440 const std::variant<std::string>& /*hostName*/) { 2441 nlohmann::json& ifaceArray = 2442 asyncResp->res.jsonValue["Members"]; 2443 ifaceArray = nlohmann::json::array(); 2444 auto& count = 2445 asyncResp->res.jsonValue["Members@odata.count"]; 2446 ifaceArray.push_back( 2447 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2448 count = ifaceArray.size(); 2449 if (!ec) 2450 { 2451 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2452 ifaceArray.push_back( 2453 {{"@odata.id", 2454 "/redfish/v1/Systems/hypervisor"}}); 2455 count = ifaceArray.size(); 2456 } 2457 }, 2458 "xyz.openbmc_project.Settings", 2459 "/xyz/openbmc_project/network/hypervisor", 2460 "org.freedesktop.DBus.Properties", "Get", 2461 "xyz.openbmc_project.Network.SystemConfiguration", 2462 "HostName"); 2463 }); 2464 } 2465 2466 /** 2467 * Function transceives data with dbus directly. 2468 */ 2469 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2470 { 2471 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2472 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2473 constexpr char const* interfaceName = 2474 "xyz.openbmc_project.Control.Host.NMI"; 2475 constexpr char const* method = "NMI"; 2476 2477 crow::connections::systemBus->async_method_call( 2478 [asyncResp](const boost::system::error_code ec) { 2479 if (ec) 2480 { 2481 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2482 messages::internalError(asyncResp->res); 2483 return; 2484 } 2485 messages::success(asyncResp->res); 2486 }, 2487 serviceName, objectPath, interfaceName, method); 2488 } 2489 2490 /** 2491 * SystemActionsReset class supports handle POST method for Reset action. 2492 * The class retrieves and sends data directly to D-Bus. 2493 */ 2494 inline void requestRoutesSystemActionsReset(App& app) 2495 { 2496 /** 2497 * Function handles POST method request. 2498 * Analyzes POST body message before sends Reset request data to D-Bus. 2499 */ 2500 BMCWEB_ROUTE(app, 2501 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2502 .privileges(redfish::privileges::postComputerSystem) 2503 .methods( 2504 boost::beast::http::verb:: 2505 post)([](const crow::Request& req, 2506 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2507 std::string resetType; 2508 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2509 resetType)) 2510 { 2511 return; 2512 } 2513 2514 // Get the command and host vs. chassis 2515 std::string command; 2516 bool hostCommand; 2517 if ((resetType == "On") || (resetType == "ForceOn")) 2518 { 2519 command = "xyz.openbmc_project.State.Host.Transition.On"; 2520 hostCommand = true; 2521 } 2522 else if (resetType == "ForceOff") 2523 { 2524 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2525 hostCommand = false; 2526 } 2527 else if (resetType == "ForceRestart") 2528 { 2529 command = 2530 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2531 hostCommand = true; 2532 } 2533 else if (resetType == "GracefulShutdown") 2534 { 2535 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2536 hostCommand = true; 2537 } 2538 else if (resetType == "GracefulRestart") 2539 { 2540 command = "xyz.openbmc_project.State.Host.Transition." 2541 "GracefulWarmReboot"; 2542 hostCommand = true; 2543 } 2544 else if (resetType == "PowerCycle") 2545 { 2546 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2547 hostCommand = true; 2548 } 2549 else if (resetType == "Nmi") 2550 { 2551 doNMI(asyncResp); 2552 return; 2553 } 2554 else 2555 { 2556 messages::actionParameterUnknown(asyncResp->res, "Reset", 2557 resetType); 2558 return; 2559 } 2560 2561 if (hostCommand) 2562 { 2563 crow::connections::systemBus->async_method_call( 2564 [asyncResp, resetType](const boost::system::error_code ec) { 2565 if (ec) 2566 { 2567 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2568 if (ec.value() == 2569 boost::asio::error::invalid_argument) 2570 { 2571 messages::actionParameterNotSupported( 2572 asyncResp->res, resetType, "Reset"); 2573 } 2574 else 2575 { 2576 messages::internalError(asyncResp->res); 2577 } 2578 return; 2579 } 2580 messages::success(asyncResp->res); 2581 }, 2582 "xyz.openbmc_project.State.Host", 2583 "/xyz/openbmc_project/state/host0", 2584 "org.freedesktop.DBus.Properties", "Set", 2585 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2586 std::variant<std::string>{command}); 2587 } 2588 else 2589 { 2590 crow::connections::systemBus->async_method_call( 2591 [asyncResp, resetType](const boost::system::error_code ec) { 2592 if (ec) 2593 { 2594 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2595 if (ec.value() == 2596 boost::asio::error::invalid_argument) 2597 { 2598 messages::actionParameterNotSupported( 2599 asyncResp->res, resetType, "Reset"); 2600 } 2601 else 2602 { 2603 messages::internalError(asyncResp->res); 2604 } 2605 return; 2606 } 2607 messages::success(asyncResp->res); 2608 }, 2609 "xyz.openbmc_project.State.Chassis", 2610 "/xyz/openbmc_project/state/chassis0", 2611 "org.freedesktop.DBus.Properties", "Set", 2612 "xyz.openbmc_project.State.Chassis", 2613 "RequestedPowerTransition", 2614 std::variant<std::string>{command}); 2615 } 2616 }); 2617 } 2618 2619 /** 2620 * Systems derived class for delivering Computer Systems Schema. 2621 */ 2622 inline void requestRoutesSystems(App& app) 2623 { 2624 2625 /** 2626 * Functions triggers appropriate requests on DBus 2627 */ 2628 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2629 .privileges(redfish::privileges::getComputerSystem) 2630 .methods( 2631 boost::beast::http::verb:: 2632 get)([](const crow::Request&, 2633 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2634 asyncResp->res.jsonValue["@odata.type"] = 2635 "#ComputerSystem.v1_15_0.ComputerSystem"; 2636 asyncResp->res.jsonValue["Name"] = "system"; 2637 asyncResp->res.jsonValue["Id"] = "system"; 2638 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2639 asyncResp->res.jsonValue["Description"] = "Computer System"; 2640 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2641 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2642 "Disabled"; 2643 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2644 uint64_t(0); 2645 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2646 "Disabled"; 2647 asyncResp->res.jsonValue["@odata.id"] = 2648 "/redfish/v1/Systems/system"; 2649 2650 asyncResp->res.jsonValue["Processors"] = { 2651 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2652 asyncResp->res.jsonValue["Memory"] = { 2653 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2654 asyncResp->res.jsonValue["Storage"] = { 2655 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2656 2657 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2658 {"target", 2659 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2660 {"@Redfish.ActionInfo", 2661 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2662 2663 asyncResp->res.jsonValue["LogServices"] = { 2664 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2665 2666 asyncResp->res.jsonValue["Bios"] = { 2667 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2668 2669 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2670 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2671 2672 asyncResp->res.jsonValue["Status"] = { 2673 {"Health", "OK"}, 2674 {"State", "Enabled"}, 2675 }; 2676 2677 // Fill in SerialConsole info 2678 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2679 15; 2680 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2681 {"ServiceEnabled", true}, 2682 }; 2683 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2684 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2685 {"ServiceEnabled", true}, 2686 {"Port", 2200}, 2687 // https://github.com/openbmc/docs/blob/master/console.md 2688 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2689 }; 2690 2691 #ifdef BMCWEB_ENABLE_KVM 2692 // Fill in GraphicalConsole info 2693 asyncResp->res.jsonValue["GraphicalConsole"] = { 2694 {"ServiceEnabled", true}, 2695 {"MaxConcurrentSessions", 4}, 2696 {"ConnectTypesSupported", {"KVMIP"}}, 2697 }; 2698 #endif // BMCWEB_ENABLE_KVM 2699 constexpr const std::array<const char*, 4> inventoryForSystems = { 2700 "xyz.openbmc_project.Inventory.Item.Dimm", 2701 "xyz.openbmc_project.Inventory.Item.Cpu", 2702 "xyz.openbmc_project.Inventory.Item.Drive", 2703 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2704 2705 auto health = std::make_shared<HealthPopulate>(asyncResp); 2706 crow::connections::systemBus->async_method_call( 2707 [health](const boost::system::error_code ec, 2708 std::vector<std::string>& resp) { 2709 if (ec) 2710 { 2711 // no inventory 2712 return; 2713 } 2714 2715 health->inventory = std::move(resp); 2716 }, 2717 "xyz.openbmc_project.ObjectMapper", 2718 "/xyz/openbmc_project/object_mapper", 2719 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2720 int32_t(0), inventoryForSystems); 2721 2722 health->populate(); 2723 2724 getMainChassisId( 2725 asyncResp, [](const std::string& chassisId, 2726 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2727 aRsp->res.jsonValue["Links"]["Chassis"] = { 2728 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2729 }); 2730 2731 getLocationIndicatorActive(asyncResp); 2732 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2733 getIndicatorLedState(asyncResp); 2734 getComputerSystem(asyncResp, health); 2735 getHostState(asyncResp); 2736 getBootProperties(asyncResp); 2737 getBootProgress(asyncResp); 2738 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2739 getHostWatchdogTimer(asyncResp); 2740 getPowerRestorePolicy(asyncResp); 2741 getAutomaticRetry(asyncResp); 2742 getLastResetTime(asyncResp); 2743 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2744 getProvisioningStatus(asyncResp); 2745 #endif 2746 getTrustedModuleRequiredToBoot(asyncResp); 2747 getPowerMode(asyncResp); 2748 }); 2749 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2750 .privileges(redfish::privileges::patchComputerSystem) 2751 .methods(boost::beast::http::verb::patch)( 2752 [](const crow::Request& req, 2753 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2754 std::optional<bool> locationIndicatorActive; 2755 std::optional<std::string> indicatorLed; 2756 std::optional<nlohmann::json> bootProps; 2757 std::optional<nlohmann::json> wdtTimerProps; 2758 std::optional<std::string> assetTag; 2759 std::optional<std::string> powerRestorePolicy; 2760 std::optional<std::string> powerMode; 2761 2762 if (!json_util::readJson( 2763 req, asyncResp->res, "IndicatorLED", indicatorLed, 2764 "LocationIndicatorActive", locationIndicatorActive, 2765 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2766 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2767 assetTag, "PowerMode", powerMode)) 2768 { 2769 return; 2770 } 2771 2772 asyncResp->res.result(boost::beast::http::status::no_content); 2773 2774 if (assetTag) 2775 { 2776 setAssetTag(asyncResp, *assetTag); 2777 } 2778 2779 if (wdtTimerProps) 2780 { 2781 std::optional<bool> wdtEnable; 2782 std::optional<std::string> wdtTimeOutAction; 2783 2784 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2785 "FunctionEnabled", wdtEnable, 2786 "TimeoutAction", wdtTimeOutAction)) 2787 { 2788 return; 2789 } 2790 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2791 } 2792 2793 if (bootProps) 2794 { 2795 std::optional<std::string> bootSource; 2796 std::optional<std::string> bootType; 2797 std::optional<std::string> bootEnable; 2798 std::optional<std::string> automaticRetryConfig; 2799 2800 if (!json_util::readJson( 2801 *bootProps, asyncResp->res, 2802 "BootSourceOverrideTarget", bootSource, 2803 "BootSourceOverrideMode", bootType, 2804 "BootSourceOverrideEnabled", bootEnable, 2805 "AutomaticRetryConfig", automaticRetryConfig)) 2806 { 2807 return; 2808 } 2809 2810 if (bootSource || bootType || bootEnable) 2811 { 2812 setBootProperties(asyncResp, bootSource, bootType, 2813 bootEnable); 2814 } 2815 if (automaticRetryConfig) 2816 { 2817 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2818 } 2819 } 2820 2821 if (locationIndicatorActive) 2822 { 2823 setLocationIndicatorActive(asyncResp, 2824 *locationIndicatorActive); 2825 } 2826 2827 // TODO (Gunnar): Remove IndicatorLED after enough time has 2828 // passed 2829 if (indicatorLed) 2830 { 2831 setIndicatorLedState(asyncResp, *indicatorLed); 2832 asyncResp->res.addHeader( 2833 boost::beast::http::field::warning, 2834 "299 - \"IndicatorLED is deprecated. Use " 2835 "LocationIndicatorActive instead.\""); 2836 } 2837 2838 if (powerRestorePolicy) 2839 { 2840 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2841 } 2842 2843 if (powerMode) 2844 { 2845 setPowerMode(asyncResp, *powerMode); 2846 } 2847 }); 2848 } 2849 2850 /** 2851 * SystemResetActionInfo derived class for delivering Computer Systems 2852 * ResetType AllowableValues using ResetInfo schema. 2853 */ 2854 inline void requestRoutesSystemResetActionInfo(App& app) 2855 { 2856 2857 /** 2858 * Functions triggers appropriate requests on DBus 2859 */ 2860 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2861 .privileges(redfish::privileges::getActionInfo) 2862 .methods(boost::beast::http::verb::get)( 2863 [](const crow::Request&, 2864 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2865 asyncResp->res.jsonValue = { 2866 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2867 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2868 {"Name", "Reset Action Info"}, 2869 {"Id", "ResetActionInfo"}, 2870 {"Parameters", 2871 {{{"Name", "ResetType"}, 2872 {"Required", true}, 2873 {"DataType", "String"}, 2874 {"AllowableValues", 2875 {"On", "ForceOff", "ForceOn", "ForceRestart", 2876 "GracefulRestart", "GracefulShutdown", "PowerCycle", 2877 "Nmi"}}}}}}; 2878 }); 2879 } 2880 } // namespace redfish 2881