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