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