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