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