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