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