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 uint64_t computerSystemIndex, const uint32_t retryAttempts) 1340 { 1341 BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts."); 1342 1343 setDbusProperty(asyncResp, "Boot/AutomaticRetryAttempts", 1344 getHostStateServiceName(computerSystemIndex), 1345 getHostStateObjectPath(computerSystemIndex), 1346 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1347 "RetryAttempts", 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 inline void setTrustedModuleRequiredToBootCallback( 1553 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1554 const uint64_t computerSystemIndex, const bool tpmRequired, 1555 const boost::system::error_code& ec, 1556 const dbus::utility::MapperGetSubTreeResponse& subtree) 1557 { 1558 if (ec) 1559 { 1560 BMCWEB_LOG_ERROR("DBUS response error on TPM.Policy GetSubTree{}", ec); 1561 messages::internalError(asyncResp->res); 1562 return; 1563 } 1564 if (subtree.empty()) 1565 { 1566 messages::propertyValueNotInList(asyncResp->res, "ComputerSystem", 1567 "TrustedModuleRequiredToBoot"); 1568 return; 1569 } 1570 1571 std::string path; 1572 std::string serv; 1573 1574 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 1575 { 1576 if (!indexMatchingSubTreeMapObjectPath(asyncResp, computerSystemIndex, 1577 subtree, path, serv)) 1578 { 1579 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1580 messages::internalError(asyncResp->res); 1581 return; 1582 } 1583 } 1584 else 1585 { 1586 // Make sure the Dbus response map has a service and objectPath 1587 // field 1588 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1589 { 1590 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1591 messages::internalError(asyncResp->res); 1592 return; 1593 } 1594 1595 path = subtree[0].first; 1596 serv = subtree[0].second.begin()->first; 1597 } 1598 1599 if (serv.empty()) 1600 { 1601 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!"); 1602 messages::internalError(asyncResp->res); 1603 return; 1604 } 1605 1606 // Valid TPM Enable object found, now setting the value 1607 setDbusProperty(asyncResp, "Boot/TrustedModuleRequiredToBoot", serv, path, 1608 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1609 tpmRequired); 1610 } 1611 1612 /** 1613 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1614 * TPM is required for booting the host. 1615 * 1616 * @param[in] asyncResp Shared pointer for generating response message. 1617 * @param[in] computerSystemIndex Index associated with the requested system 1618 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1619 * 1620 * @return None. 1621 */ 1622 inline void setTrustedModuleRequiredToBoot( 1623 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1624 const uint64_t computerSystemIndex, const bool tpmRequired) 1625 { 1626 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot."); 1627 constexpr std::array<std::string_view, 1> interfaces = { 1628 "xyz.openbmc_project.Control.TPM.Policy"}; 1629 dbus::utility::getSubTree( 1630 "/", 0, interfaces, 1631 std::bind_front(setTrustedModuleRequiredToBootCallback, asyncResp, 1632 computerSystemIndex, tpmRequired)); 1633 } 1634 1635 /** 1636 * @brief Sets boot properties into DBUS object(s). 1637 * 1638 * @param[in] asyncResp Shared pointer for generating response message. 1639 * @param[in] computerSystemIndex Index associated with the requested system 1640 * @param[in] bootType The boot type to set. 1641 * @return Integer error code. 1642 */ 1643 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1644 const uint64_t computerSystemIndex, 1645 const std::optional<std::string>& bootType) 1646 { 1647 std::string bootTypeStr; 1648 1649 if (!bootType) 1650 { 1651 return; 1652 } 1653 1654 // Source target specified 1655 BMCWEB_LOG_DEBUG("Boot type: {}", *bootType); 1656 // Figure out which DBUS interface and property to use 1657 if (*bootType == "Legacy") 1658 { 1659 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1660 } 1661 else if (*bootType == "UEFI") 1662 { 1663 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1664 } 1665 else 1666 { 1667 BMCWEB_LOG_DEBUG("Invalid property value for " 1668 "BootSourceOverrideMode: {}", 1669 *bootType); 1670 messages::propertyValueNotInList(asyncResp->res, *bootType, 1671 "BootSourceOverrideMode"); 1672 return; 1673 } 1674 1675 // Act on validated parameters 1676 BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr); 1677 1678 sdbusplus::message::object_path path("/xyz/openbmc_project/control/host" + 1679 std::to_string(computerSystemIndex)); 1680 path /= "boot"; 1681 setDbusProperty(asyncResp, "Boot/BootSourceOverrideMode", 1682 "xyz.openbmc_project.Settings", path, 1683 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1684 bootTypeStr); 1685 } 1686 1687 /** 1688 * @brief Sets boot properties into DBUS object(s). 1689 * 1690 * @param[in] asyncResp Shared pointer for generating response 1691 * message. 1692 * @param[in] computerSystemIndex Index associated with the requested system 1693 * @param[in] bootType The boot type to set. 1694 * @return Integer error code. 1695 */ 1696 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1697 const uint64_t computerSystemIndex, 1698 const std::optional<std::string>& bootEnable) 1699 { 1700 if (!bootEnable) 1701 { 1702 return; 1703 } 1704 // Source target specified 1705 BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable); 1706 1707 bool bootOverrideEnable = false; 1708 bool bootOverridePersistent = false; 1709 // Figure out which DBUS interface and property to use 1710 if (*bootEnable == "Disabled") 1711 { 1712 bootOverrideEnable = false; 1713 } 1714 else if (*bootEnable == "Once") 1715 { 1716 bootOverrideEnable = true; 1717 bootOverridePersistent = false; 1718 } 1719 else if (*bootEnable == "Continuous") 1720 { 1721 bootOverrideEnable = true; 1722 bootOverridePersistent = true; 1723 } 1724 else 1725 { 1726 BMCWEB_LOG_DEBUG( 1727 "Invalid property value for BootSourceOverrideEnabled: {}", 1728 *bootEnable); 1729 messages::propertyValueNotInList(asyncResp->res, *bootEnable, 1730 "BootSourceOverrideEnabled"); 1731 return; 1732 } 1733 1734 // Act on validated parameters 1735 BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable); 1736 1737 sdbusplus::message::object_path path("/xyz/openbmc_project/control/host" + 1738 std::to_string(computerSystemIndex)); 1739 path /= "boot"; 1740 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled", 1741 "xyz.openbmc_project.Settings", path, 1742 "xyz.openbmc_project.Object.Enable", "Enabled", 1743 bootOverrideEnable); 1744 1745 if (!bootOverrideEnable) 1746 { 1747 return; 1748 } 1749 1750 // In case boot override is enabled we need to set correct value for the 1751 // 'one_time' enable DBus interface 1752 BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}", 1753 bootOverridePersistent); 1754 1755 path /= "one_time"; 1756 setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled", 1757 "xyz.openbmc_project.Settings", path, 1758 "xyz.openbmc_project.Object.Enable", "Enabled", 1759 !bootOverridePersistent); 1760 } 1761 1762 /** 1763 * @brief Sets boot properties into DBUS object(s). 1764 * 1765 * @param[in] asyncResp Shared pointer for generating response message. 1766 * @param[in] computerSystemIndex Index associated with the requested system 1767 * @param[in] bootSource The boot source to set. 1768 * 1769 * @return Integer error code. 1770 */ 1771 inline void setBootModeOrSource( 1772 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1773 const uint64_t computerSystemIndex, 1774 const std::optional<std::string>& bootSource) 1775 { 1776 std::string bootSourceStr; 1777 std::string bootModeStr; 1778 1779 if (!bootSource) 1780 { 1781 return; 1782 } 1783 1784 // Source target specified 1785 BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource); 1786 // Figure out which DBUS interface and property to use 1787 if (assignBootParameters(asyncResp, *bootSource, bootSourceStr, 1788 bootModeStr) != 0) 1789 { 1790 BMCWEB_LOG_DEBUG( 1791 "Invalid property value for BootSourceOverrideTarget: {}", 1792 *bootSource); 1793 messages::propertyValueNotInList(asyncResp->res, *bootSource, 1794 "BootSourceTargetOverride"); 1795 return; 1796 } 1797 1798 // Act on validated parameters 1799 BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr); 1800 BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr); 1801 1802 sdbusplus::message::object_path path("/xyz/openbmc_project/control/host" + 1803 std::to_string(computerSystemIndex)); 1804 path /= "boot"; 1805 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget", 1806 "xyz.openbmc_project.Settings", path, 1807 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1808 bootSourceStr); 1809 setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget", 1810 "xyz.openbmc_project.Settings", path, 1811 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1812 bootModeStr); 1813 } 1814 1815 /** 1816 * @brief Sets Boot source override properties. 1817 * 1818 * @param[in] asyncResp Shared pointer for generating response message. 1819 * @param[in] computerSystemIndex Index associated with the requested system 1820 * @param[in] bootSource The boot source from incoming RF request. 1821 * @param[in] bootType The boot type from incoming RF request. 1822 * @param[in] bootEnable The boot override enable from incoming RF request. 1823 * 1824 * @return Integer error code. 1825 */ 1826 1827 inline void setBootProperties( 1828 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1829 const uint64_t computerSystemIndex, 1830 const std::optional<std::string>& bootSource, 1831 const std::optional<std::string>& bootType, 1832 const std::optional<std::string>& bootEnable) 1833 { 1834 BMCWEB_LOG_DEBUG("Set boot information."); 1835 1836 setBootModeOrSource(asyncResp, computerSystemIndex, bootSource); 1837 setBootType(asyncResp, computerSystemIndex, bootType); 1838 setBootEnable(asyncResp, computerSystemIndex, bootEnable); 1839 } 1840 1841 /** 1842 * @brief Sets AssetTag 1843 * 1844 * @param[in] asyncResp Shared pointer for generating response message. 1845 * @param[in] assetTag "AssetTag" from request. 1846 * 1847 * @return None. 1848 */ 1849 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1850 const std::string& assetTag) 1851 { 1852 constexpr std::array<std::string_view, 1> interfaces = { 1853 "xyz.openbmc_project.Inventory.Item.System"}; 1854 dbus::utility::getSubTree( 1855 "/xyz/openbmc_project/inventory", 0, interfaces, 1856 [asyncResp, 1857 assetTag](const boost::system::error_code& ec, 1858 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1859 if (ec) 1860 { 1861 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); 1862 messages::internalError(asyncResp->res); 1863 return; 1864 } 1865 if (subtree.empty()) 1866 { 1867 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!"); 1868 messages::internalError(asyncResp->res); 1869 return; 1870 } 1871 // Assume only 1 system D-Bus object 1872 // Throw an error if there is more than 1 1873 if (subtree.size() > 1) 1874 { 1875 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!"); 1876 messages::internalError(asyncResp->res); 1877 return; 1878 } 1879 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1880 { 1881 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!"); 1882 messages::internalError(asyncResp->res); 1883 return; 1884 } 1885 1886 const std::string& path = subtree[0].first; 1887 const std::string& service = subtree[0].second.begin()->first; 1888 1889 if (service.empty()) 1890 { 1891 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!"); 1892 messages::internalError(asyncResp->res); 1893 return; 1894 } 1895 1896 setDbusProperty(asyncResp, "AssetTag", service, path, 1897 "xyz.openbmc_project.Inventory.Decorator.AssetTag", 1898 "AssetTag", assetTag); 1899 }); 1900 } 1901 1902 /** 1903 * @brief Validate the specified stopBootOnFault is valid and return the 1904 * stopBootOnFault name associated with that string 1905 * 1906 * @param[in] stopBootOnFaultString String representing the desired 1907 * stopBootOnFault 1908 * 1909 * @return stopBootOnFault value or empty if incoming value is not valid 1910 */ 1911 inline std::optional<bool> validstopBootOnFault( 1912 const std::string& stopBootOnFaultString) 1913 { 1914 if (stopBootOnFaultString == "AnyFault") 1915 { 1916 return true; 1917 } 1918 1919 if (stopBootOnFaultString == "Never") 1920 { 1921 return false; 1922 } 1923 1924 return std::nullopt; 1925 } 1926 1927 /** 1928 * @brief Sets stopBootOnFault 1929 * 1930 * @param[in] asyncResp Shared pointer for generating response message. 1931 * @param[in] stopBootOnFault "StopBootOnFault" from request. 1932 * 1933 * @return None. 1934 */ 1935 inline void setStopBootOnFault( 1936 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1937 const std::string& stopBootOnFault) 1938 { 1939 BMCWEB_LOG_DEBUG("Set Stop Boot On Fault."); 1940 1941 std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault); 1942 if (!stopBootEnabled) 1943 { 1944 BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}", 1945 stopBootOnFault); 1946 messages::propertyValueNotInList(asyncResp->res, stopBootOnFault, 1947 "StopBootOnFault"); 1948 return; 1949 } 1950 1951 setDbusProperty(asyncResp, "Boot/StopBootOnFault", 1952 "xyz.openbmc_project.Settings", 1953 sdbusplus::message::object_path( 1954 "/xyz/openbmc_project/logging/settings"), 1955 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1956 *stopBootEnabled); 1957 } 1958 1959 /** 1960 * @brief Sets automaticRetry (Auto Reboot) 1961 * 1962 * @param[in] asyncResp Shared pointer for generating response message. 1963 * @param[in] computerSystemIndex Index associated with the requested system 1964 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1965 * 1966 * @return None. 1967 */ 1968 inline void setAutomaticRetry( 1969 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1970 const uint64_t computerSystemIndex, const std::string& automaticRetryConfig) 1971 { 1972 BMCWEB_LOG_DEBUG("Set Automatic Retry."); 1973 1974 // OpenBMC only supports "Disabled" and "RetryAttempts". 1975 bool autoRebootEnabled = false; 1976 1977 if (automaticRetryConfig == "Disabled") 1978 { 1979 autoRebootEnabled = false; 1980 } 1981 else if (automaticRetryConfig == "RetryAttempts") 1982 { 1983 autoRebootEnabled = true; 1984 } 1985 else 1986 { 1987 BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}", 1988 automaticRetryConfig); 1989 messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig, 1990 "AutomaticRetryConfig"); 1991 return; 1992 } 1993 1994 sdbusplus::message::object_path path("/xyz/openbmc_project/control/host" + 1995 std::to_string(computerSystemIndex)); 1996 path /= "auto_reboot"; 1997 setDbusProperty(asyncResp, "Boot/AutomaticRetryConfig", 1998 "xyz.openbmc_project.Settings", path, 1999 "xyz.openbmc_project.Control.Boot.RebootPolicy", 2000 "AutoReboot", autoRebootEnabled); 2001 } 2002 2003 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy) 2004 { 2005 if (policy == "AlwaysOn") 2006 { 2007 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"; 2008 } 2009 if (policy == "AlwaysOff") 2010 { 2011 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"; 2012 } 2013 if (policy == "LastState") 2014 { 2015 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"; 2016 } 2017 return ""; 2018 } 2019 2020 /** 2021 * @brief Sets power restore policy properties. 2022 * 2023 * @param[in] asyncResp Shared pointer for generating response message. 2024 * @param[in] computerSystemIndex Index associated with the requested system 2025 * @param[in] policy power restore policy properties from request. 2026 * 2027 * @return None. 2028 */ 2029 inline void setPowerRestorePolicy( 2030 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2031 const uint64_t computerSystemIndex, std::string_view policy) 2032 { 2033 BMCWEB_LOG_DEBUG("Set power restore policy."); 2034 2035 std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy); 2036 2037 if (powerRestorePolicy.empty()) 2038 { 2039 messages::propertyValueNotInList(asyncResp->res, policy, 2040 "PowerRestorePolicy"); 2041 return; 2042 } 2043 2044 sdbusplus::message::object_path path("/xyz/openbmc_project/control/host" + 2045 std::to_string(computerSystemIndex)); 2046 path /= "power_restore_policy"; 2047 setDbusProperty(asyncResp, "PowerRestorePolicy", 2048 "xyz.openbmc_project.Settings", path, 2049 "xyz.openbmc_project.Control.Power.RestorePolicy", 2050 "PowerRestorePolicy", powerRestorePolicy); 2051 } 2052 2053 /** 2054 * @brief Retrieves provisioning status 2055 * 2056 * @param[in] asyncResp Shared pointer for completing asynchronous 2057 * calls. 2058 * 2059 * @return None. 2060 */ 2061 inline void getProvisioningStatus( 2062 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2063 { 2064 BMCWEB_LOG_DEBUG("Get OEM information."); 2065 dbus::utility::getAllProperties( 2066 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 2067 "xyz.openbmc_project.PFR.Attributes", 2068 [asyncResp](const boost::system::error_code& ec, 2069 const dbus::utility::DBusPropertiesMap& propertiesList) { 2070 nlohmann::json& oemPFR = 2071 asyncResp->res 2072 .jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 2073 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 2074 "#OpenBMCComputerSystem.v1_0_0.OpenBmc"; 2075 oemPFR["@odata.type"] = 2076 "#OpenBMCComputerSystem.FirmwareProvisioning"; 2077 2078 if (ec) 2079 { 2080 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2081 // not an error, don't have to have the interface 2082 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2083 FirmwareProvisioningStatus::NotProvisioned; 2084 return; 2085 } 2086 2087 const bool* provState = nullptr; 2088 const bool* lockState = nullptr; 2089 2090 const bool success = sdbusplus::unpackPropertiesNoThrow( 2091 dbus_utils::UnpackErrorPrinter(), propertiesList, 2092 "UfmProvisioned", provState, "UfmLocked", lockState); 2093 2094 if (!success) 2095 { 2096 messages::internalError(asyncResp->res); 2097 return; 2098 } 2099 2100 if ((provState == nullptr) || (lockState == nullptr)) 2101 { 2102 BMCWEB_LOG_DEBUG("Unable to get PFR attributes."); 2103 messages::internalError(asyncResp->res); 2104 return; 2105 } 2106 2107 if (*provState) 2108 { 2109 if (*lockState) 2110 { 2111 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2112 FirmwareProvisioningStatus::ProvisionedAndLocked; 2113 } 2114 else 2115 { 2116 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2117 FirmwareProvisioningStatus::ProvisionedButNotLocked; 2118 } 2119 } 2120 else 2121 { 2122 oemPFR["ProvisioningStatus"] = open_bmc_computer_system:: 2123 FirmwareProvisioningStatus::NotProvisioned; 2124 } 2125 }); 2126 } 2127 2128 /** 2129 * @brief Translate the PowerMode string to enum value 2130 * 2131 * @param[in] modeString PowerMode string to be translated 2132 * 2133 * @return PowerMode enum 2134 */ 2135 inline computer_system::PowerMode translatePowerModeString( 2136 const std::string& modeString) 2137 { 2138 using PowerMode = computer_system::PowerMode; 2139 2140 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 2141 { 2142 return PowerMode::Static; 2143 } 2144 if (modeString == 2145 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 2146 { 2147 return PowerMode::MaximumPerformance; 2148 } 2149 if (modeString == 2150 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 2151 { 2152 return PowerMode::PowerSaving; 2153 } 2154 if (modeString == 2155 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance") 2156 { 2157 return PowerMode::BalancedPerformance; 2158 } 2159 if (modeString == 2160 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance") 2161 { 2162 return PowerMode::EfficiencyFavorPerformance; 2163 } 2164 if (modeString == 2165 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower") 2166 { 2167 return PowerMode::EfficiencyFavorPower; 2168 } 2169 if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 2170 { 2171 return PowerMode::OEM; 2172 } 2173 // Any other values would be invalid 2174 BMCWEB_LOG_ERROR("PowerMode value was not valid: {}", modeString); 2175 return PowerMode::Invalid; 2176 } 2177 2178 inline void afterGetPowerMode( 2179 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2180 const boost::system::error_code& ec, 2181 const dbus::utility::DBusPropertiesMap& properties) 2182 { 2183 if (ec) 2184 { 2185 BMCWEB_LOG_ERROR("DBUS response error on PowerMode GetAll: {}", ec); 2186 messages::internalError(asyncResp->res); 2187 return; 2188 } 2189 2190 std::string powerMode; 2191 const std::vector<std::string>* allowedModes = nullptr; 2192 const bool success = sdbusplus::unpackPropertiesNoThrow( 2193 dbus_utils::UnpackErrorPrinter(), properties, "PowerMode", powerMode, 2194 "AllowedPowerModes", allowedModes); 2195 2196 if (!success) 2197 { 2198 messages::internalError(asyncResp->res); 2199 return; 2200 } 2201 2202 nlohmann::json::array_t modeList; 2203 if (allowedModes == nullptr) 2204 { 2205 modeList.emplace_back("Static"); 2206 modeList.emplace_back("MaximumPerformance"); 2207 modeList.emplace_back("PowerSaving"); 2208 } 2209 else 2210 { 2211 for (const auto& aMode : *allowedModes) 2212 { 2213 computer_system::PowerMode modeValue = 2214 translatePowerModeString(aMode); 2215 if (modeValue == computer_system::PowerMode::Invalid) 2216 { 2217 messages::internalError(asyncResp->res); 2218 continue; 2219 } 2220 modeList.emplace_back(modeValue); 2221 } 2222 } 2223 asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = modeList; 2224 2225 BMCWEB_LOG_DEBUG("Current power mode: {}", powerMode); 2226 const computer_system::PowerMode modeValue = 2227 translatePowerModeString(powerMode); 2228 if (modeValue == computer_system::PowerMode::Invalid) 2229 { 2230 messages::internalError(asyncResp->res); 2231 return; 2232 } 2233 asyncResp->res.jsonValue["PowerMode"] = modeValue; 2234 } 2235 /** 2236 * @brief Retrieves system power mode 2237 * 2238 * @param[in] asyncResp Shared pointer for generating response message. 2239 * 2240 * @return None. 2241 */ 2242 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2243 { 2244 BMCWEB_LOG_DEBUG("Get power mode."); 2245 2246 // Get Power Mode object path: 2247 constexpr std::array<std::string_view, 1> interfaces = { 2248 "xyz.openbmc_project.Control.Power.Mode"}; 2249 dbus::utility::getSubTree( 2250 "/", 0, interfaces, 2251 [asyncResp](const boost::system::error_code& ec, 2252 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2253 if (ec) 2254 { 2255 BMCWEB_LOG_DEBUG( 2256 "DBUS response error on Power.Mode GetSubTree {}", ec); 2257 // This is an optional D-Bus object so just return if 2258 // error occurs 2259 return; 2260 } 2261 if (subtree.empty()) 2262 { 2263 // As noted above, this is an optional interface so just return 2264 // if there is no instance found 2265 return; 2266 } 2267 if (subtree.size() > 1) 2268 { 2269 // More then one PowerMode object is not supported and is an 2270 // error 2271 BMCWEB_LOG_DEBUG( 2272 "Found more than 1 system D-Bus Power.Mode objects: {}", 2273 subtree.size()); 2274 messages::internalError(asyncResp->res); 2275 return; 2276 } 2277 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2278 { 2279 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2280 messages::internalError(asyncResp->res); 2281 return; 2282 } 2283 const std::string& path = subtree[0].first; 2284 const std::string& service = subtree[0].second.begin()->first; 2285 if (service.empty()) 2286 { 2287 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2288 messages::internalError(asyncResp->res); 2289 return; 2290 } 2291 2292 // Valid Power Mode object found, now read the mode properties 2293 dbus::utility::getAllProperties( 2294 *crow::connections::systemBus, service, path, 2295 "xyz.openbmc_project.Control.Power.Mode", 2296 [asyncResp]( 2297 const boost::system::error_code& ec2, 2298 const dbus::utility::DBusPropertiesMap& properties) { 2299 afterGetPowerMode(asyncResp, ec2, properties); 2300 }); 2301 }); 2302 } 2303 2304 /** 2305 * @brief Validate the specified mode is valid and return the PowerMode 2306 * name associated with that string 2307 * 2308 * @param[in] asyncResp Shared pointer for generating response message. 2309 * @param[in] modeValue String representing the desired PowerMode 2310 * 2311 * @return PowerMode value or empty string if mode is not valid 2312 */ 2313 inline std::string validatePowerMode( 2314 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2315 const nlohmann::json& modeValue) 2316 { 2317 using PowerMode = computer_system::PowerMode; 2318 std::string mode; 2319 2320 if (modeValue == PowerMode::Static) 2321 { 2322 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2323 } 2324 else if (modeValue == PowerMode::MaximumPerformance) 2325 { 2326 mode = 2327 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2328 } 2329 else if (modeValue == PowerMode::PowerSaving) 2330 { 2331 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2332 } 2333 else if (modeValue == PowerMode::BalancedPerformance) 2334 { 2335 mode = 2336 "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance"; 2337 } 2338 else if (modeValue == PowerMode::EfficiencyFavorPerformance) 2339 { 2340 mode = 2341 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance"; 2342 } 2343 else if (modeValue == PowerMode::EfficiencyFavorPower) 2344 { 2345 mode = 2346 "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower"; 2347 } 2348 else 2349 { 2350 messages::propertyValueNotInList(asyncResp->res, modeValue.dump(), 2351 "PowerMode"); 2352 } 2353 return mode; 2354 } 2355 2356 /** 2357 * @brief Sets system power mode. 2358 * 2359 * @param[in] asyncResp Shared pointer for generating response message. 2360 * @param[in] pmode System power mode from request. 2361 * 2362 * @return None. 2363 */ 2364 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2365 const std::string& pmode) 2366 { 2367 BMCWEB_LOG_DEBUG("Set power mode."); 2368 2369 std::string powerMode = validatePowerMode(asyncResp, pmode); 2370 if (powerMode.empty()) 2371 { 2372 return; 2373 } 2374 2375 // Get Power Mode object path: 2376 constexpr std::array<std::string_view, 1> interfaces = { 2377 "xyz.openbmc_project.Control.Power.Mode"}; 2378 dbus::utility::getSubTree( 2379 "/", 0, interfaces, 2380 [asyncResp, 2381 powerMode](const boost::system::error_code& ec, 2382 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2383 if (ec) 2384 { 2385 BMCWEB_LOG_ERROR( 2386 "DBUS response error on Power.Mode GetSubTree {}", ec); 2387 // This is an optional D-Bus object, but user attempted to patch 2388 messages::internalError(asyncResp->res); 2389 return; 2390 } 2391 if (subtree.empty()) 2392 { 2393 // This is an optional D-Bus object, but user attempted to patch 2394 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2395 "PowerMode"); 2396 return; 2397 } 2398 if (subtree.size() > 1) 2399 { 2400 // More then one PowerMode object is not supported and is an 2401 // error 2402 BMCWEB_LOG_DEBUG( 2403 "Found more than 1 system D-Bus Power.Mode objects: {}", 2404 subtree.size()); 2405 messages::internalError(asyncResp->res); 2406 return; 2407 } 2408 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2409 { 2410 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2411 messages::internalError(asyncResp->res); 2412 return; 2413 } 2414 const std::string& path = subtree[0].first; 2415 const std::string& service = subtree[0].second.begin()->first; 2416 if (service.empty()) 2417 { 2418 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2419 messages::internalError(asyncResp->res); 2420 return; 2421 } 2422 2423 BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path); 2424 2425 // Set the Power Mode property 2426 setDbusProperty(asyncResp, "PowerMode", service, path, 2427 "xyz.openbmc_project.Control.Power.Mode", 2428 "PowerMode", powerMode); 2429 }); 2430 } 2431 2432 /** 2433 * @brief Translates watchdog timeout action DBUS property value to redfish. 2434 * 2435 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2436 * 2437 * @return Returns as a string, the timeout action in Redfish terms. If 2438 * translation cannot be done, returns an empty string. 2439 */ 2440 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2441 { 2442 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2443 { 2444 return "None"; 2445 } 2446 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2447 { 2448 return "ResetSystem"; 2449 } 2450 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2451 { 2452 return "PowerDown"; 2453 } 2454 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2455 { 2456 return "PowerCycle"; 2457 } 2458 2459 return ""; 2460 } 2461 2462 /** 2463 *@brief Translates timeout action from Redfish to DBUS property value. 2464 * 2465 *@param[in] rfAction The timeout action in Redfish. 2466 * 2467 *@return Returns as a string, the time_out action as expected by DBUS. 2468 *If translation cannot be done, returns an empty string. 2469 */ 2470 2471 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2472 { 2473 if (rfAction == "None") 2474 { 2475 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2476 } 2477 if (rfAction == "PowerCycle") 2478 { 2479 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2480 } 2481 if (rfAction == "PowerDown") 2482 { 2483 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2484 } 2485 if (rfAction == "ResetSystem") 2486 { 2487 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2488 } 2489 2490 return ""; 2491 } 2492 2493 /** 2494 * @brief Retrieves host watchdog timer properties over DBUS 2495 * 2496 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2497 * 2498 * @return None. 2499 */ 2500 inline void getHostWatchdogTimer( 2501 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2502 { 2503 BMCWEB_LOG_DEBUG("Get host watchodg"); 2504 dbus::utility::getAllProperties( 2505 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2506 "xyz.openbmc_project.State.Watchdog", 2507 [asyncResp](const boost::system::error_code& ec, 2508 const dbus::utility::DBusPropertiesMap& properties) { 2509 if (ec) 2510 { 2511 // watchdog service is stopped 2512 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2513 return; 2514 } 2515 2516 BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size()); 2517 2518 nlohmann::json& hostWatchdogTimer = 2519 asyncResp->res.jsonValue["HostWatchdogTimer"]; 2520 2521 // watchdog service is running/enabled 2522 hostWatchdogTimer["Status"]["State"] = resource::State::Enabled; 2523 2524 const bool* enabled = nullptr; 2525 const std::string* expireAction = nullptr; 2526 2527 const bool success = sdbusplus::unpackPropertiesNoThrow( 2528 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", 2529 enabled, "ExpireAction", expireAction); 2530 2531 if (!success) 2532 { 2533 messages::internalError(asyncResp->res); 2534 return; 2535 } 2536 2537 if (enabled != nullptr) 2538 { 2539 hostWatchdogTimer["FunctionEnabled"] = *enabled; 2540 } 2541 2542 if (expireAction != nullptr) 2543 { 2544 std::string action = dbusToRfWatchdogAction(*expireAction); 2545 if (action.empty()) 2546 { 2547 messages::internalError(asyncResp->res); 2548 return; 2549 } 2550 hostWatchdogTimer["TimeoutAction"] = action; 2551 } 2552 }); 2553 } 2554 2555 /** 2556 * @brief Sets Host WatchDog Timer properties. 2557 * 2558 * @param[in] asyncResp Shared pointer for generating response message. 2559 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2560 * RF request. 2561 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2562 * 2563 * @return None. 2564 */ 2565 inline void setWDTProperties( 2566 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2567 const std::optional<bool> wdtEnable, 2568 const std::optional<std::string>& wdtTimeOutAction) 2569 { 2570 BMCWEB_LOG_DEBUG("Set host watchdog"); 2571 2572 if (wdtTimeOutAction) 2573 { 2574 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2575 // check if TimeOut Action is Valid 2576 if (wdtTimeOutActStr.empty()) 2577 { 2578 BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}", 2579 *wdtTimeOutAction); 2580 messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction, 2581 "TimeoutAction"); 2582 return; 2583 } 2584 2585 setDbusProperty(asyncResp, "HostWatchdogTimer/TimeoutAction", 2586 "xyz.openbmc_project.Watchdog", 2587 sdbusplus::message::object_path( 2588 "/xyz/openbmc_project/watchdog/host0"), 2589 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2590 wdtTimeOutActStr); 2591 } 2592 2593 if (wdtEnable) 2594 { 2595 setDbusProperty(asyncResp, "HostWatchdogTimer/FunctionEnabled", 2596 "xyz.openbmc_project.Watchdog", 2597 sdbusplus::message::object_path( 2598 "/xyz/openbmc_project/watchdog/host0"), 2599 "xyz.openbmc_project.State.Watchdog", "Enabled", 2600 *wdtEnable); 2601 } 2602 } 2603 2604 /** 2605 * @brief Parse the Idle Power Saver properties into json 2606 * 2607 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2608 * @param[in] properties IPS property data from DBus. 2609 * 2610 * @return true if successful 2611 */ 2612 inline bool parseIpsProperties( 2613 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2614 const dbus::utility::DBusPropertiesMap& properties) 2615 { 2616 const bool* enabled = nullptr; 2617 const uint8_t* enterUtilizationPercent = nullptr; 2618 const uint64_t* enterDwellTime = nullptr; 2619 const uint8_t* exitUtilizationPercent = nullptr; 2620 const uint64_t* exitDwellTime = nullptr; 2621 2622 const bool success = sdbusplus::unpackPropertiesNoThrow( 2623 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2624 "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime", 2625 enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent, 2626 "ExitDwellTime", exitDwellTime); 2627 2628 if (!success) 2629 { 2630 return false; 2631 } 2632 2633 if (enabled != nullptr) 2634 { 2635 asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled; 2636 } 2637 2638 if (enterUtilizationPercent != nullptr) 2639 { 2640 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] = 2641 *enterUtilizationPercent; 2642 } 2643 2644 if (enterDwellTime != nullptr) 2645 { 2646 const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime); 2647 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2648 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2649 .count(); 2650 } 2651 2652 if (exitUtilizationPercent != nullptr) 2653 { 2654 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] = 2655 *exitUtilizationPercent; 2656 } 2657 2658 if (exitDwellTime != nullptr) 2659 { 2660 const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime); 2661 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2662 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2663 .count(); 2664 } 2665 2666 return true; 2667 } 2668 2669 /** 2670 * @brief Retrieves idle power saver properties over DBUS 2671 * 2672 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2673 * 2674 * @return None. 2675 */ 2676 inline void getIdlePowerSaver( 2677 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2678 { 2679 BMCWEB_LOG_DEBUG("Get idle power saver parameters"); 2680 2681 // Get IdlePowerSaver object path: 2682 constexpr std::array<std::string_view, 1> interfaces = { 2683 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2684 dbus::utility::getSubTree( 2685 "/", 0, interfaces, 2686 [asyncResp](const boost::system::error_code& ec, 2687 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2688 if (ec) 2689 { 2690 BMCWEB_LOG_ERROR( 2691 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2692 ec); 2693 messages::internalError(asyncResp->res); 2694 return; 2695 } 2696 if (subtree.empty()) 2697 { 2698 // This is an optional interface so just return 2699 // if there is no instance found 2700 BMCWEB_LOG_DEBUG("No instances found"); 2701 return; 2702 } 2703 if (subtree.size() > 1) 2704 { 2705 // More then one PowerIdlePowerSaver object is not supported and 2706 // is an error 2707 BMCWEB_LOG_DEBUG( 2708 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}", 2709 subtree.size()); 2710 messages::internalError(asyncResp->res); 2711 return; 2712 } 2713 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2714 { 2715 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2716 messages::internalError(asyncResp->res); 2717 return; 2718 } 2719 const std::string& path = subtree[0].first; 2720 const std::string& service = subtree[0].second.begin()->first; 2721 if (service.empty()) 2722 { 2723 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2724 messages::internalError(asyncResp->res); 2725 return; 2726 } 2727 2728 // Valid IdlePowerSaver object found, now read the current values 2729 dbus::utility::getAllProperties( 2730 *crow::connections::systemBus, service, path, 2731 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2732 [asyncResp]( 2733 const boost::system::error_code& ec2, 2734 const dbus::utility::DBusPropertiesMap& properties) { 2735 if (ec2) 2736 { 2737 BMCWEB_LOG_ERROR( 2738 "DBUS response error on IdlePowerSaver GetAll: {}", 2739 ec2); 2740 messages::internalError(asyncResp->res); 2741 return; 2742 } 2743 2744 if (!parseIpsProperties(asyncResp, properties)) 2745 { 2746 messages::internalError(asyncResp->res); 2747 return; 2748 } 2749 }); 2750 }); 2751 2752 BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters"); 2753 } 2754 2755 /** 2756 * @brief Sets Idle Power Saver properties. 2757 * 2758 * @param[in] asyncResp Shared pointer for generating response message. 2759 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2760 * RF request. 2761 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2762 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2763 * before entering idle state. 2764 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2765 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2766 * before exiting idle state 2767 * 2768 * @return None. 2769 */ 2770 inline void setIdlePowerSaver( 2771 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2772 const std::optional<bool> ipsEnable, 2773 const std::optional<uint8_t> ipsEnterUtil, 2774 const std::optional<uint64_t> ipsEnterTime, 2775 const std::optional<uint8_t> ipsExitUtil, 2776 const std::optional<uint64_t> ipsExitTime) 2777 { 2778 BMCWEB_LOG_DEBUG("Set idle power saver properties"); 2779 2780 // Get IdlePowerSaver object path: 2781 constexpr std::array<std::string_view, 1> interfaces = { 2782 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2783 dbus::utility::getSubTree( 2784 "/", 0, interfaces, 2785 [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2786 ipsExitTime](const boost::system::error_code& ec, 2787 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2788 if (ec) 2789 { 2790 BMCWEB_LOG_ERROR( 2791 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2792 ec); 2793 messages::internalError(asyncResp->res); 2794 return; 2795 } 2796 if (subtree.empty()) 2797 { 2798 // This is an optional D-Bus object, but user attempted to patch 2799 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2800 "IdlePowerSaver"); 2801 return; 2802 } 2803 if (subtree.size() > 1) 2804 { 2805 // More then one PowerIdlePowerSaver object is not supported and 2806 // is an error 2807 BMCWEB_LOG_DEBUG( 2808 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}", 2809 subtree.size()); 2810 messages::internalError(asyncResp->res); 2811 return; 2812 } 2813 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2814 { 2815 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2816 messages::internalError(asyncResp->res); 2817 return; 2818 } 2819 const std::string& path = subtree[0].first; 2820 const std::string& service = subtree[0].second.begin()->first; 2821 if (service.empty()) 2822 { 2823 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2824 messages::internalError(asyncResp->res); 2825 return; 2826 } 2827 2828 // Valid Power IdlePowerSaver object found, now set any values that 2829 // need to be updated 2830 2831 if (ipsEnable) 2832 { 2833 setDbusProperty( 2834 asyncResp, "IdlePowerSaver/Enabled", service, path, 2835 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2836 "Enabled", *ipsEnable); 2837 } 2838 if (ipsEnterUtil) 2839 { 2840 setDbusProperty( 2841 asyncResp, "IdlePowerSaver/EnterUtilizationPercent", 2842 service, path, 2843 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2844 "EnterUtilizationPercent", *ipsEnterUtil); 2845 } 2846 if (ipsEnterTime) 2847 { 2848 // Convert from seconds into milliseconds for DBus 2849 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2850 setDbusProperty( 2851 asyncResp, "IdlePowerSaver/EnterDwellTimeSeconds", service, 2852 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2853 "EnterDwellTime", timeMilliseconds); 2854 } 2855 if (ipsExitUtil) 2856 { 2857 setDbusProperty( 2858 asyncResp, "IdlePowerSaver/ExitUtilizationPercent", service, 2859 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2860 "ExitUtilizationPercent", *ipsExitUtil); 2861 } 2862 if (ipsExitTime) 2863 { 2864 // Convert from seconds into milliseconds for DBus 2865 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2866 setDbusProperty( 2867 asyncResp, "IdlePowerSaver/ExitDwellTimeSeconds", service, 2868 path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2869 "ExitDwellTime", timeMilliseconds); 2870 } 2871 }); 2872 2873 BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters"); 2874 } 2875 2876 inline void handleComputerSystemCollectionHead( 2877 crow::App& app, const crow::Request& req, 2878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2879 { 2880 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2881 { 2882 return; 2883 } 2884 asyncResp->res.addHeader( 2885 boost::beast::http::field::link, 2886 "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby"); 2887 } 2888 2889 inline void handleComputerSystemCollectionGet( 2890 crow::App& app, const crow::Request& req, 2891 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2892 { 2893 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2894 { 2895 return; 2896 } 2897 2898 asyncResp->res.addHeader( 2899 boost::beast::http::field::link, 2900 "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby"); 2901 asyncResp->res.jsonValue["@odata.type"] = 2902 "#ComputerSystemCollection.ComputerSystemCollection"; 2903 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2904 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2905 2906 getSystemCollectionMembers(asyncResp); 2907 } 2908 2909 /** 2910 * Function transceives data with dbus directly. 2911 */ 2912 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2913 { 2914 constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2915 constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2916 constexpr const char* interfaceName = 2917 "xyz.openbmc_project.Control.Host.NMI"; 2918 constexpr const char* method = "NMI"; 2919 2920 dbus::utility::async_method_call( 2921 asyncResp, 2922 [asyncResp](const boost::system::error_code& ec) { 2923 if (ec) 2924 { 2925 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec); 2926 messages::internalError(asyncResp->res); 2927 return; 2928 } 2929 messages::success(asyncResp->res); 2930 }, 2931 serviceName, objectPath, interfaceName, method); 2932 } 2933 2934 inline void handleComputerSystemResetActionPost( 2935 crow::App& app, const crow::Request& req, 2936 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2937 const std::string& systemName) 2938 { 2939 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2940 { 2941 return; 2942 } 2943 2944 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 2945 { 2946 if (systemName == "hypervisor") 2947 { 2948 handleHypervisorSystemResetPost(req, asyncResp); 2949 return; 2950 } 2951 } 2952 2953 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 2954 { 2955 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2956 systemName); 2957 return; 2958 } 2959 if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 2960 { 2961 // Option currently returns no systems. TBD 2962 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2963 systemName); 2964 return; 2965 } 2966 std::string resetType; 2967 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 2968 { 2969 return; 2970 } 2971 2972 // Get the command and host vs. chassis 2973 std::string command; 2974 bool hostCommand = true; 2975 if ((resetType == "On") || (resetType == "ForceOn")) 2976 { 2977 command = "xyz.openbmc_project.State.Host.Transition.On"; 2978 hostCommand = true; 2979 } 2980 else if (resetType == "ForceOff") 2981 { 2982 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2983 hostCommand = false; 2984 } 2985 else if (resetType == "ForceRestart") 2986 { 2987 command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2988 hostCommand = true; 2989 } 2990 else if (resetType == "GracefulShutdown") 2991 { 2992 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2993 hostCommand = true; 2994 } 2995 else if (resetType == "GracefulRestart") 2996 { 2997 command = 2998 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2999 hostCommand = true; 3000 } 3001 else if (resetType == "PowerCycle") 3002 { 3003 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 3004 hostCommand = true; 3005 } 3006 else if (resetType == "Nmi") 3007 { 3008 doNMI(asyncResp); 3009 return; 3010 } 3011 else 3012 { 3013 messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); 3014 return; 3015 } 3016 sdbusplus::message::object_path statePath("/xyz/openbmc_project/state"); 3017 3018 if (hostCommand) 3019 { 3020 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Host", 3021 statePath / "host0", "xyz.openbmc_project.State.Host", 3022 "RequestedHostTransition", command); 3023 } 3024 else 3025 { 3026 setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Chassis", 3027 statePath / "chassis0", 3028 "xyz.openbmc_project.State.Chassis", 3029 "RequestedPowerTransition", command); 3030 } 3031 } 3032 3033 inline void handleComputerSystemHead( 3034 App& app, const crow::Request& req, 3035 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3036 const std::string& /*systemName*/) 3037 { 3038 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3039 { 3040 return; 3041 } 3042 3043 asyncResp->res.addHeader( 3044 boost::beast::http::field::link, 3045 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3046 } 3047 3048 inline void afterPortRequest( 3049 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3050 const boost::system::error_code& ec, 3051 const std::vector<std::tuple<std::string, std::string, bool>>& socketData) 3052 { 3053 if (ec) 3054 { 3055 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 3056 messages::internalError(asyncResp->res); 3057 return; 3058 } 3059 for (const auto& data : socketData) 3060 { 3061 const std::string& socketPath = get<0>(data); 3062 const std::string& protocolName = get<1>(data); 3063 bool isProtocolEnabled = get<2>(data); 3064 nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"]; 3065 dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled; 3066 // need to retrieve port number for 3067 // obmc-console-ssh service 3068 if (protocolName == "SSH") 3069 { 3070 getPortNumber(socketPath, [asyncResp, protocolName]( 3071 const boost::system::error_code& ec1, 3072 int portNumber) { 3073 if (ec1) 3074 { 3075 BMCWEB_LOG_ERROR("DBUS response error {}", ec1); 3076 messages::internalError(asyncResp->res); 3077 return; 3078 } 3079 nlohmann::json& dataJson1 = 3080 asyncResp->res.jsonValue["SerialConsole"]; 3081 dataJson1[protocolName]["Port"] = portNumber; 3082 }); 3083 } 3084 } 3085 } 3086 3087 /** 3088 * @brief process the GET request after getting the computerSystemIndex 3089 * 3090 * @param[in] asyncResp Shared pointer for completing asynchronous 3091 * calls 3092 * @param[in] systemName Name of the requested system 3093 * @param[in] computerSystemIndex Index associated with the requested system 3094 * 3095 * @return None 3096 */ 3097 inline void processComputerSystemGet( 3098 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3099 const std::string& systemName, const uint64_t computerSystemIndex) 3100 { 3101 asyncResp->res.addHeader( 3102 boost::beast::http::field::link, 3103 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3104 asyncResp->res.jsonValue["@odata.type"] = 3105 "#ComputerSystem.v1_22_0.ComputerSystem"; 3106 asyncResp->res.jsonValue["Name"] = systemName; 3107 asyncResp->res.jsonValue["Id"] = systemName; 3108 asyncResp->res.jsonValue["SystemType"] = 3109 computer_system::SystemType::Physical; 3110 asyncResp->res.jsonValue["Description"] = "Computer System"; 3111 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 3112 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 3113 double(0); 3114 asyncResp->res.jsonValue["@odata.id"] = 3115 boost::urls::format("/redfish/v1/Systems/{}", systemName); 3116 3117 // Currently not supported on multi-host. TBD 3118 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3119 { 3120 asyncResp->res.jsonValue["Bios"]["@odata.id"] = 3121 boost::urls::format("/redfish/v1/Systems/{}/Bios", systemName); 3122 asyncResp->res.jsonValue["Processors"]["@odata.id"] = 3123 boost::urls::format("/redfish/v1/Systems/{}/Processors", 3124 systemName); 3125 asyncResp->res.jsonValue["Memory"]["@odata.id"] = 3126 boost::urls::format("/redfish/v1/Systems/{}/Memory", systemName); 3127 asyncResp->res.jsonValue["Storage"]["@odata.id"] = 3128 boost::urls::format("/redfish/v1/Systems/{}/Storage", systemName); 3129 asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = 3130 boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters", 3131 systemName); 3132 } 3133 3134 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = 3135 boost::urls::format( 3136 "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset", systemName); 3137 asyncResp->res 3138 .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = 3139 boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo", 3140 systemName); 3141 3142 asyncResp->res.jsonValue["LogServices"]["@odata.id"] = 3143 boost::urls::format("/redfish/v1/Systems/{}/LogServices", systemName); 3144 3145 nlohmann::json::array_t managedBy; 3146 nlohmann::json& manager = managedBy.emplace_back(); 3147 manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 3148 BMCWEB_REDFISH_MANAGER_URI_NAME); 3149 asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 3150 asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 3151 asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 3152 3153 // Fill in SerialConsole info 3154 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 3155 asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true; 3156 3157 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true; 3158 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; 3159 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = 3160 "Press ~. to exit console"; 3161 getPortStatusAndPath(std::span{protocolToDBusForSystems}, 3162 std::bind_front(afterPortRequest, asyncResp)); 3163 3164 if constexpr (BMCWEB_KVM) 3165 { 3166 // Fill in GraphicalConsole info 3167 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 3168 asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 3169 4; 3170 asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = 3171 nlohmann::json::array_t({"KVMIP"}); 3172 } 3173 3174 systems_utils::getValidSystemsPath( 3175 asyncResp, systemName, 3176 [asyncResp, 3177 systemName](const std::optional<std::string>& validSystemsPath) { 3178 if (validSystemsPath) 3179 { 3180 getLocationIndicatorActive(asyncResp, *validSystemsPath); 3181 } 3182 }); 3183 3184 if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 3185 { 3186 getIndicatorLedState(asyncResp); 3187 } 3188 3189 // Currently not supported on multi-host. 3190 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3191 { 3192 getComputerSystem(asyncResp); 3193 // Todo: chassis matching could be handled by patch 3194 // https://gerrit.openbmc.org/c/openbmc/bmcweb/+/60793 3195 getMainChassisId( 3196 asyncResp, [](const std::string& chassisId, 3197 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 3198 nlohmann::json::array_t chassisArray; 3199 nlohmann::json& chassis = chassisArray.emplace_back(); 3200 chassis["@odata.id"] = 3201 boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 3202 aRsp->res.jsonValue["Links"]["Chassis"] = 3203 std::move(chassisArray); 3204 }); 3205 3206 pcie_util::getPCIeDeviceList( 3207 asyncResp, nlohmann::json::json_pointer("/PCIeDevices")); 3208 } 3209 getHostState(asyncResp, computerSystemIndex); 3210 getBootProperties(asyncResp, computerSystemIndex); 3211 getBootProgress(asyncResp, computerSystemIndex); 3212 getBootProgressLastStateTime(asyncResp, computerSystemIndex); 3213 getHostWatchdogTimer(asyncResp); 3214 getPowerRestorePolicy(asyncResp, computerSystemIndex); 3215 getStopBootOnFault(asyncResp); 3216 getAutomaticRetryPolicy(asyncResp, computerSystemIndex); 3217 getLastResetTime(asyncResp, computerSystemIndex); 3218 if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE) 3219 { 3220 getProvisioningStatus(asyncResp); 3221 } 3222 getTrustedModuleRequiredToBoot(asyncResp, computerSystemIndex); 3223 getPowerMode(asyncResp); 3224 getIdlePowerSaver(asyncResp); 3225 } 3226 3227 inline void handleComputerSystemGet( 3228 crow::App& app, const crow::Request& req, 3229 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3230 const std::string& systemName) 3231 { 3232 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3233 { 3234 return; 3235 } 3236 3237 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 3238 { 3239 if (systemName == "hypervisor") 3240 { 3241 handleHypervisorSystemGet(asyncResp); 3242 return; 3243 } 3244 } 3245 3246 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3247 { 3248 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3249 { 3250 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3251 systemName); 3252 return; 3253 } 3254 } 3255 3256 BMCWEB_LOG_DEBUG("requested system = {}", systemName); 3257 getComputerSystemIndex( 3258 asyncResp, systemName, 3259 std::bind_front(processComputerSystemGet, asyncResp, systemName)); 3260 } 3261 3262 struct PatchParams 3263 { 3264 std::optional<bool> locationIndicatorActive; 3265 std::optional<std::string> indicatorLed; 3266 std::optional<std::string> assetTag; 3267 std::optional<std::string> powerRestorePolicy; 3268 std::optional<std::string> powerMode; 3269 std::optional<bool> wdtEnable; 3270 std::optional<std::string> wdtTimeOutAction; 3271 std::optional<std::string> bootSource; 3272 std::optional<std::string> bootType; 3273 std::optional<std::string> bootEnable; 3274 std::optional<std::string> bootAutomaticRetry; 3275 std::optional<uint32_t> bootAutomaticRetryAttempts; 3276 std::optional<bool> bootTrustedModuleRequired; 3277 std::optional<std::string> stopBootOnFault; 3278 std::optional<bool> ipsEnable; 3279 std::optional<uint8_t> ipsEnterUtil; 3280 std::optional<uint64_t> ipsEnterTime; 3281 std::optional<uint8_t> ipsExitUtil; 3282 std::optional<uint64_t> ipsExitTime; 3283 }; 3284 3285 /** 3286 * @brief process the POST request after getting the computerSystemIndex 3287 * 3288 * @param[in] asyncResp Shared pointer for completing asynchronous 3289 * calls 3290 * @param[in] patchParams Struct containing the property we want to 3291 * patch 3292 * @param[in] computerSystemIndex Index associated with the requested system 3293 * 3294 * @return None 3295 */ 3296 3297 inline void processComputerSystemPatch( 3298 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3299 std::string& systemName, PatchParams& patchParams, 3300 const uint64_t computerSystemIndex) 3301 { 3302 if constexpr (!BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 3303 { 3304 if (patchParams.indicatorLed) 3305 { 3306 messages::propertyUnknown(asyncResp->res, "IndicatorLED"); 3307 return; 3308 } 3309 } 3310 3311 if (patchParams.assetTag) 3312 { 3313 setAssetTag(asyncResp, *patchParams.assetTag); 3314 } 3315 3316 if (patchParams.wdtEnable || patchParams.wdtTimeOutAction) 3317 { 3318 setWDTProperties(asyncResp, patchParams.wdtEnable, 3319 patchParams.wdtTimeOutAction); 3320 } 3321 3322 if (patchParams.bootSource || patchParams.bootType || 3323 patchParams.bootEnable) 3324 { 3325 setBootProperties(asyncResp, computerSystemIndex, 3326 patchParams.bootSource, patchParams.bootType, 3327 patchParams.bootEnable); 3328 } 3329 if (patchParams.bootAutomaticRetry) 3330 { 3331 setAutomaticRetry(asyncResp, computerSystemIndex, 3332 *patchParams.bootAutomaticRetry); 3333 } 3334 3335 if (patchParams.bootAutomaticRetryAttempts) 3336 { 3337 setAutomaticRetryAttempts( 3338 asyncResp, computerSystemIndex, 3339 patchParams.bootAutomaticRetryAttempts.value()); 3340 } 3341 3342 if (patchParams.bootTrustedModuleRequired) 3343 { 3344 setTrustedModuleRequiredToBoot(asyncResp, computerSystemIndex, 3345 *patchParams.bootTrustedModuleRequired); 3346 } 3347 3348 if (patchParams.stopBootOnFault) 3349 { 3350 setStopBootOnFault(asyncResp, *patchParams.stopBootOnFault); 3351 } 3352 3353 if (patchParams.locationIndicatorActive) 3354 { 3355 systems_utils::getValidSystemsPath( 3356 asyncResp, systemName, 3357 [asyncResp, systemName, 3358 locationIndicatorActive{*patchParams.locationIndicatorActive}]( 3359 const std::optional<std::string>& validSystemsPath) { 3360 if (!validSystemsPath) 3361 { 3362 messages::resourceNotFound(asyncResp->res, "Systems", 3363 systemName); 3364 return; 3365 } 3366 setLocationIndicatorActive(asyncResp, *validSystemsPath, 3367 locationIndicatorActive); 3368 }); 3369 } 3370 3371 if constexpr (BMCWEB_REDFISH_ALLOW_DEPRECATED_INDICATORLED) 3372 { 3373 if (patchParams.indicatorLed) 3374 { 3375 setIndicatorLedState(asyncResp, *patchParams.indicatorLed); 3376 asyncResp->res.addHeader(boost::beast::http::field::warning, 3377 "299 - \"IndicatorLED is deprecated. Use " 3378 "LocationIndicatorActive instead.\""); 3379 } 3380 } 3381 3382 if (patchParams.powerRestorePolicy) 3383 { 3384 setPowerRestorePolicy(asyncResp, computerSystemIndex, 3385 *patchParams.powerRestorePolicy); 3386 } 3387 3388 if (patchParams.powerMode) 3389 { 3390 setPowerMode(asyncResp, *patchParams.powerMode); 3391 } 3392 3393 if (patchParams.ipsEnable || patchParams.ipsEnterUtil || 3394 patchParams.ipsEnterTime || patchParams.ipsExitUtil || 3395 patchParams.ipsExitTime) 3396 { 3397 setIdlePowerSaver(asyncResp, patchParams.ipsEnable, 3398 patchParams.ipsEnterUtil, patchParams.ipsEnterTime, 3399 patchParams.ipsExitUtil, patchParams.ipsExitTime); 3400 } 3401 } 3402 3403 inline void handleComputerSystemPatch( 3404 crow::App& app, const crow::Request& req, 3405 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3406 const std::string& systemName) 3407 { 3408 PatchParams patchParams; 3409 3410 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3411 { 3412 return; 3413 } 3414 3415 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3416 { 3417 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3418 { 3419 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3420 systemName); 3421 return; 3422 } 3423 } 3424 3425 asyncResp->res.addHeader( 3426 boost::beast::http::field::link, 3427 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3428 3429 if (!json_util::readJsonPatch( 3430 req, asyncResp->res, // 3431 "AssetTag", patchParams.assetTag, // 3432 "Boot/AutomaticRetryAttempts", 3433 patchParams.bootAutomaticRetryAttempts, // 3434 "Boot/AutomaticRetryConfig", patchParams.bootAutomaticRetry, // 3435 "Boot/BootSourceOverrideEnabled", patchParams.bootEnable, // 3436 "Boot/BootSourceOverrideMode", patchParams.bootType, // 3437 "Boot/BootSourceOverrideTarget", patchParams.bootSource, // 3438 "Boot/StopBootOnFault", patchParams.stopBootOnFault, // 3439 "Boot/TrustedModuleRequiredToBoot", 3440 patchParams.bootTrustedModuleRequired, // 3441 "HostWatchdogTimer/FunctionEnabled", patchParams.wdtEnable, // 3442 "HostWatchdogTimer/TimeoutAction", patchParams.wdtTimeOutAction, // 3443 "IdlePowerSaver/Enabled", patchParams.ipsEnable, // 3444 "IdlePowerSaver/EnterDwellTimeSeconds", patchParams.ipsEnterTime, // 3445 "IdlePowerSaver/EnterUtilizationPercent", 3446 patchParams.ipsEnterUtil, // 3447 "IdlePowerSaver/ExitDwellTimeSeconds", patchParams.ipsExitTime, // 3448 "IdlePowerSaver/ExitUtilizationPercent", patchParams.ipsExitUtil, // 3449 "IndicatorLED", patchParams.indicatorLed, // 3450 "LocationIndicatorActive", patchParams.locationIndicatorActive, // 3451 "PowerMode", patchParams.powerMode, // 3452 "PowerRestorePolicy", patchParams.powerRestorePolicy)) 3453 { 3454 return; 3455 } 3456 3457 getComputerSystemIndex(asyncResp, systemName, 3458 std::bind_front(processComputerSystemPatch, 3459 asyncResp, systemName, patchParams)); 3460 } 3461 3462 inline void handleSystemCollectionResetActionHead( 3463 crow::App& app, const crow::Request& req, 3464 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3465 const std::string& /*systemName*/) 3466 { 3467 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3468 { 3469 return; 3470 } 3471 asyncResp->res.addHeader( 3472 boost::beast::http::field::link, 3473 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3474 } 3475 3476 /** 3477 * @brief Translates allowed host transitions to redfish string 3478 * 3479 * @param[in] dbusAllowedHostTran The allowed host transition on dbus 3480 * @param[out] allowableValues The translated host transition(s) 3481 * 3482 * @return Emplaces corresponding Redfish translated value(s) in 3483 * allowableValues. If translation not possible, does nothing to 3484 * allowableValues. 3485 */ 3486 inline void dbusToRfAllowedHostTransitions( 3487 const std::string& dbusAllowedHostTran, 3488 nlohmann::json::array_t& allowableValues) 3489 { 3490 if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On") 3491 { 3492 allowableValues.emplace_back(resource::ResetType::On); 3493 allowableValues.emplace_back(resource::ResetType::ForceOn); 3494 } 3495 else if (dbusAllowedHostTran == 3496 "xyz.openbmc_project.State.Host.Transition.Off") 3497 { 3498 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3499 } 3500 else if (dbusAllowedHostTran == 3501 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot") 3502 { 3503 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3504 } 3505 else if (dbusAllowedHostTran == 3506 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot") 3507 { 3508 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3509 } 3510 else 3511 { 3512 BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran); 3513 } 3514 } 3515 3516 inline void afterGetAllowedHostTransitions( 3517 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3518 const boost::system::error_code& ec, 3519 const std::vector<std::string>& allowedHostTransitions) 3520 { 3521 nlohmann::json::array_t allowableValues; 3522 3523 // Supported on all systems currently 3524 allowableValues.emplace_back(resource::ResetType::ForceOff); 3525 allowableValues.emplace_back(resource::ResetType::PowerCycle); 3526 allowableValues.emplace_back(resource::ResetType::Nmi); 3527 3528 if (ec) 3529 { 3530 if ((ec.value() == 3531 boost::system::linux_error::bad_request_descriptor) || 3532 (ec.value() == boost::asio::error::basic_errors::host_unreachable)) 3533 { 3534 // Property not implemented so just return defaults 3535 BMCWEB_LOG_DEBUG("Property not available {}", ec); 3536 allowableValues.emplace_back(resource::ResetType::On); 3537 allowableValues.emplace_back(resource::ResetType::ForceOn); 3538 allowableValues.emplace_back(resource::ResetType::ForceRestart); 3539 allowableValues.emplace_back(resource::ResetType::GracefulRestart); 3540 allowableValues.emplace_back(resource::ResetType::GracefulShutdown); 3541 } 3542 else 3543 { 3544 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 3545 messages::internalError(asyncResp->res); 3546 return; 3547 } 3548 } 3549 else 3550 { 3551 for (const std::string& transition : allowedHostTransitions) 3552 { 3553 BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition); 3554 dbusToRfAllowedHostTransitions(transition, allowableValues); 3555 } 3556 } 3557 3558 nlohmann::json::object_t parameter; 3559 parameter["Name"] = "ResetType"; 3560 parameter["Required"] = true; 3561 parameter["DataType"] = action_info::ParameterTypes::String; 3562 parameter["AllowableValues"] = std::move(allowableValues); 3563 nlohmann::json::array_t parameters; 3564 parameters.emplace_back(std::move(parameter)); 3565 asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 3566 } 3567 3568 inline void getAllowedHostTransitions( 3569 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3570 const uint64_t computerSystemIndex) 3571 { 3572 dbus::utility::getProperty<std::vector<std::string>>( 3573 getHostStateServiceName(computerSystemIndex), 3574 getHostStateObjectPath(computerSystemIndex), 3575 "xyz.openbmc_project.State.Host", "AllowedHostTransitions", 3576 std::bind_front(afterGetAllowedHostTransitions, asyncResp)); 3577 } 3578 3579 inline void handleSystemCollectionResetActionGet( 3580 crow::App& app, const crow::Request& req, 3581 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3582 const std::string& systemName) 3583 { 3584 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3585 { 3586 return; 3587 } 3588 3589 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 3590 { 3591 if (systemName == "hypervisor") 3592 { 3593 handleHypervisorResetActionGet(asyncResp); 3594 return; 3595 } 3596 } 3597 3598 if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 3599 { 3600 if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME) 3601 { 3602 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3603 systemName); 3604 return; 3605 } 3606 } 3607 3608 asyncResp->res.addHeader( 3609 boost::beast::http::field::link, 3610 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3611 3612 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 3613 "/redfish/v1/Systems/{}/ResetActionInfo", systemName); 3614 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 3615 asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 3616 asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 3617 3618 // Look to see if system defines AllowedHostTransitions 3619 getComputerSystemIndex( 3620 asyncResp, systemName, 3621 std::bind_front(getAllowedHostTransitions, asyncResp)); 3622 } 3623 3624 /** 3625 * SystemResetActionInfo derived class for delivering Computer Systems 3626 * ResetType AllowableValues using ResetInfo schema. 3627 */ 3628 inline void requestRoutesSystems(App& app) 3629 { 3630 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3631 .privileges(redfish::privileges::headComputerSystemCollection) 3632 .methods(boost::beast::http::verb::head)( 3633 std::bind_front(handleComputerSystemCollectionHead, std::ref(app))); 3634 3635 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3636 .privileges(redfish::privileges::getComputerSystemCollection) 3637 .methods(boost::beast::http::verb::get)( 3638 std::bind_front(handleComputerSystemCollectionGet, std::ref(app))); 3639 3640 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3641 .privileges(redfish::privileges::headComputerSystem) 3642 .methods(boost::beast::http::verb::head)( 3643 std::bind_front(handleComputerSystemHead, std::ref(app))); 3644 3645 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3646 .privileges(redfish::privileges::getComputerSystem) 3647 .methods(boost::beast::http::verb::get)( 3648 std::bind_front(handleComputerSystemGet, std::ref(app))); 3649 3650 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3651 .privileges(redfish::privileges::patchComputerSystem) 3652 .methods(boost::beast::http::verb::patch)( 3653 std::bind_front(handleComputerSystemPatch, std::ref(app))); 3654 3655 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/") 3656 .privileges(redfish::privileges::postComputerSystem) 3657 .methods(boost::beast::http::verb::post)(std::bind_front( 3658 handleComputerSystemResetActionPost, std::ref(app))); 3659 3660 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3661 .privileges(redfish::privileges::headActionInfo) 3662 .methods(boost::beast::http::verb::head)(std::bind_front( 3663 handleSystemCollectionResetActionHead, std::ref(app))); 3664 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3665 .privileges(redfish::privileges::getActionInfo) 3666 .methods(boost::beast::http::verb::get)(std::bind_front( 3667 handleSystemCollectionResetActionGet, std::ref(app))); 3668 } 3669 } // namespace redfish 3670