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 // The caller has initialized the bootSource and bootMode to: 773 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 774 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 775 // Only modify the bootSource/bootMode variable needed to achieve the 776 // desired boot action. 777 778 if (rfSource == "None") 779 { 780 return 0; 781 } 782 if (rfSource == "Pxe") 783 { 784 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 785 } 786 else if (rfSource == "Hdd") 787 { 788 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 789 } 790 else if (rfSource == "Diags") 791 { 792 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 793 } 794 else if (rfSource == "Cd") 795 { 796 bootSource = 797 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 798 } 799 else if (rfSource == "BiosSetup") 800 { 801 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 802 } 803 else if (rfSource == "Usb") 804 { 805 bootSource = 806 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 807 } 808 else 809 { 810 BMCWEB_LOG_DEBUG << "Invalid property value for " 811 "BootSourceOverrideTarget: " 812 << bootSource; 813 messages::propertyValueNotInList(aResp->res, rfSource, 814 "BootSourceTargetOverride"); 815 return -1; 816 } 817 return 0; 818 } 819 820 /** 821 * @brief Retrieves boot progress of the system 822 * 823 * @param[in] aResp Shared pointer for generating response message. 824 * 825 * @return None. 826 */ 827 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 828 { 829 crow::connections::systemBus->async_method_call( 830 [aResp](const boost::system::error_code ec, 831 const std::variant<std::string>& bootProgress) { 832 if (ec) 833 { 834 // BootProgress is an optional object so just do nothing if 835 // not found 836 return; 837 } 838 839 const std::string* bootProgressStr = 840 std::get_if<std::string>(&bootProgress); 841 842 if (!bootProgressStr) 843 { 844 // Interface implemented but property not found, return error 845 // for that 846 messages::internalError(aResp->res); 847 return; 848 } 849 850 BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr; 851 852 // Now convert the D-Bus BootProgress to the appropriate Redfish 853 // enum 854 std::string rfBpLastState = "None"; 855 if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress." 856 "ProgressStages.Unspecified") 857 { 858 rfBpLastState = "None"; 859 } 860 else if (*bootProgressStr == 861 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 862 "PrimaryProcInit") 863 { 864 rfBpLastState = "PrimaryProcessorInitializationStarted"; 865 } 866 else if (*bootProgressStr == 867 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 868 "BusInit") 869 { 870 rfBpLastState = "BusInitializationStarted"; 871 } 872 else if (*bootProgressStr == 873 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 874 "MemoryInit") 875 { 876 rfBpLastState = "MemoryInitializationStarted"; 877 } 878 else if (*bootProgressStr == 879 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 880 "SecondaryProcInit") 881 { 882 rfBpLastState = "SecondaryProcessorInitializationStarted"; 883 } 884 else if (*bootProgressStr == 885 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 886 "PCIInit") 887 { 888 rfBpLastState = "PCIResourceConfigStarted"; 889 } 890 else if (*bootProgressStr == 891 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 892 "SystemInitComplete") 893 { 894 rfBpLastState = "SystemHardwareInitializationComplete"; 895 } 896 else if (*bootProgressStr == 897 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 898 "OSStart") 899 { 900 rfBpLastState = "OSBootStarted"; 901 } 902 else if (*bootProgressStr == 903 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 904 "OSRunning") 905 { 906 rfBpLastState = "OSRunning"; 907 } 908 else 909 { 910 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 911 << *bootProgressStr; 912 // Just return the default 913 } 914 915 aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState; 916 }, 917 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 918 "org.freedesktop.DBus.Properties", "Get", 919 "xyz.openbmc_project.State.Boot.Progress", "BootProgress"); 920 } 921 922 /** 923 * @brief Checks if the current boot override state can be considered as 924 * Disabled 925 * 926 * @param[in] aResp Shared pointer for generating response message. 927 * 928 * @return None. 929 */ 930 inline void 931 checkIfOverrideIsDisabled(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 932 { 933 // If the BootSourceOverrideTarget is still "None" at the end, 934 // reset the BootSourceOverrideEnabled to indicate that 935 // overrides are disabled 936 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == "None") 937 { 938 // If the BootSourceOverrideMode is supported we should 939 // check if it is still "UEFI" too 940 if (aResp->res.jsonValue["Boot"].contains("BootSourceOverrideMode")) 941 { 942 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] != 943 "UEFI") 944 { 945 return; 946 } 947 } 948 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled"; 949 } 950 } 951 952 /** 953 * @brief Retrieves boot type over DBUS and fills out the response 954 * 955 * @param[in] aResp Shared pointer for generating response message. 956 * @param[in] bootDbusObj The dbus object to query for boot properties. 957 * 958 * @return None. 959 */ 960 inline void getBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 961 const std::string& bootDbusObj) 962 { 963 crow::connections::systemBus->async_method_call( 964 [aResp](const boost::system::error_code ec, 965 const std::variant<std::string>& bootType) { 966 if (ec) 967 { 968 // not an error, don't have to have the interface 969 970 // Support Disabled override state in a way: 971 // "BootSourceOverrideEnabled=Disabled" = 972 // "BootSourceOverrideMode=UEFI" + 973 // "BootSourceOverrideTarget=None" 974 checkIfOverrideIsDisabled(aResp); 975 return; 976 } 977 978 const std::string* bootTypeStr = 979 std::get_if<std::string>(&bootType); 980 981 if (!bootTypeStr) 982 { 983 messages::internalError(aResp->res); 984 return; 985 } 986 987 BMCWEB_LOG_DEBUG << "Boot type: " << *bootTypeStr; 988 989 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode@Redfish." 990 "AllowableValues"] = {"Legacy", 991 "UEFI"}; 992 993 auto rfType = dbusToRfBootType(*bootTypeStr); 994 if (rfType.empty()) 995 { 996 messages::internalError(aResp->res); 997 return; 998 } 999 1000 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType; 1001 1002 // Support Disabled override state in a way: 1003 // "BootSourceOverrideEnabled=Disabled" = 1004 // "BootSourceOverrideMode=UEFI" + "BootSourceOverrideTarget=None" 1005 checkIfOverrideIsDisabled(aResp); 1006 }, 1007 "xyz.openbmc_project.Settings", bootDbusObj, 1008 "org.freedesktop.DBus.Properties", "Get", 1009 "xyz.openbmc_project.Control.Boot.Type", "BootType"); 1010 } 1011 1012 /** 1013 * @brief Retrieves boot mode over DBUS and fills out the response 1014 * 1015 * @param[in] aResp Shared pointer for generating response message. 1016 * @param[in] bootDbusObj The dbus object to query for boot properties. 1017 * 1018 * @return None. 1019 */ 1020 inline void getBootMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1021 const std::string& bootDbusObj) 1022 { 1023 crow::connections::systemBus->async_method_call( 1024 [aResp, bootDbusObj](const boost::system::error_code ec, 1025 const std::variant<std::string>& bootMode) { 1026 if (ec) 1027 { 1028 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1029 messages::internalError(aResp->res); 1030 return; 1031 } 1032 1033 const std::string* bootModeStr = 1034 std::get_if<std::string>(&bootMode); 1035 1036 if (!bootModeStr) 1037 { 1038 messages::internalError(aResp->res); 1039 return; 1040 } 1041 1042 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 1043 1044 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 1045 "AllowableValues"] = { 1046 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 1047 1048 if (*bootModeStr != 1049 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 1050 { 1051 auto rfMode = dbusToRfBootMode(*bootModeStr); 1052 if (!rfMode.empty()) 1053 { 1054 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1055 rfMode; 1056 } 1057 } 1058 1059 // Get BootType inside this async call as we need all of the 1060 // BootSource/BootMode/BootType to support 1061 // "BootSourceOverrideEnabled"="Disabled" state. 1062 getBootType(aResp, bootDbusObj); 1063 }, 1064 "xyz.openbmc_project.Settings", bootDbusObj, 1065 "org.freedesktop.DBus.Properties", "Get", 1066 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 1067 } 1068 1069 /** 1070 * @brief Retrieves boot source over DBUS 1071 * 1072 * @param[in] aResp Shared pointer for generating response message. 1073 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 1074 * 1075 * @return None. 1076 */ 1077 inline void getBootSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1078 bool oneTimeEnabled) 1079 { 1080 std::string bootDbusObj = 1081 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 1082 : "/xyz/openbmc_project/control/host0/boot"; 1083 1084 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 1085 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 1086 (oneTimeEnabled) ? "Once" : "Continuous"; 1087 1088 crow::connections::systemBus->async_method_call( 1089 [aResp, bootDbusObj](const boost::system::error_code ec, 1090 const std::variant<std::string>& bootSource) { 1091 if (ec) 1092 { 1093 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1094 messages::internalError(aResp->res); 1095 return; 1096 } 1097 1098 const std::string* bootSourceStr = 1099 std::get_if<std::string>(&bootSource); 1100 1101 if (!bootSourceStr) 1102 { 1103 messages::internalError(aResp->res); 1104 return; 1105 } 1106 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 1107 1108 auto rfSource = dbusToRfBootSource(*bootSourceStr); 1109 if (!rfSource.empty()) 1110 { 1111 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1112 rfSource; 1113 } 1114 1115 // Get BootMode as BootSourceOverrideTarget is constructed 1116 // from both BootSource and BootMode 1117 getBootMode(aResp, bootDbusObj); 1118 }, 1119 "xyz.openbmc_project.Settings", bootDbusObj, 1120 "org.freedesktop.DBus.Properties", "Get", 1121 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 1122 } 1123 1124 /** 1125 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1126 * get boot source and boot mode. 1127 * 1128 * @param[in] aResp Shared pointer for generating response message. 1129 * 1130 * @return None. 1131 */ 1132 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1133 { 1134 BMCWEB_LOG_DEBUG << "Get boot information."; 1135 1136 crow::connections::systemBus->async_method_call( 1137 [aResp](const boost::system::error_code ec, 1138 const std::variant<bool>& oneTime) { 1139 if (ec) 1140 { 1141 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1142 // not an error, don't have to have the interface 1143 return; 1144 } 1145 1146 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1147 1148 if (!oneTimePtr) 1149 { 1150 messages::internalError(aResp->res); 1151 return; 1152 } 1153 getBootSource(aResp, *oneTimePtr); 1154 }, 1155 "xyz.openbmc_project.Settings", 1156 "/xyz/openbmc_project/control/host0/boot/one_time", 1157 "org.freedesktop.DBus.Properties", "Get", 1158 "xyz.openbmc_project.Object.Enable", "Enabled"); 1159 } 1160 1161 /** 1162 * @brief Retrieves the Last Reset Time 1163 * 1164 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1165 * and power off. Even though this is the "system" Redfish object look at the 1166 * chassis D-Bus interface for the LastStateChangeTime since this has the 1167 * last power operation time. 1168 * 1169 * @param[in] aResp Shared pointer for generating response message. 1170 * 1171 * @return None. 1172 */ 1173 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1174 { 1175 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1176 1177 crow::connections::systemBus->async_method_call( 1178 [aResp](const boost::system::error_code ec, 1179 std::variant<uint64_t>& lastResetTime) { 1180 if (ec) 1181 { 1182 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1183 return; 1184 } 1185 1186 const uint64_t* lastResetTimePtr = 1187 std::get_if<uint64_t>(&lastResetTime); 1188 1189 if (!lastResetTimePtr) 1190 { 1191 messages::internalError(aResp->res); 1192 return; 1193 } 1194 // LastStateChangeTime is epoch time, in milliseconds 1195 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1196 time_t lastResetTimeStamp = 1197 static_cast<time_t>(*lastResetTimePtr / 1000); 1198 1199 // Convert to ISO 8601 standard 1200 aResp->res.jsonValue["LastResetTime"] = 1201 crow::utility::getDateTime(lastResetTimeStamp); 1202 }, 1203 "xyz.openbmc_project.State.Chassis", 1204 "/xyz/openbmc_project/state/chassis0", 1205 "org.freedesktop.DBus.Properties", "Get", 1206 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1207 } 1208 1209 /** 1210 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1211 * 1212 * @param[in] aResp Shared pointer for generating response message. 1213 * 1214 * @return None. 1215 */ 1216 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1217 { 1218 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1219 1220 crow::connections::systemBus->async_method_call( 1221 [aResp](const boost::system::error_code ec, 1222 std::variant<bool>& autoRebootEnabled) { 1223 if (ec) 1224 { 1225 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1226 return; 1227 } 1228 1229 const bool* autoRebootEnabledPtr = 1230 std::get_if<bool>(&autoRebootEnabled); 1231 1232 if (!autoRebootEnabledPtr) 1233 { 1234 messages::internalError(aResp->res); 1235 return; 1236 } 1237 1238 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1239 if (*autoRebootEnabledPtr == true) 1240 { 1241 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1242 "RetryAttempts"; 1243 // If AutomaticRetry (AutoReboot) is enabled see how many 1244 // attempts are left 1245 crow::connections::systemBus->async_method_call( 1246 [aResp](const boost::system::error_code ec2, 1247 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1248 if (ec2) 1249 { 1250 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1251 return; 1252 } 1253 1254 const uint32_t* autoRebootAttemptsLeftPtr = 1255 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1256 1257 if (!autoRebootAttemptsLeftPtr) 1258 { 1259 messages::internalError(aResp->res); 1260 return; 1261 } 1262 1263 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1264 << *autoRebootAttemptsLeftPtr; 1265 1266 aResp->res 1267 .jsonValue["Boot"] 1268 ["RemainingAutomaticRetryAttempts"] = 1269 *autoRebootAttemptsLeftPtr; 1270 }, 1271 "xyz.openbmc_project.State.Host", 1272 "/xyz/openbmc_project/state/host0", 1273 "org.freedesktop.DBus.Properties", "Get", 1274 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1275 "AttemptsLeft"); 1276 } 1277 else 1278 { 1279 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1280 "Disabled"; 1281 } 1282 1283 // Not on D-Bus. Hardcoded here: 1284 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1285 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1286 1287 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1288 // and RetryAttempts. OpenBMC only supports Disabled and 1289 // RetryAttempts. 1290 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1291 "AllowableValues"] = {"Disabled", 1292 "RetryAttempts"}; 1293 }, 1294 "xyz.openbmc_project.Settings", 1295 "/xyz/openbmc_project/control/host0/auto_reboot", 1296 "org.freedesktop.DBus.Properties", "Get", 1297 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1298 } 1299 1300 /** 1301 * @brief Retrieves power restore policy over DBUS. 1302 * 1303 * @param[in] aResp Shared pointer for generating response message. 1304 * 1305 * @return None. 1306 */ 1307 inline void 1308 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1309 { 1310 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1311 1312 crow::connections::systemBus->async_method_call( 1313 [aResp](const boost::system::error_code ec, 1314 std::variant<std::string>& policy) { 1315 if (ec) 1316 { 1317 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1318 return; 1319 } 1320 1321 const boost::container::flat_map<std::string, std::string> 1322 policyMaps = { 1323 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1324 "AlwaysOn", 1325 "AlwaysOn"}, 1326 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1327 "AlwaysOff", 1328 "AlwaysOff"}, 1329 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1330 "Restore", 1331 "LastState"}}; 1332 1333 const std::string* policyPtr = std::get_if<std::string>(&policy); 1334 1335 if (!policyPtr) 1336 { 1337 messages::internalError(aResp->res); 1338 return; 1339 } 1340 1341 auto policyMapsIt = policyMaps.find(*policyPtr); 1342 if (policyMapsIt == policyMaps.end()) 1343 { 1344 messages::internalError(aResp->res); 1345 return; 1346 } 1347 1348 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1349 }, 1350 "xyz.openbmc_project.Settings", 1351 "/xyz/openbmc_project/control/host0/power_restore_policy", 1352 "org.freedesktop.DBus.Properties", "Get", 1353 "xyz.openbmc_project.Control.Power.RestorePolicy", 1354 "PowerRestorePolicy"); 1355 } 1356 1357 /** 1358 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1359 * TPM is required for booting the host. 1360 * 1361 * @param[in] aResp Shared pointer for generating response message. 1362 * 1363 * @return None. 1364 */ 1365 inline void getTrustedModuleRequiredToBoot( 1366 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1367 { 1368 BMCWEB_LOG_DEBUG << "Get TPM required to boot."; 1369 1370 crow::connections::systemBus->async_method_call( 1371 [aResp]( 1372 const boost::system::error_code ec, 1373 std::vector<std::pair< 1374 std::string, 1375 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1376 subtree) { 1377 if (ec) 1378 { 1379 BMCWEB_LOG_DEBUG 1380 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1381 // This is an optional D-Bus object so just return if 1382 // error occurs 1383 return; 1384 } 1385 if (subtree.size() == 0) 1386 { 1387 // As noted above, this is an optional interface so just return 1388 // if there is no instance found 1389 return; 1390 } 1391 1392 /* When there is more than one TPMEnable object... */ 1393 if (subtree.size() > 1) 1394 { 1395 BMCWEB_LOG_DEBUG 1396 << "DBUS response has more than 1 TPM Enable object:" 1397 << subtree.size(); 1398 // Throw an internal Error and return 1399 messages::internalError(aResp->res); 1400 return; 1401 } 1402 1403 // Make sure the Dbus response map has a service and objectPath 1404 // field 1405 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1406 { 1407 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1408 messages::internalError(aResp->res); 1409 return; 1410 } 1411 1412 const std::string& path = subtree[0].first; 1413 const std::string& serv = subtree[0].second.begin()->first; 1414 1415 // Valid TPM Enable object found, now reading the current value 1416 crow::connections::systemBus->async_method_call( 1417 [aResp](const boost::system::error_code ec, 1418 std::variant<bool>& tpmRequired) { 1419 if (ec) 1420 { 1421 BMCWEB_LOG_DEBUG 1422 << "D-BUS response error on TPM.Policy Get" << ec; 1423 messages::internalError(aResp->res); 1424 return; 1425 } 1426 1427 const bool* tpmRequiredVal = 1428 std::get_if<bool>(&tpmRequired); 1429 1430 if (!tpmRequiredVal) 1431 { 1432 messages::internalError(aResp->res); 1433 return; 1434 } 1435 1436 if (*tpmRequiredVal == true) 1437 { 1438 aResp->res 1439 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1440 "Required"; 1441 } 1442 else 1443 { 1444 aResp->res 1445 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1446 "Disabled"; 1447 } 1448 }, 1449 serv, path, "org.freedesktop.DBus.Properties", "Get", 1450 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable"); 1451 }, 1452 "xyz.openbmc_project.ObjectMapper", 1453 "/xyz/openbmc_project/object_mapper", 1454 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1455 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1456 } 1457 1458 /** 1459 * @brief Sets boot properties into DBUS object(s). 1460 * 1461 * @param[in] aResp Shared pointer for generating response message. 1462 * @param[in] overrideEnabled The source override "enable". 1463 * @param[in] bootObj Path to the DBUS object. 1464 * @param[in] bootType The boot type to set. 1465 * @return Integer error code. 1466 */ 1467 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1468 const bool overrideEnabled, const std::string& bootObj, 1469 const std::optional<std::string>& bootType) 1470 { 1471 std::string bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1472 1473 if (bootType && overrideEnabled) 1474 { 1475 // Source target specified 1476 BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; 1477 // Figure out which DBUS interface and property to use 1478 if (*bootType == "Legacy") 1479 { 1480 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1481 } 1482 else if (*bootType == "UEFI") 1483 { 1484 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1485 } 1486 else 1487 { 1488 BMCWEB_LOG_DEBUG << "Invalid property value for " 1489 "BootSourceOverrideMode: " 1490 << *bootType; 1491 messages::propertyValueNotInList(aResp->res, *bootType, 1492 "BootSourceOverrideMode"); 1493 return; 1494 } 1495 } 1496 1497 // Act on validated parameters 1498 BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; 1499 1500 crow::connections::systemBus->async_method_call( 1501 [aResp, bootType](const boost::system::error_code ec) { 1502 if (ec) 1503 { 1504 if (!bootType) 1505 { 1506 // If bootType wasn't explicitly present in the incoming 1507 // message don't output error. The error could come from a 1508 // fact that the BootType interface may be not present in 1509 // the settings object. It could happen because this 1510 // interface is not relevant for some Host architectures 1511 // (for example POWER). 1512 return; 1513 } 1514 1515 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1516 if (ec.value() == boost::asio::error::host_unreachable) 1517 { 1518 messages::resourceNotFound(aResp->res, "Set", "BootType"); 1519 return; 1520 } 1521 messages::internalError(aResp->res); 1522 return; 1523 } 1524 BMCWEB_LOG_DEBUG << "Boot type update done."; 1525 }, 1526 "xyz.openbmc_project.Settings", bootObj, 1527 "org.freedesktop.DBus.Properties", "Set", 1528 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1529 std::variant<std::string>(bootTypeStr)); 1530 } 1531 1532 /** 1533 * @brief Sets boot properties into DBUS object(s). 1534 * 1535 * @param[in] aResp Shared pointer for generating response message. 1536 * @param[in] overrideEnabled The source override "enable". 1537 * @param[in] bootObj Path to the DBUS object. 1538 * @param[in] bootSource The boot source to set. 1539 * 1540 * @return Integer error code. 1541 */ 1542 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1543 const bool overrideEnabled, 1544 const std::string& bootObj, 1545 const std::optional<std::string>& bootSource) 1546 { 1547 std::string bootSourceStr = 1548 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1549 std::string bootModeStr = 1550 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1551 1552 if (bootSource && overrideEnabled) 1553 { 1554 // Source target specified 1555 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1556 // Figure out which DBUS interface and property to use 1557 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1558 bootModeStr)) 1559 { 1560 BMCWEB_LOG_DEBUG 1561 << "Invalid property value for BootSourceOverrideTarget: " 1562 << *bootSource; 1563 messages::propertyValueNotInList(aResp->res, *bootSource, 1564 "BootSourceTargetOverride"); 1565 return; 1566 } 1567 } 1568 1569 // Act on validated parameters 1570 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1571 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1572 1573 crow::connections::systemBus->async_method_call( 1574 [aResp](const boost::system::error_code ec) { 1575 if (ec) 1576 { 1577 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1578 messages::internalError(aResp->res); 1579 return; 1580 } 1581 BMCWEB_LOG_DEBUG << "Boot source update done."; 1582 }, 1583 "xyz.openbmc_project.Settings", bootObj, 1584 "org.freedesktop.DBus.Properties", "Set", 1585 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1586 std::variant<std::string>(bootSourceStr)); 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 mode update done."; 1597 }, 1598 "xyz.openbmc_project.Settings", bootObj, 1599 "org.freedesktop.DBus.Properties", "Set", 1600 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1601 std::variant<std::string>(bootModeStr)); 1602 } 1603 1604 /** 1605 * @brief Sets "One time" enabled setting into DBUS object 1606 * 1607 * @param[in] aResp Shared pointer for generating response message. 1608 * @param[in] oneTime Enable property for one-time object 1609 * 1610 * @return Integer error code. 1611 */ 1612 inline void setOneTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1613 bool oneTime) 1614 { 1615 crow::connections::systemBus->async_method_call( 1616 [aResp{aResp}](const boost::system::error_code ec) { 1617 if (ec) 1618 { 1619 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1620 messages::internalError(aResp->res); 1621 return; 1622 } 1623 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1624 }, 1625 "xyz.openbmc_project.Settings", 1626 "/xyz/openbmc_project/control/host0/boot/one_time", 1627 "org.freedesktop.DBus.Properties", "Set", 1628 "xyz.openbmc_project.Object.Enable", "Enabled", 1629 std::variant<bool>(oneTime)); 1630 } 1631 1632 /** 1633 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1634 * set boot source/boot mode properties. 1635 * 1636 * @param[in] aResp Shared pointer for generating response message. 1637 * @param[in] bootSource The boot source from incoming RF request. 1638 * @param[in] bootType The boot type from incoming RF request. 1639 * @param[in] bootEnable The boot override enable from incoming RF request. 1640 * 1641 * @return Integer error code. 1642 */ 1643 inline void 1644 setBootSourceProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1645 std::optional<std::string> bootSource, 1646 std::optional<std::string> bootType, 1647 std::optional<std::string> bootEnable) 1648 { 1649 BMCWEB_LOG_DEBUG << "Set boot information."; 1650 1651 crow::connections::systemBus->async_method_call( 1652 [aResp, bootSource{std::move(bootSource)}, 1653 bootType{std::move(bootType)}, 1654 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1655 const std::variant<bool>& oneTime) { 1656 if (ec) 1657 { 1658 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1659 messages::internalError(aResp->res); 1660 return; 1661 } 1662 1663 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1664 1665 if (!oneTimePtr) 1666 { 1667 messages::internalError(aResp->res); 1668 return; 1669 } 1670 1671 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1672 1673 bool oneTimeSetting = *oneTimePtr; 1674 bool overrideEnabled = true; 1675 1676 // Validate incoming parameters 1677 if (bootEnable) 1678 { 1679 if (*bootEnable == "Once") 1680 { 1681 oneTimeSetting = true; 1682 } 1683 else if (*bootEnable == "Continuous") 1684 { 1685 oneTimeSetting = false; 1686 } 1687 else if (*bootEnable == "Disabled") 1688 { 1689 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1690 oneTimeSetting = false; 1691 overrideEnabled = false; 1692 } 1693 else 1694 { 1695 BMCWEB_LOG_DEBUG << "Unsupported value for " 1696 "BootSourceOverrideEnabled: " 1697 << *bootEnable; 1698 messages::propertyValueNotInList( 1699 aResp->res, *bootEnable, "BootSourceOverrideEnabled"); 1700 return; 1701 } 1702 } 1703 1704 std::string bootObj = "/xyz/openbmc_project/control/host0/boot"; 1705 if (oneTimeSetting) 1706 { 1707 bootObj += "/one_time"; 1708 } 1709 1710 setBootModeOrSource(aResp, overrideEnabled, bootObj, bootSource); 1711 setBootType(aResp, overrideEnabled, bootObj, bootType); 1712 setOneTime(aResp, oneTimeSetting); 1713 }, 1714 "xyz.openbmc_project.Settings", 1715 "/xyz/openbmc_project/control/host0/boot/one_time", 1716 "org.freedesktop.DBus.Properties", "Get", 1717 "xyz.openbmc_project.Object.Enable", "Enabled"); 1718 } 1719 1720 /** 1721 * @brief Sets AssetTag 1722 * 1723 * @param[in] aResp Shared pointer for generating response message. 1724 * @param[in] assetTag "AssetTag" from request. 1725 * 1726 * @return None. 1727 */ 1728 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1729 const std::string& assetTag) 1730 { 1731 crow::connections::systemBus->async_method_call( 1732 [aResp, assetTag]( 1733 const boost::system::error_code ec, 1734 const std::vector<std::pair< 1735 std::string, 1736 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1737 subtree) { 1738 if (ec) 1739 { 1740 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1741 messages::internalError(aResp->res); 1742 return; 1743 } 1744 if (subtree.size() == 0) 1745 { 1746 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1747 messages::internalError(aResp->res); 1748 return; 1749 } 1750 // Assume only 1 system D-Bus object 1751 // Throw an error if there is more than 1 1752 if (subtree.size() > 1) 1753 { 1754 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1755 messages::internalError(aResp->res); 1756 return; 1757 } 1758 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1759 { 1760 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1761 messages::internalError(aResp->res); 1762 return; 1763 } 1764 1765 const std::string& path = subtree[0].first; 1766 const std::string& service = subtree[0].second.begin()->first; 1767 1768 if (service.empty()) 1769 { 1770 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1771 messages::internalError(aResp->res); 1772 return; 1773 } 1774 1775 crow::connections::systemBus->async_method_call( 1776 [aResp](const boost::system::error_code ec2) { 1777 if (ec2) 1778 { 1779 BMCWEB_LOG_DEBUG 1780 << "D-Bus response error on AssetTag Set " << ec2; 1781 messages::internalError(aResp->res); 1782 return; 1783 } 1784 }, 1785 service, path, "org.freedesktop.DBus.Properties", "Set", 1786 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1787 std::variant<std::string>(assetTag)); 1788 }, 1789 "xyz.openbmc_project.ObjectMapper", 1790 "/xyz/openbmc_project/object_mapper", 1791 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1792 "/xyz/openbmc_project/inventory", int32_t(0), 1793 std::array<const char*, 1>{ 1794 "xyz.openbmc_project.Inventory.Item.System"}); 1795 } 1796 1797 /** 1798 * @brief Sets automaticRetry (Auto Reboot) 1799 * 1800 * @param[in] aResp Shared pointer for generating response message. 1801 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1802 * 1803 * @return None. 1804 */ 1805 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1806 const std::string& automaticRetryConfig) 1807 { 1808 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1809 1810 // OpenBMC only supports "Disabled" and "RetryAttempts". 1811 bool autoRebootEnabled; 1812 1813 if (automaticRetryConfig == "Disabled") 1814 { 1815 autoRebootEnabled = false; 1816 } 1817 else if (automaticRetryConfig == "RetryAttempts") 1818 { 1819 autoRebootEnabled = true; 1820 } 1821 else 1822 { 1823 BMCWEB_LOG_DEBUG << "Invalid property value for " 1824 "AutomaticRetryConfig: " 1825 << automaticRetryConfig; 1826 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1827 "AutomaticRetryConfig"); 1828 return; 1829 } 1830 1831 crow::connections::systemBus->async_method_call( 1832 [aResp](const boost::system::error_code ec) { 1833 if (ec) 1834 { 1835 messages::internalError(aResp->res); 1836 return; 1837 } 1838 }, 1839 "xyz.openbmc_project.Settings", 1840 "/xyz/openbmc_project/control/host0/auto_reboot", 1841 "org.freedesktop.DBus.Properties", "Set", 1842 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1843 std::variant<bool>(autoRebootEnabled)); 1844 } 1845 1846 /** 1847 * @brief Sets power restore policy properties. 1848 * 1849 * @param[in] aResp Shared pointer for generating response message. 1850 * @param[in] policy power restore policy properties from request. 1851 * 1852 * @return None. 1853 */ 1854 inline void 1855 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1856 const std::string& policy) 1857 { 1858 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1859 1860 const boost::container::flat_map<std::string, std::string> policyMaps = { 1861 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1862 "AlwaysOn"}, 1863 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1864 "AlwaysOff"}, 1865 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1866 "Restore"}}; 1867 1868 std::string powerRestorPolicy; 1869 1870 auto policyMapsIt = policyMaps.find(policy); 1871 if (policyMapsIt == policyMaps.end()) 1872 { 1873 messages::propertyValueNotInList(aResp->res, policy, 1874 "PowerRestorePolicy"); 1875 return; 1876 } 1877 1878 powerRestorPolicy = policyMapsIt->second; 1879 1880 crow::connections::systemBus->async_method_call( 1881 [aResp](const boost::system::error_code ec) { 1882 if (ec) 1883 { 1884 messages::internalError(aResp->res); 1885 return; 1886 } 1887 }, 1888 "xyz.openbmc_project.Settings", 1889 "/xyz/openbmc_project/control/host0/power_restore_policy", 1890 "org.freedesktop.DBus.Properties", "Set", 1891 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1892 std::variant<std::string>(powerRestorPolicy)); 1893 } 1894 1895 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1896 /** 1897 * @brief Retrieves provisioning status 1898 * 1899 * @param[in] aResp Shared pointer for completing asynchronous calls. 1900 * 1901 * @return None. 1902 */ 1903 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1904 { 1905 BMCWEB_LOG_DEBUG << "Get OEM information."; 1906 crow::connections::systemBus->async_method_call( 1907 [aResp](const boost::system::error_code ec, 1908 const std::vector<std::pair<std::string, VariantType>>& 1909 propertiesList) { 1910 nlohmann::json& oemPFR = 1911 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1912 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1913 "#OemComputerSystem.OpenBmc"; 1914 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1915 1916 if (ec) 1917 { 1918 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1919 // not an error, don't have to have the interface 1920 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1921 return; 1922 } 1923 1924 const bool* provState = nullptr; 1925 const bool* lockState = nullptr; 1926 for (const std::pair<std::string, VariantType>& property : 1927 propertiesList) 1928 { 1929 if (property.first == "UfmProvisioned") 1930 { 1931 provState = std::get_if<bool>(&property.second); 1932 } 1933 else if (property.first == "UfmLocked") 1934 { 1935 lockState = std::get_if<bool>(&property.second); 1936 } 1937 } 1938 1939 if ((provState == nullptr) || (lockState == nullptr)) 1940 { 1941 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1942 messages::internalError(aResp->res); 1943 return; 1944 } 1945 1946 if (*provState == true) 1947 { 1948 if (*lockState == true) 1949 { 1950 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1951 } 1952 else 1953 { 1954 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1955 } 1956 } 1957 else 1958 { 1959 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1960 } 1961 }, 1962 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1963 "org.freedesktop.DBus.Properties", "GetAll", 1964 "xyz.openbmc_project.PFR.Attributes"); 1965 } 1966 #endif 1967 1968 /** 1969 * @brief Translate the PowerMode to a response message. 1970 * 1971 * @param[in] aResp Shared pointer for generating response message. 1972 * @param[in] modeValue PowerMode value to be translated 1973 * 1974 * @return None. 1975 */ 1976 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1977 const std::string& modeValue) 1978 { 1979 std::string modeString; 1980 1981 if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1982 "PowerMode.Static") 1983 { 1984 aResp->res.jsonValue["PowerMode"] = "Static"; 1985 } 1986 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1987 "PowerMode.MaximumPerformance") 1988 { 1989 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1990 } 1991 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1992 "PowerMode.PowerSaving") 1993 { 1994 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1995 } 1996 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1997 "PowerMode.OEM") 1998 { 1999 aResp->res.jsonValue["PowerMode"] = "OEM"; 2000 } 2001 else 2002 { 2003 // Any other values would be invalid 2004 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 2005 messages::internalError(aResp->res); 2006 } 2007 } 2008 2009 /** 2010 * @brief Retrieves system power mode 2011 * 2012 * @param[in] aResp Shared pointer for generating response message. 2013 * 2014 * @return None. 2015 */ 2016 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2017 { 2018 BMCWEB_LOG_DEBUG << "Get power mode."; 2019 2020 // Get Power Mode object path: 2021 crow::connections::systemBus->async_method_call( 2022 [aResp]( 2023 const boost::system::error_code ec, 2024 const std::vector<std::pair< 2025 std::string, 2026 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2027 subtree) { 2028 if (ec) 2029 { 2030 BMCWEB_LOG_DEBUG 2031 << "DBUS response error on Power.Mode GetSubTree " << ec; 2032 // This is an optional D-Bus object so just return if 2033 // error occurs 2034 return; 2035 } 2036 if (subtree.empty()) 2037 { 2038 // As noted above, this is an optional interface so just return 2039 // if there is no instance found 2040 return; 2041 } 2042 if (subtree.size() > 1) 2043 { 2044 // More then one PowerMode object is not supported and is an 2045 // error 2046 BMCWEB_LOG_DEBUG 2047 << "Found more than 1 system D-Bus Power.Mode objects: " 2048 << subtree.size(); 2049 messages::internalError(aResp->res); 2050 return; 2051 } 2052 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2053 { 2054 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2055 messages::internalError(aResp->res); 2056 return; 2057 } 2058 const std::string& path = subtree[0].first; 2059 const std::string& service = subtree[0].second.begin()->first; 2060 if (service.empty()) 2061 { 2062 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2063 messages::internalError(aResp->res); 2064 return; 2065 } 2066 // Valid Power Mode object found, now read the current value 2067 crow::connections::systemBus->async_method_call( 2068 [aResp](const boost::system::error_code ec, 2069 const std::variant<std::string>& pmode) { 2070 if (ec) 2071 { 2072 BMCWEB_LOG_DEBUG 2073 << "DBUS response error on PowerMode Get: " << ec; 2074 messages::internalError(aResp->res); 2075 return; 2076 } 2077 2078 const std::string* s = std::get_if<std::string>(&pmode); 2079 if (s == nullptr) 2080 { 2081 BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; 2082 messages::internalError(aResp->res); 2083 return; 2084 } 2085 2086 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 2087 {"Static", "MaximumPerformance", "PowerSaving"}; 2088 2089 BMCWEB_LOG_DEBUG << "Current power mode: " << *s; 2090 translatePowerMode(aResp, *s); 2091 }, 2092 service, path, "org.freedesktop.DBus.Properties", "Get", 2093 "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); 2094 }, 2095 "xyz.openbmc_project.ObjectMapper", 2096 "/xyz/openbmc_project/object_mapper", 2097 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2098 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2099 } 2100 2101 /** 2102 * @brief Validate the specified mode is valid and return the PowerMode 2103 * name associated with that string 2104 * 2105 * @param[in] aResp Shared pointer for generating response message. 2106 * @param[in] modeString String representing the desired PowerMode 2107 * 2108 * @return PowerMode value or empty string if mode is not valid 2109 */ 2110 inline std::string 2111 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2112 const std::string& modeString) 2113 { 2114 std::string mode; 2115 2116 if (modeString == "Static") 2117 { 2118 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2119 } 2120 else if (modeString == "MaximumPerformance") 2121 { 2122 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode." 2123 "MaximumPerformance"; 2124 } 2125 else if (modeString == "PowerSaving") 2126 { 2127 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2128 } 2129 else 2130 { 2131 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2132 } 2133 return mode; 2134 } 2135 2136 /** 2137 * @brief Sets system power mode. 2138 * 2139 * @param[in] aResp Shared pointer for generating response message. 2140 * @param[in] pmode System power mode from request. 2141 * 2142 * @return None. 2143 */ 2144 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2145 const std::string& pmode) 2146 { 2147 BMCWEB_LOG_DEBUG << "Set power mode."; 2148 2149 std::string powerMode = validatePowerMode(aResp, pmode); 2150 if (powerMode.empty()) 2151 { 2152 return; 2153 } 2154 2155 // Get Power Mode object path: 2156 crow::connections::systemBus->async_method_call( 2157 [aResp, powerMode]( 2158 const boost::system::error_code ec, 2159 const std::vector<std::pair< 2160 std::string, 2161 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 2162 subtree) { 2163 if (ec) 2164 { 2165 BMCWEB_LOG_DEBUG 2166 << "DBUS response error on Power.Mode GetSubTree " << ec; 2167 // This is an optional D-Bus object, but user attempted to patch 2168 messages::internalError(aResp->res); 2169 return; 2170 } 2171 if (subtree.empty()) 2172 { 2173 // This is an optional D-Bus object, but user attempted to patch 2174 messages::resourceNotFound(aResp->res, "ComputerSystem", 2175 "PowerMode"); 2176 return; 2177 } 2178 if (subtree.size() > 1) 2179 { 2180 // More then one PowerMode object is not supported and is an 2181 // error 2182 BMCWEB_LOG_DEBUG 2183 << "Found more than 1 system D-Bus Power.Mode objects: " 2184 << subtree.size(); 2185 messages::internalError(aResp->res); 2186 return; 2187 } 2188 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2189 { 2190 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2191 messages::internalError(aResp->res); 2192 return; 2193 } 2194 const std::string& path = subtree[0].first; 2195 const std::string& service = subtree[0].second.begin()->first; 2196 if (service.empty()) 2197 { 2198 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2199 messages::internalError(aResp->res); 2200 return; 2201 } 2202 2203 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2204 << path; 2205 2206 // Set the Power Mode property 2207 crow::connections::systemBus->async_method_call( 2208 [aResp](const boost::system::error_code ec) { 2209 if (ec) 2210 { 2211 messages::internalError(aResp->res); 2212 return; 2213 } 2214 }, 2215 service, path, "org.freedesktop.DBus.Properties", "Set", 2216 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2217 std::variant<std::string>(powerMode)); 2218 }, 2219 "xyz.openbmc_project.ObjectMapper", 2220 "/xyz/openbmc_project/object_mapper", 2221 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2222 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2223 } 2224 2225 /** 2226 * @brief Translates watchdog timeout action DBUS property value to redfish. 2227 * 2228 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2229 * 2230 * @return Returns as a string, the timeout action in Redfish terms. If 2231 * translation cannot be done, returns an empty string. 2232 */ 2233 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2234 { 2235 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2236 { 2237 return "None"; 2238 } 2239 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2240 { 2241 return "ResetSystem"; 2242 } 2243 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2244 { 2245 return "PowerDown"; 2246 } 2247 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2248 { 2249 return "PowerCycle"; 2250 } 2251 2252 return ""; 2253 } 2254 2255 /** 2256 *@brief Translates timeout action from Redfish to DBUS property value. 2257 * 2258 *@param[in] rfAction The timeout action in Redfish. 2259 * 2260 *@return Returns as a string, the time_out action as expected by DBUS. 2261 *If translation cannot be done, returns an empty string. 2262 */ 2263 2264 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2265 { 2266 if (rfAction == "None") 2267 { 2268 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2269 } 2270 if (rfAction == "PowerCycle") 2271 { 2272 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2273 } 2274 if (rfAction == "PowerDown") 2275 { 2276 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2277 } 2278 if (rfAction == "ResetSystem") 2279 { 2280 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2281 } 2282 2283 return ""; 2284 } 2285 2286 /** 2287 * @brief Retrieves host watchdog timer properties over DBUS 2288 * 2289 * @param[in] aResp Shared pointer for completing asynchronous calls. 2290 * 2291 * @return None. 2292 */ 2293 inline void 2294 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2295 { 2296 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2297 crow::connections::systemBus->async_method_call( 2298 [aResp](const boost::system::error_code ec, 2299 PropertiesType& properties) { 2300 if (ec) 2301 { 2302 // watchdog service is stopped 2303 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2304 return; 2305 } 2306 2307 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2308 2309 nlohmann::json& hostWatchdogTimer = 2310 aResp->res.jsonValue["HostWatchdogTimer"]; 2311 2312 // watchdog service is running/enabled 2313 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2314 2315 for (const auto& property : properties) 2316 { 2317 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2318 if (property.first == "Enabled") 2319 { 2320 const bool* state = std::get_if<bool>(&property.second); 2321 2322 if (!state) 2323 { 2324 messages::internalError(aResp->res); 2325 return; 2326 } 2327 2328 hostWatchdogTimer["FunctionEnabled"] = *state; 2329 } 2330 else if (property.first == "ExpireAction") 2331 { 2332 const std::string* s = 2333 std::get_if<std::string>(&property.second); 2334 if (!s) 2335 { 2336 messages::internalError(aResp->res); 2337 return; 2338 } 2339 2340 std::string action = dbusToRfWatchdogAction(*s); 2341 if (action.empty()) 2342 { 2343 messages::internalError(aResp->res); 2344 return; 2345 } 2346 hostWatchdogTimer["TimeoutAction"] = action; 2347 } 2348 } 2349 }, 2350 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2351 "org.freedesktop.DBus.Properties", "GetAll", 2352 "xyz.openbmc_project.State.Watchdog"); 2353 } 2354 2355 /** 2356 * @brief Sets Host WatchDog Timer properties. 2357 * 2358 * @param[in] aResp Shared pointer for generating response message. 2359 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2360 * RF request. 2361 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2362 * 2363 * @return None. 2364 */ 2365 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2366 const std::optional<bool> wdtEnable, 2367 const std::optional<std::string>& wdtTimeOutAction) 2368 { 2369 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2370 2371 if (wdtTimeOutAction) 2372 { 2373 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2374 // check if TimeOut Action is Valid 2375 if (wdtTimeOutActStr.empty()) 2376 { 2377 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2378 << *wdtTimeOutAction; 2379 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2380 "TimeoutAction"); 2381 return; 2382 } 2383 2384 crow::connections::systemBus->async_method_call( 2385 [aResp](const boost::system::error_code ec) { 2386 if (ec) 2387 { 2388 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2389 messages::internalError(aResp->res); 2390 return; 2391 } 2392 }, 2393 "xyz.openbmc_project.Watchdog", 2394 "/xyz/openbmc_project/watchdog/host0", 2395 "org.freedesktop.DBus.Properties", "Set", 2396 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2397 std::variant<std::string>(wdtTimeOutActStr)); 2398 } 2399 2400 if (wdtEnable) 2401 { 2402 crow::connections::systemBus->async_method_call( 2403 [aResp](const boost::system::error_code ec) { 2404 if (ec) 2405 { 2406 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2407 messages::internalError(aResp->res); 2408 return; 2409 } 2410 }, 2411 "xyz.openbmc_project.Watchdog", 2412 "/xyz/openbmc_project/watchdog/host0", 2413 "org.freedesktop.DBus.Properties", "Set", 2414 "xyz.openbmc_project.State.Watchdog", "Enabled", 2415 std::variant<bool>(*wdtEnable)); 2416 } 2417 } 2418 2419 /** 2420 * SystemsCollection derived class for delivering ComputerSystems Collection 2421 * Schema 2422 */ 2423 inline void requestRoutesSystemsCollection(App& app) 2424 { 2425 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2426 .privileges(redfish::privileges::getComputerSystemCollection) 2427 .methods(boost::beast::http::verb::get)( 2428 [](const crow::Request& /*req*/, 2429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2430 asyncResp->res.jsonValue["@odata.type"] = 2431 "#ComputerSystemCollection.ComputerSystemCollection"; 2432 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2433 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2434 2435 crow::connections::systemBus->async_method_call( 2436 [asyncResp](const boost::system::error_code ec, 2437 const std::variant<std::string>& /*hostName*/) { 2438 nlohmann::json& ifaceArray = 2439 asyncResp->res.jsonValue["Members"]; 2440 ifaceArray = nlohmann::json::array(); 2441 auto& count = 2442 asyncResp->res.jsonValue["Members@odata.count"]; 2443 ifaceArray.push_back( 2444 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2445 count = ifaceArray.size(); 2446 if (!ec) 2447 { 2448 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2449 ifaceArray.push_back( 2450 {{"@odata.id", 2451 "/redfish/v1/Systems/hypervisor"}}); 2452 count = ifaceArray.size(); 2453 } 2454 }, 2455 "xyz.openbmc_project.Settings", 2456 "/xyz/openbmc_project/network/hypervisor", 2457 "org.freedesktop.DBus.Properties", "Get", 2458 "xyz.openbmc_project.Network.SystemConfiguration", 2459 "HostName"); 2460 }); 2461 } 2462 2463 /** 2464 * Function transceives data with dbus directly. 2465 */ 2466 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2467 { 2468 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2469 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2470 constexpr char const* interfaceName = 2471 "xyz.openbmc_project.Control.Host.NMI"; 2472 constexpr char const* method = "NMI"; 2473 2474 crow::connections::systemBus->async_method_call( 2475 [asyncResp](const boost::system::error_code ec) { 2476 if (ec) 2477 { 2478 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2479 messages::internalError(asyncResp->res); 2480 return; 2481 } 2482 messages::success(asyncResp->res); 2483 }, 2484 serviceName, objectPath, interfaceName, method); 2485 } 2486 2487 /** 2488 * SystemActionsReset class supports handle POST method for Reset action. 2489 * The class retrieves and sends data directly to D-Bus. 2490 */ 2491 inline void requestRoutesSystemActionsReset(App& app) 2492 { 2493 /** 2494 * Function handles POST method request. 2495 * Analyzes POST body message before sends Reset request data to D-Bus. 2496 */ 2497 BMCWEB_ROUTE(app, 2498 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2499 .privileges(redfish::privileges::postComputerSystem) 2500 .methods( 2501 boost::beast::http::verb:: 2502 post)([](const crow::Request& req, 2503 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2504 std::string resetType; 2505 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2506 resetType)) 2507 { 2508 return; 2509 } 2510 2511 // Get the command and host vs. chassis 2512 std::string command; 2513 bool hostCommand; 2514 if ((resetType == "On") || (resetType == "ForceOn")) 2515 { 2516 command = "xyz.openbmc_project.State.Host.Transition.On"; 2517 hostCommand = true; 2518 } 2519 else if (resetType == "ForceOff") 2520 { 2521 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2522 hostCommand = false; 2523 } 2524 else if (resetType == "ForceRestart") 2525 { 2526 command = 2527 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2528 hostCommand = true; 2529 } 2530 else if (resetType == "GracefulShutdown") 2531 { 2532 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2533 hostCommand = true; 2534 } 2535 else if (resetType == "GracefulRestart") 2536 { 2537 command = "xyz.openbmc_project.State.Host.Transition." 2538 "GracefulWarmReboot"; 2539 hostCommand = true; 2540 } 2541 else if (resetType == "PowerCycle") 2542 { 2543 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2544 hostCommand = true; 2545 } 2546 else if (resetType == "Nmi") 2547 { 2548 doNMI(asyncResp); 2549 return; 2550 } 2551 else 2552 { 2553 messages::actionParameterUnknown(asyncResp->res, "Reset", 2554 resetType); 2555 return; 2556 } 2557 2558 if (hostCommand) 2559 { 2560 crow::connections::systemBus->async_method_call( 2561 [asyncResp, resetType](const boost::system::error_code ec) { 2562 if (ec) 2563 { 2564 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2565 if (ec.value() == 2566 boost::asio::error::invalid_argument) 2567 { 2568 messages::actionParameterNotSupported( 2569 asyncResp->res, resetType, "Reset"); 2570 } 2571 else 2572 { 2573 messages::internalError(asyncResp->res); 2574 } 2575 return; 2576 } 2577 messages::success(asyncResp->res); 2578 }, 2579 "xyz.openbmc_project.State.Host", 2580 "/xyz/openbmc_project/state/host0", 2581 "org.freedesktop.DBus.Properties", "Set", 2582 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2583 std::variant<std::string>{command}); 2584 } 2585 else 2586 { 2587 crow::connections::systemBus->async_method_call( 2588 [asyncResp, resetType](const boost::system::error_code ec) { 2589 if (ec) 2590 { 2591 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2592 if (ec.value() == 2593 boost::asio::error::invalid_argument) 2594 { 2595 messages::actionParameterNotSupported( 2596 asyncResp->res, resetType, "Reset"); 2597 } 2598 else 2599 { 2600 messages::internalError(asyncResp->res); 2601 } 2602 return; 2603 } 2604 messages::success(asyncResp->res); 2605 }, 2606 "xyz.openbmc_project.State.Chassis", 2607 "/xyz/openbmc_project/state/chassis0", 2608 "org.freedesktop.DBus.Properties", "Set", 2609 "xyz.openbmc_project.State.Chassis", 2610 "RequestedPowerTransition", 2611 std::variant<std::string>{command}); 2612 } 2613 }); 2614 } 2615 2616 /** 2617 * Systems derived class for delivering Computer Systems Schema. 2618 */ 2619 inline void requestRoutesSystems(App& app) 2620 { 2621 2622 /** 2623 * Functions triggers appropriate requests on DBus 2624 */ 2625 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2626 .privileges(redfish::privileges::getComputerSystem) 2627 .methods( 2628 boost::beast::http::verb:: 2629 get)([](const crow::Request&, 2630 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2631 asyncResp->res.jsonValue["@odata.type"] = 2632 "#ComputerSystem.v1_15_0.ComputerSystem"; 2633 asyncResp->res.jsonValue["Name"] = "system"; 2634 asyncResp->res.jsonValue["Id"] = "system"; 2635 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2636 asyncResp->res.jsonValue["Description"] = "Computer System"; 2637 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2638 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2639 "Disabled"; 2640 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2641 uint64_t(0); 2642 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2643 "Disabled"; 2644 asyncResp->res.jsonValue["@odata.id"] = 2645 "/redfish/v1/Systems/system"; 2646 2647 asyncResp->res.jsonValue["Processors"] = { 2648 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2649 asyncResp->res.jsonValue["Memory"] = { 2650 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2651 asyncResp->res.jsonValue["Storage"] = { 2652 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2653 2654 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2655 {"target", 2656 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2657 {"@Redfish.ActionInfo", 2658 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2659 2660 asyncResp->res.jsonValue["LogServices"] = { 2661 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2662 2663 asyncResp->res.jsonValue["Bios"] = { 2664 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2665 2666 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2667 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2668 2669 asyncResp->res.jsonValue["Status"] = { 2670 {"Health", "OK"}, 2671 {"State", "Enabled"}, 2672 }; 2673 2674 // Fill in SerialConsole info 2675 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2676 15; 2677 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2678 {"ServiceEnabled", true}, 2679 }; 2680 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2681 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2682 {"ServiceEnabled", true}, 2683 {"Port", 2200}, 2684 // https://github.com/openbmc/docs/blob/master/console.md 2685 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2686 }; 2687 2688 #ifdef BMCWEB_ENABLE_KVM 2689 // Fill in GraphicalConsole info 2690 asyncResp->res.jsonValue["GraphicalConsole"] = { 2691 {"ServiceEnabled", true}, 2692 {"MaxConcurrentSessions", 4}, 2693 {"ConnectTypesSupported", {"KVMIP"}}, 2694 }; 2695 #endif // BMCWEB_ENABLE_KVM 2696 constexpr const std::array<const char*, 4> inventoryForSystems = { 2697 "xyz.openbmc_project.Inventory.Item.Dimm", 2698 "xyz.openbmc_project.Inventory.Item.Cpu", 2699 "xyz.openbmc_project.Inventory.Item.Drive", 2700 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2701 2702 auto health = std::make_shared<HealthPopulate>(asyncResp); 2703 crow::connections::systemBus->async_method_call( 2704 [health](const boost::system::error_code ec, 2705 std::vector<std::string>& resp) { 2706 if (ec) 2707 { 2708 // no inventory 2709 return; 2710 } 2711 2712 health->inventory = std::move(resp); 2713 }, 2714 "xyz.openbmc_project.ObjectMapper", 2715 "/xyz/openbmc_project/object_mapper", 2716 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2717 int32_t(0), inventoryForSystems); 2718 2719 health->populate(); 2720 2721 getMainChassisId( 2722 asyncResp, [](const std::string& chassisId, 2723 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2724 aRsp->res.jsonValue["Links"]["Chassis"] = { 2725 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2726 }); 2727 2728 getLocationIndicatorActive(asyncResp); 2729 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2730 getIndicatorLedState(asyncResp); 2731 getComputerSystem(asyncResp, health); 2732 getHostState(asyncResp); 2733 getBootProperties(asyncResp); 2734 getBootProgress(asyncResp); 2735 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2736 getHostWatchdogTimer(asyncResp); 2737 getPowerRestorePolicy(asyncResp); 2738 getAutomaticRetry(asyncResp); 2739 getLastResetTime(asyncResp); 2740 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2741 getProvisioningStatus(asyncResp); 2742 #endif 2743 getTrustedModuleRequiredToBoot(asyncResp); 2744 getPowerMode(asyncResp); 2745 }); 2746 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2747 .privileges(redfish::privileges::patchComputerSystem) 2748 .methods(boost::beast::http::verb::patch)( 2749 [](const crow::Request& req, 2750 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2751 std::optional<bool> locationIndicatorActive; 2752 std::optional<std::string> indicatorLed; 2753 std::optional<nlohmann::json> bootProps; 2754 std::optional<nlohmann::json> wdtTimerProps; 2755 std::optional<std::string> assetTag; 2756 std::optional<std::string> powerRestorePolicy; 2757 std::optional<std::string> powerMode; 2758 2759 if (!json_util::readJson( 2760 req, asyncResp->res, "IndicatorLED", indicatorLed, 2761 "LocationIndicatorActive", locationIndicatorActive, 2762 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2763 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2764 assetTag, "PowerMode", powerMode)) 2765 { 2766 return; 2767 } 2768 2769 asyncResp->res.result(boost::beast::http::status::no_content); 2770 2771 if (assetTag) 2772 { 2773 setAssetTag(asyncResp, *assetTag); 2774 } 2775 2776 if (wdtTimerProps) 2777 { 2778 std::optional<bool> wdtEnable; 2779 std::optional<std::string> wdtTimeOutAction; 2780 2781 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2782 "FunctionEnabled", wdtEnable, 2783 "TimeoutAction", wdtTimeOutAction)) 2784 { 2785 return; 2786 } 2787 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2788 } 2789 2790 if (bootProps) 2791 { 2792 std::optional<std::string> bootSource; 2793 std::optional<std::string> bootType; 2794 std::optional<std::string> bootEnable; 2795 std::optional<std::string> automaticRetryConfig; 2796 2797 if (!json_util::readJson( 2798 *bootProps, asyncResp->res, 2799 "BootSourceOverrideTarget", bootSource, 2800 "BootSourceOverrideMode", bootType, 2801 "BootSourceOverrideEnabled", bootEnable, 2802 "AutomaticRetryConfig", automaticRetryConfig)) 2803 { 2804 return; 2805 } 2806 if (bootSource || bootType || bootEnable) 2807 { 2808 setBootSourceProperties( 2809 asyncResp, std::move(bootSource), 2810 std::move(bootType), std::move(bootEnable)); 2811 } 2812 if (automaticRetryConfig) 2813 { 2814 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2815 } 2816 } 2817 2818 if (locationIndicatorActive) 2819 { 2820 setLocationIndicatorActive(asyncResp, 2821 *locationIndicatorActive); 2822 } 2823 2824 // TODO (Gunnar): Remove IndicatorLED after enough time has 2825 // passed 2826 if (indicatorLed) 2827 { 2828 setIndicatorLedState(asyncResp, *indicatorLed); 2829 asyncResp->res.addHeader( 2830 boost::beast::http::field::warning, 2831 "299 - \"IndicatorLED is deprecated. Use " 2832 "LocationIndicatorActive instead.\""); 2833 } 2834 2835 if (powerRestorePolicy) 2836 { 2837 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2838 } 2839 2840 if (powerMode) 2841 { 2842 setPowerMode(asyncResp, *powerMode); 2843 } 2844 }); 2845 } 2846 2847 /** 2848 * SystemResetActionInfo derived class for delivering Computer Systems 2849 * ResetType AllowableValues using ResetInfo schema. 2850 */ 2851 inline void requestRoutesSystemResetActionInfo(App& app) 2852 { 2853 2854 /** 2855 * Functions triggers appropriate requests on DBus 2856 */ 2857 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2858 .privileges(redfish::privileges::getActionInfo) 2859 .methods(boost::beast::http::verb::get)( 2860 [](const crow::Request&, 2861 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2862 asyncResp->res.jsonValue = { 2863 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2864 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2865 {"Name", "Reset Action Info"}, 2866 {"Id", "ResetActionInfo"}, 2867 {"Parameters", 2868 {{{"Name", "ResetType"}, 2869 {"Required", true}, 2870 {"DataType", "String"}, 2871 {"AllowableValues", 2872 {"On", "ForceOff", "ForceOn", "ForceRestart", 2873 "GracefulRestart", "GracefulShutdown", "PowerCycle", 2874 "Nmi"}}}}}}; 2875 }); 2876 } 2877 } // namespace redfish 2878