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