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