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