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