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