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_DEBUG("DBUS response error"); 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_DEBUG("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_DEBUG("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 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1046 if (ec.value() == boost::asio::error::host_unreachable) 1047 { 1048 return; 1049 } 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_DEBUG("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 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1137 if (ec.value() == boost::asio::error::host_unreachable) 1138 { 1139 return; 1140 } 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 messages::internalError(asyncResp->res); 1427 } 1428 return; 1429 } 1430 1431 if (value) 1432 { 1433 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = "AnyFault"; 1434 } 1435 else 1436 { 1437 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] = "Never"; 1438 } 1439 }); 1440 } 1441 1442 /** 1443 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1444 * TPM is required for booting the host. 1445 * 1446 * @param[in] asyncResp Shared pointer for generating response message. 1447 * 1448 * @return None. 1449 */ 1450 inline void getTrustedModuleRequiredToBoot( 1451 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1452 { 1453 BMCWEB_LOG_DEBUG("Get TPM required to boot."); 1454 constexpr std::array<std::string_view, 1> interfaces = { 1455 "xyz.openbmc_project.Control.TPM.Policy"}; 1456 dbus::utility::getSubTree( 1457 "/", 0, interfaces, 1458 [asyncResp](const boost::system::error_code& ec, 1459 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1460 if (ec) 1461 { 1462 BMCWEB_LOG_DEBUG("DBUS response error on TPM.Policy GetSubTree{}", 1463 ec); 1464 // This is an optional D-Bus object so just return if 1465 // error occurs 1466 return; 1467 } 1468 if (subtree.empty()) 1469 { 1470 // As noted above, this is an optional interface so just return 1471 // if there is no instance found 1472 return; 1473 } 1474 1475 /* When there is more than one TPMEnable object... */ 1476 if (subtree.size() > 1) 1477 { 1478 BMCWEB_LOG_DEBUG( 1479 "DBUS response has more than 1 TPM Enable object:{}", 1480 subtree.size()); 1481 // Throw an internal Error and return 1482 messages::internalError(asyncResp->res); 1483 return; 1484 } 1485 1486 // Make sure the Dbus response map has a service and objectPath 1487 // field 1488 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1489 { 1490 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1491 messages::internalError(asyncResp->res); 1492 return; 1493 } 1494 1495 const std::string& path = subtree[0].first; 1496 const std::string& serv = subtree[0].second.begin()->first; 1497 1498 // Valid TPM Enable object found, now reading the current value 1499 sdbusplus::asio::getProperty<bool>( 1500 *crow::connections::systemBus, serv, path, 1501 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1502 [asyncResp](const boost::system::error_code& ec2, 1503 bool tpmRequired) { 1504 if (ec2) 1505 { 1506 BMCWEB_LOG_DEBUG("D-BUS response error on TPM.Policy Get{}", 1507 ec2); 1508 messages::internalError(asyncResp->res); 1509 return; 1510 } 1511 1512 if (tpmRequired) 1513 { 1514 asyncResp->res 1515 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1516 "Required"; 1517 } 1518 else 1519 { 1520 asyncResp->res 1521 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1522 "Disabled"; 1523 } 1524 }); 1525 }); 1526 } 1527 1528 /** 1529 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1530 * TPM is required for booting the host. 1531 * 1532 * @param[in] asyncResp Shared pointer for generating response message. 1533 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1534 * 1535 * @return None. 1536 */ 1537 inline void setTrustedModuleRequiredToBoot( 1538 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool tpmRequired) 1539 { 1540 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot."); 1541 constexpr std::array<std::string_view, 1> interfaces = { 1542 "xyz.openbmc_project.Control.TPM.Policy"}; 1543 dbus::utility::getSubTree( 1544 "/", 0, interfaces, 1545 [asyncResp, 1546 tpmRequired](const boost::system::error_code& ec, 1547 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1548 if (ec) 1549 { 1550 BMCWEB_LOG_DEBUG("DBUS response error on TPM.Policy GetSubTree{}", 1551 ec); 1552 messages::internalError(asyncResp->res); 1553 return; 1554 } 1555 if (subtree.empty()) 1556 { 1557 messages::propertyValueNotInList(asyncResp->res, "ComputerSystem", 1558 "TrustedModuleRequiredToBoot"); 1559 return; 1560 } 1561 1562 /* When there is more than one TPMEnable object... */ 1563 if (subtree.size() > 1) 1564 { 1565 BMCWEB_LOG_DEBUG( 1566 "DBUS response has more than 1 TPM Enable object:{}", 1567 subtree.size()); 1568 // Throw an internal Error and return 1569 messages::internalError(asyncResp->res); 1570 return; 1571 } 1572 1573 // Make sure the Dbus response map has a service and objectPath 1574 // field 1575 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1576 { 1577 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!"); 1578 messages::internalError(asyncResp->res); 1579 return; 1580 } 1581 1582 const std::string& path = subtree[0].first; 1583 const std::string& serv = subtree[0].second.begin()->first; 1584 1585 if (serv.empty()) 1586 { 1587 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!"); 1588 messages::internalError(asyncResp->res); 1589 return; 1590 } 1591 1592 // Valid TPM Enable object found, now setting the value 1593 sdbusplus::asio::setProperty( 1594 *crow::connections::systemBus, serv, path, 1595 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", tpmRequired, 1596 [asyncResp](const boost::system::error_code& ec2) { 1597 if (ec2) 1598 { 1599 BMCWEB_LOG_DEBUG( 1600 "DBUS response error: Set TrustedModuleRequiredToBoot{}", 1601 ec2); 1602 messages::internalError(asyncResp->res); 1603 return; 1604 } 1605 BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot done."); 1606 }); 1607 }); 1608 } 1609 1610 /** 1611 * @brief Sets boot properties into DBUS object(s). 1612 * 1613 * @param[in] asyncResp Shared pointer for generating response message. 1614 * @param[in] bootType The boot type to set. 1615 * @return Integer error code. 1616 */ 1617 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1618 const std::optional<std::string>& bootType) 1619 { 1620 std::string bootTypeStr; 1621 1622 if (!bootType) 1623 { 1624 return; 1625 } 1626 1627 // Source target specified 1628 BMCWEB_LOG_DEBUG("Boot type: {}", *bootType); 1629 // Figure out which DBUS interface and property to use 1630 if (*bootType == "Legacy") 1631 { 1632 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1633 } 1634 else if (*bootType == "UEFI") 1635 { 1636 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1637 } 1638 else 1639 { 1640 BMCWEB_LOG_DEBUG("Invalid property value for " 1641 "BootSourceOverrideMode: {}", 1642 *bootType); 1643 messages::propertyValueNotInList(asyncResp->res, *bootType, 1644 "BootSourceOverrideMode"); 1645 return; 1646 } 1647 1648 // Act on validated parameters 1649 BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr); 1650 1651 sdbusplus::asio::setProperty( 1652 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1653 "/xyz/openbmc_project/control/host0/boot", 1654 "xyz.openbmc_project.Control.Boot.Type", "BootType", bootTypeStr, 1655 [asyncResp](const boost::system::error_code& ec) { 1656 if (ec) 1657 { 1658 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1659 if (ec.value() == boost::asio::error::host_unreachable) 1660 { 1661 messages::resourceNotFound(asyncResp->res, "Set", "BootType"); 1662 return; 1663 } 1664 messages::internalError(asyncResp->res); 1665 return; 1666 } 1667 BMCWEB_LOG_DEBUG("Boot type update done."); 1668 }); 1669 } 1670 1671 /** 1672 * @brief Sets boot properties into DBUS object(s). 1673 * 1674 * @param[in] asyncResp Shared pointer for generating response 1675 * message. 1676 * @param[in] bootType The boot type to set. 1677 * @return Integer error code. 1678 */ 1679 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1680 const std::optional<std::string>& bootEnable) 1681 { 1682 if (!bootEnable) 1683 { 1684 return; 1685 } 1686 // Source target specified 1687 BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable); 1688 1689 bool bootOverrideEnable = false; 1690 bool bootOverridePersistent = false; 1691 // Figure out which DBUS interface and property to use 1692 if (*bootEnable == "Disabled") 1693 { 1694 bootOverrideEnable = false; 1695 } 1696 else if (*bootEnable == "Once") 1697 { 1698 bootOverrideEnable = true; 1699 bootOverridePersistent = false; 1700 } 1701 else if (*bootEnable == "Continuous") 1702 { 1703 bootOverrideEnable = true; 1704 bootOverridePersistent = true; 1705 } 1706 else 1707 { 1708 BMCWEB_LOG_DEBUG( 1709 "Invalid property value for BootSourceOverrideEnabled: {}", 1710 *bootEnable); 1711 messages::propertyValueNotInList(asyncResp->res, *bootEnable, 1712 "BootSourceOverrideEnabled"); 1713 return; 1714 } 1715 1716 // Act on validated parameters 1717 BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable); 1718 1719 sdbusplus::asio::setProperty( 1720 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1721 "/xyz/openbmc_project/control/host0/boot", 1722 "xyz.openbmc_project.Object.Enable", "Enabled", bootOverrideEnable, 1723 [asyncResp](const boost::system::error_code& ec2) { 1724 if (ec2) 1725 { 1726 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 1727 messages::internalError(asyncResp->res); 1728 return; 1729 } 1730 BMCWEB_LOG_DEBUG("Boot override enable update done."); 1731 }); 1732 1733 if (!bootOverrideEnable) 1734 { 1735 return; 1736 } 1737 1738 // In case boot override is enabled we need to set correct value for the 1739 // 'one_time' enable DBus interface 1740 BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}", 1741 bootOverridePersistent); 1742 1743 sdbusplus::asio::setProperty( 1744 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1745 "/xyz/openbmc_project/control/host0/boot/one_time", 1746 "xyz.openbmc_project.Object.Enable", "Enabled", !bootOverridePersistent, 1747 [asyncResp](const boost::system::error_code& ec) { 1748 if (ec) 1749 { 1750 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1751 messages::internalError(asyncResp->res); 1752 return; 1753 } 1754 BMCWEB_LOG_DEBUG("Boot one_time update done."); 1755 }); 1756 } 1757 1758 /** 1759 * @brief Sets boot properties into DBUS object(s). 1760 * 1761 * @param[in] asyncResp Shared pointer for generating response message. 1762 * @param[in] bootSource The boot source to set. 1763 * 1764 * @return Integer error code. 1765 */ 1766 inline void 1767 setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1768 const std::optional<std::string>& bootSource) 1769 { 1770 std::string bootSourceStr; 1771 std::string bootModeStr; 1772 1773 if (!bootSource) 1774 { 1775 return; 1776 } 1777 1778 // Source target specified 1779 BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource); 1780 // Figure out which DBUS interface and property to use 1781 if (assignBootParameters(asyncResp, *bootSource, bootSourceStr, 1782 bootModeStr) != 0) 1783 { 1784 BMCWEB_LOG_DEBUG( 1785 "Invalid property value for BootSourceOverrideTarget: {}", 1786 *bootSource); 1787 messages::propertyValueNotInList(asyncResp->res, *bootSource, 1788 "BootSourceTargetOverride"); 1789 return; 1790 } 1791 1792 // Act on validated parameters 1793 BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr); 1794 BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr); 1795 1796 sdbusplus::asio::setProperty( 1797 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1798 "/xyz/openbmc_project/control/host0/boot", 1799 "xyz.openbmc_project.Control.Boot.Source", "BootSource", bootSourceStr, 1800 [asyncResp](const boost::system::error_code& ec) { 1801 if (ec) 1802 { 1803 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1804 messages::internalError(asyncResp->res); 1805 return; 1806 } 1807 BMCWEB_LOG_DEBUG("Boot source update done."); 1808 }); 1809 1810 sdbusplus::asio::setProperty( 1811 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1812 "/xyz/openbmc_project/control/host0/boot", 1813 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", bootModeStr, 1814 [asyncResp](const boost::system::error_code& ec) { 1815 if (ec) 1816 { 1817 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 1818 messages::internalError(asyncResp->res); 1819 return; 1820 } 1821 BMCWEB_LOG_DEBUG("Boot mode update done."); 1822 }); 1823 } 1824 1825 /** 1826 * @brief Sets Boot source override properties. 1827 * 1828 * @param[in] asyncResp Shared pointer for generating response message. 1829 * @param[in] bootSource The boot source from incoming RF request. 1830 * @param[in] bootType The boot type from incoming RF request. 1831 * @param[in] bootEnable The boot override enable from incoming RF request. 1832 * 1833 * @return Integer error code. 1834 */ 1835 1836 inline void 1837 setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1838 const std::optional<std::string>& bootSource, 1839 const std::optional<std::string>& bootType, 1840 const std::optional<std::string>& bootEnable) 1841 { 1842 BMCWEB_LOG_DEBUG("Set boot information."); 1843 1844 setBootModeOrSource(asyncResp, bootSource); 1845 setBootType(asyncResp, bootType); 1846 setBootEnable(asyncResp, bootEnable); 1847 } 1848 1849 /** 1850 * @brief Sets AssetTag 1851 * 1852 * @param[in] asyncResp Shared pointer for generating response message. 1853 * @param[in] assetTag "AssetTag" from request. 1854 * 1855 * @return None. 1856 */ 1857 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1858 const std::string& assetTag) 1859 { 1860 constexpr std::array<std::string_view, 1> interfaces = { 1861 "xyz.openbmc_project.Inventory.Item.System"}; 1862 dbus::utility::getSubTree( 1863 "/xyz/openbmc_project/inventory", 0, interfaces, 1864 [asyncResp, 1865 assetTag](const boost::system::error_code& ec, 1866 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1867 if (ec) 1868 { 1869 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); 1870 messages::internalError(asyncResp->res); 1871 return; 1872 } 1873 if (subtree.empty()) 1874 { 1875 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!"); 1876 messages::internalError(asyncResp->res); 1877 return; 1878 } 1879 // Assume only 1 system D-Bus object 1880 // Throw an error if there is more than 1 1881 if (subtree.size() > 1) 1882 { 1883 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!"); 1884 messages::internalError(asyncResp->res); 1885 return; 1886 } 1887 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1888 { 1889 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!"); 1890 messages::internalError(asyncResp->res); 1891 return; 1892 } 1893 1894 const std::string& path = subtree[0].first; 1895 const std::string& service = subtree[0].second.begin()->first; 1896 1897 if (service.empty()) 1898 { 1899 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!"); 1900 messages::internalError(asyncResp->res); 1901 return; 1902 } 1903 1904 sdbusplus::asio::setProperty( 1905 *crow::connections::systemBus, service, path, 1906 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1907 assetTag, [asyncResp](const boost::system::error_code& ec2) { 1908 if (ec2) 1909 { 1910 BMCWEB_LOG_DEBUG("D-Bus response error on AssetTag Set {}", 1911 ec2); 1912 messages::internalError(asyncResp->res); 1913 return; 1914 } 1915 }); 1916 }); 1917 } 1918 1919 /** 1920 * @brief Validate the specified stopBootOnFault is valid and return the 1921 * stopBootOnFault name associated with that string 1922 * 1923 * @param[in] stopBootOnFaultString String representing the desired 1924 * stopBootOnFault 1925 * 1926 * @return stopBootOnFault value or empty if incoming value is not valid 1927 */ 1928 inline std::optional<bool> 1929 validstopBootOnFault(const std::string& stopBootOnFaultString) 1930 { 1931 if (stopBootOnFaultString == "AnyFault") 1932 { 1933 return true; 1934 } 1935 1936 if (stopBootOnFaultString == "Never") 1937 { 1938 return false; 1939 } 1940 1941 return std::nullopt; 1942 } 1943 1944 /** 1945 * @brief Sets stopBootOnFault 1946 * 1947 * @param[in] asyncResp Shared pointer for generating response message. 1948 * @param[in] stopBootOnFault "StopBootOnFault" from request. 1949 * 1950 * @return None. 1951 */ 1952 inline void 1953 setStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1954 const std::string& stopBootOnFault) 1955 { 1956 BMCWEB_LOG_DEBUG("Set Stop Boot On Fault."); 1957 1958 std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault); 1959 if (!stopBootEnabled) 1960 { 1961 BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}", 1962 stopBootOnFault); 1963 messages::propertyValueNotInList(asyncResp->res, stopBootOnFault, 1964 "StopBootOnFault"); 1965 return; 1966 } 1967 1968 sdbusplus::asio::setProperty( 1969 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1970 "/xyz/openbmc_project/logging/settings", 1971 "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError", 1972 *stopBootEnabled, [asyncResp](const boost::system::error_code& ec) { 1973 if (ec) 1974 { 1975 if (ec.value() != EBADR) 1976 { 1977 messages::internalError(asyncResp->res); 1978 } 1979 return; 1980 } 1981 }); 1982 } 1983 1984 /** 1985 * @brief Sets automaticRetry (Auto Reboot) 1986 * 1987 * @param[in] asyncResp Shared pointer for generating response message. 1988 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1989 * 1990 * @return None. 1991 */ 1992 inline void 1993 setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1994 const std::string& automaticRetryConfig) 1995 { 1996 BMCWEB_LOG_DEBUG("Set Automatic Retry."); 1997 1998 // OpenBMC only supports "Disabled" and "RetryAttempts". 1999 bool autoRebootEnabled = false; 2000 2001 if (automaticRetryConfig == "Disabled") 2002 { 2003 autoRebootEnabled = false; 2004 } 2005 else if (automaticRetryConfig == "RetryAttempts") 2006 { 2007 autoRebootEnabled = true; 2008 } 2009 else 2010 { 2011 BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}", 2012 automaticRetryConfig); 2013 messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig, 2014 "AutomaticRetryConfig"); 2015 return; 2016 } 2017 2018 sdbusplus::asio::setProperty( 2019 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 2020 "/xyz/openbmc_project/control/host0/auto_reboot", 2021 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 2022 autoRebootEnabled, [asyncResp](const boost::system::error_code& ec) { 2023 if (ec) 2024 { 2025 messages::internalError(asyncResp->res); 2026 return; 2027 } 2028 }); 2029 } 2030 2031 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy) 2032 { 2033 if (policy == "AlwaysOn") 2034 { 2035 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"; 2036 } 2037 if (policy == "AlwaysOff") 2038 { 2039 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"; 2040 } 2041 if (policy == "LastState") 2042 { 2043 return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"; 2044 } 2045 return ""; 2046 } 2047 2048 /** 2049 * @brief Sets power restore policy properties. 2050 * 2051 * @param[in] asyncResp Shared pointer for generating response message. 2052 * @param[in] policy power restore policy properties from request. 2053 * 2054 * @return None. 2055 */ 2056 inline void 2057 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2058 std::string_view policy) 2059 { 2060 BMCWEB_LOG_DEBUG("Set power restore policy."); 2061 2062 std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy); 2063 2064 if (powerRestorePolicy.empty()) 2065 { 2066 messages::propertyValueNotInList(asyncResp->res, policy, 2067 "PowerRestorePolicy"); 2068 return; 2069 } 2070 2071 sdbusplus::asio::setProperty( 2072 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 2073 "/xyz/openbmc_project/control/host0/power_restore_policy", 2074 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 2075 powerRestorePolicy, [asyncResp](const boost::system::error_code& ec) { 2076 if (ec) 2077 { 2078 messages::internalError(asyncResp->res); 2079 return; 2080 } 2081 }); 2082 } 2083 2084 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2085 /** 2086 * @brief Retrieves provisioning status 2087 * 2088 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2089 * 2090 * @return None. 2091 */ 2092 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> asyncResp) 2093 { 2094 BMCWEB_LOG_DEBUG("Get OEM information."); 2095 sdbusplus::asio::getAllProperties( 2096 *crow::connections::systemBus, "xyz.openbmc_project.PFR.Manager", 2097 "/xyz/openbmc_project/pfr", "xyz.openbmc_project.PFR.Attributes", 2098 [asyncResp](const boost::system::error_code& ec, 2099 const dbus::utility::DBusPropertiesMap& propertiesList) { 2100 nlohmann::json& oemPFR = 2101 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 2102 asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 2103 "#OemComputerSystem.OpenBmc"; 2104 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 2105 2106 if (ec) 2107 { 2108 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2109 // not an error, don't have to have the interface 2110 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2111 return; 2112 } 2113 2114 const bool* provState = nullptr; 2115 const bool* lockState = nullptr; 2116 2117 const bool success = sdbusplus::unpackPropertiesNoThrow( 2118 dbus_utils::UnpackErrorPrinter(), propertiesList, "UfmProvisioned", 2119 provState, "UfmLocked", lockState); 2120 2121 if (!success) 2122 { 2123 messages::internalError(asyncResp->res); 2124 return; 2125 } 2126 2127 if ((provState == nullptr) || (lockState == nullptr)) 2128 { 2129 BMCWEB_LOG_DEBUG("Unable to get PFR attributes."); 2130 messages::internalError(asyncResp->res); 2131 return; 2132 } 2133 2134 if (*provState == true) 2135 { 2136 if (*lockState == true) 2137 { 2138 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 2139 } 2140 else 2141 { 2142 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 2143 } 2144 } 2145 else 2146 { 2147 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 2148 } 2149 }); 2150 } 2151 #endif 2152 2153 /** 2154 * @brief Translate the PowerMode to a response message. 2155 * 2156 * @param[in] asyncResp Shared pointer for generating response message. 2157 * @param[in] modeValue PowerMode value to be translated 2158 * 2159 * @return None. 2160 */ 2161 inline void 2162 translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2163 const std::string& modeValue) 2164 { 2165 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 2166 { 2167 asyncResp->res.jsonValue["PowerMode"] = "Static"; 2168 } 2169 else if ( 2170 modeValue == 2171 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 2172 { 2173 asyncResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 2174 } 2175 else if (modeValue == 2176 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 2177 { 2178 asyncResp->res.jsonValue["PowerMode"] = "PowerSaving"; 2179 } 2180 else if (modeValue == 2181 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 2182 { 2183 asyncResp->res.jsonValue["PowerMode"] = "OEM"; 2184 } 2185 else 2186 { 2187 // Any other values would be invalid 2188 BMCWEB_LOG_DEBUG("PowerMode value was not valid: {}", modeValue); 2189 messages::internalError(asyncResp->res); 2190 } 2191 } 2192 2193 /** 2194 * @brief Retrieves system power mode 2195 * 2196 * @param[in] asyncResp Shared pointer for generating response message. 2197 * 2198 * @return None. 2199 */ 2200 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2201 { 2202 BMCWEB_LOG_DEBUG("Get power mode."); 2203 2204 // Get Power Mode object path: 2205 constexpr std::array<std::string_view, 1> interfaces = { 2206 "xyz.openbmc_project.Control.Power.Mode"}; 2207 dbus::utility::getSubTree( 2208 "/", 0, interfaces, 2209 [asyncResp](const boost::system::error_code& ec, 2210 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2211 if (ec) 2212 { 2213 BMCWEB_LOG_DEBUG("DBUS response error on Power.Mode GetSubTree {}", 2214 ec); 2215 // This is an optional D-Bus object so just return if 2216 // error occurs 2217 return; 2218 } 2219 if (subtree.empty()) 2220 { 2221 // As noted above, this is an optional interface so just return 2222 // if there is no instance found 2223 return; 2224 } 2225 if (subtree.size() > 1) 2226 { 2227 // More then one PowerMode object is not supported and is an 2228 // error 2229 BMCWEB_LOG_DEBUG( 2230 "Found more than 1 system D-Bus Power.Mode objects: {}", 2231 subtree.size()); 2232 messages::internalError(asyncResp->res); 2233 return; 2234 } 2235 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2236 { 2237 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2238 messages::internalError(asyncResp->res); 2239 return; 2240 } 2241 const std::string& path = subtree[0].first; 2242 const std::string& service = subtree[0].second.begin()->first; 2243 if (service.empty()) 2244 { 2245 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2246 messages::internalError(asyncResp->res); 2247 return; 2248 } 2249 // Valid Power Mode object found, now read the current value 2250 sdbusplus::asio::getProperty<std::string>( 2251 *crow::connections::systemBus, service, path, 2252 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2253 [asyncResp](const boost::system::error_code& ec2, 2254 const std::string& pmode) { 2255 if (ec2) 2256 { 2257 BMCWEB_LOG_DEBUG("DBUS response error on PowerMode Get: {}", 2258 ec2); 2259 messages::internalError(asyncResp->res); 2260 return; 2261 } 2262 2263 asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = { 2264 "Static", "MaximumPerformance", "PowerSaving"}; 2265 2266 BMCWEB_LOG_DEBUG("Current power mode: {}", pmode); 2267 translatePowerMode(asyncResp, pmode); 2268 }); 2269 }); 2270 } 2271 2272 /** 2273 * @brief Validate the specified mode is valid and return the PowerMode 2274 * name associated with that string 2275 * 2276 * @param[in] asyncResp Shared pointer for generating response message. 2277 * @param[in] modeString String representing the desired PowerMode 2278 * 2279 * @return PowerMode value or empty string if mode is not valid 2280 */ 2281 inline std::string 2282 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2283 const std::string& modeString) 2284 { 2285 std::string mode; 2286 2287 if (modeString == "Static") 2288 { 2289 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2290 } 2291 else if (modeString == "MaximumPerformance") 2292 { 2293 mode = 2294 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2295 } 2296 else if (modeString == "PowerSaving") 2297 { 2298 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2299 } 2300 else 2301 { 2302 messages::propertyValueNotInList(asyncResp->res, modeString, 2303 "PowerMode"); 2304 } 2305 return mode; 2306 } 2307 2308 /** 2309 * @brief Sets system power mode. 2310 * 2311 * @param[in] asyncResp Shared pointer for generating response message. 2312 * @param[in] pmode System power mode from request. 2313 * 2314 * @return None. 2315 */ 2316 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2317 const std::string& pmode) 2318 { 2319 BMCWEB_LOG_DEBUG("Set power mode."); 2320 2321 std::string powerMode = validatePowerMode(asyncResp, pmode); 2322 if (powerMode.empty()) 2323 { 2324 return; 2325 } 2326 2327 // Get Power Mode object path: 2328 constexpr std::array<std::string_view, 1> interfaces = { 2329 "xyz.openbmc_project.Control.Power.Mode"}; 2330 dbus::utility::getSubTree( 2331 "/", 0, interfaces, 2332 [asyncResp, 2333 powerMode](const boost::system::error_code& ec, 2334 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2335 if (ec) 2336 { 2337 BMCWEB_LOG_DEBUG("DBUS response error on Power.Mode GetSubTree {}", 2338 ec); 2339 // This is an optional D-Bus object, but user attempted to patch 2340 messages::internalError(asyncResp->res); 2341 return; 2342 } 2343 if (subtree.empty()) 2344 { 2345 // This is an optional D-Bus object, but user attempted to patch 2346 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2347 "PowerMode"); 2348 return; 2349 } 2350 if (subtree.size() > 1) 2351 { 2352 // More then one PowerMode object is not supported and is an 2353 // error 2354 BMCWEB_LOG_DEBUG( 2355 "Found more than 1 system D-Bus Power.Mode objects: {}", 2356 subtree.size()); 2357 messages::internalError(asyncResp->res); 2358 return; 2359 } 2360 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2361 { 2362 BMCWEB_LOG_DEBUG("Power.Mode mapper error!"); 2363 messages::internalError(asyncResp->res); 2364 return; 2365 } 2366 const std::string& path = subtree[0].first; 2367 const std::string& service = subtree[0].second.begin()->first; 2368 if (service.empty()) 2369 { 2370 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!"); 2371 messages::internalError(asyncResp->res); 2372 return; 2373 } 2374 2375 BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path); 2376 2377 // Set the Power Mode property 2378 sdbusplus::asio::setProperty( 2379 *crow::connections::systemBus, service, path, 2380 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", powerMode, 2381 [asyncResp](const boost::system::error_code& ec2) { 2382 if (ec2) 2383 { 2384 messages::internalError(asyncResp->res); 2385 return; 2386 } 2387 }); 2388 }); 2389 } 2390 2391 /** 2392 * @brief Translates watchdog timeout action DBUS property value to redfish. 2393 * 2394 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2395 * 2396 * @return Returns as a string, the timeout action in Redfish terms. If 2397 * translation cannot be done, returns an empty string. 2398 */ 2399 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2400 { 2401 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2402 { 2403 return "None"; 2404 } 2405 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2406 { 2407 return "ResetSystem"; 2408 } 2409 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2410 { 2411 return "PowerDown"; 2412 } 2413 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2414 { 2415 return "PowerCycle"; 2416 } 2417 2418 return ""; 2419 } 2420 2421 /** 2422 *@brief Translates timeout action from Redfish to DBUS property value. 2423 * 2424 *@param[in] rfAction The timeout action in Redfish. 2425 * 2426 *@return Returns as a string, the time_out action as expected by DBUS. 2427 *If translation cannot be done, returns an empty string. 2428 */ 2429 2430 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2431 { 2432 if (rfAction == "None") 2433 { 2434 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2435 } 2436 if (rfAction == "PowerCycle") 2437 { 2438 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2439 } 2440 if (rfAction == "PowerDown") 2441 { 2442 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2443 } 2444 if (rfAction == "ResetSystem") 2445 { 2446 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2447 } 2448 2449 return ""; 2450 } 2451 2452 /** 2453 * @brief Retrieves host watchdog timer properties over DBUS 2454 * 2455 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2456 * 2457 * @return None. 2458 */ 2459 inline void 2460 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2461 { 2462 BMCWEB_LOG_DEBUG("Get host watchodg"); 2463 sdbusplus::asio::getAllProperties( 2464 *crow::connections::systemBus, "xyz.openbmc_project.Watchdog", 2465 "/xyz/openbmc_project/watchdog/host0", 2466 "xyz.openbmc_project.State.Watchdog", 2467 [asyncResp](const boost::system::error_code& ec, 2468 const dbus::utility::DBusPropertiesMap& properties) { 2469 if (ec) 2470 { 2471 // watchdog service is stopped 2472 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2473 return; 2474 } 2475 2476 BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size()); 2477 2478 nlohmann::json& hostWatchdogTimer = 2479 asyncResp->res.jsonValue["HostWatchdogTimer"]; 2480 2481 // watchdog service is running/enabled 2482 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2483 2484 const bool* enabled = nullptr; 2485 const std::string* expireAction = nullptr; 2486 2487 const bool success = sdbusplus::unpackPropertiesNoThrow( 2488 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2489 "ExpireAction", expireAction); 2490 2491 if (!success) 2492 { 2493 messages::internalError(asyncResp->res); 2494 return; 2495 } 2496 2497 if (enabled != nullptr) 2498 { 2499 hostWatchdogTimer["FunctionEnabled"] = *enabled; 2500 } 2501 2502 if (expireAction != nullptr) 2503 { 2504 std::string action = dbusToRfWatchdogAction(*expireAction); 2505 if (action.empty()) 2506 { 2507 messages::internalError(asyncResp->res); 2508 return; 2509 } 2510 hostWatchdogTimer["TimeoutAction"] = action; 2511 } 2512 }); 2513 } 2514 2515 /** 2516 * @brief Sets Host WatchDog Timer properties. 2517 * 2518 * @param[in] asyncResp Shared pointer for generating response message. 2519 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2520 * RF request. 2521 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2522 * 2523 * @return None. 2524 */ 2525 inline void 2526 setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2527 const std::optional<bool> wdtEnable, 2528 const std::optional<std::string>& wdtTimeOutAction) 2529 { 2530 BMCWEB_LOG_DEBUG("Set host watchdog"); 2531 2532 if (wdtTimeOutAction) 2533 { 2534 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2535 // check if TimeOut Action is Valid 2536 if (wdtTimeOutActStr.empty()) 2537 { 2538 BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}", 2539 *wdtTimeOutAction); 2540 messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction, 2541 "TimeoutAction"); 2542 return; 2543 } 2544 2545 sdbusplus::asio::setProperty( 2546 *crow::connections::systemBus, "xyz.openbmc_project.Watchdog", 2547 "/xyz/openbmc_project/watchdog/host0", 2548 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2549 wdtTimeOutActStr, [asyncResp](const boost::system::error_code& ec) { 2550 if (ec) 2551 { 2552 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2553 messages::internalError(asyncResp->res); 2554 return; 2555 } 2556 }); 2557 } 2558 2559 if (wdtEnable) 2560 { 2561 sdbusplus::asio::setProperty( 2562 *crow::connections::systemBus, "xyz.openbmc_project.Watchdog", 2563 "/xyz/openbmc_project/watchdog/host0", 2564 "xyz.openbmc_project.State.Watchdog", "Enabled", *wdtEnable, 2565 [asyncResp](const boost::system::error_code& ec) { 2566 if (ec) 2567 { 2568 BMCWEB_LOG_DEBUG("DBUS response error {}", ec); 2569 messages::internalError(asyncResp->res); 2570 return; 2571 } 2572 }); 2573 } 2574 } 2575 2576 /** 2577 * @brief Parse the Idle Power Saver properties into json 2578 * 2579 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2580 * @param[in] properties IPS property data from DBus. 2581 * 2582 * @return true if successful 2583 */ 2584 inline bool 2585 parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2586 const dbus::utility::DBusPropertiesMap& properties) 2587 { 2588 const bool* enabled = nullptr; 2589 const uint8_t* enterUtilizationPercent = nullptr; 2590 const uint64_t* enterDwellTime = nullptr; 2591 const uint8_t* exitUtilizationPercent = nullptr; 2592 const uint64_t* exitDwellTime = nullptr; 2593 2594 const bool success = sdbusplus::unpackPropertiesNoThrow( 2595 dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, 2596 "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime", 2597 enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent, 2598 "ExitDwellTime", exitDwellTime); 2599 2600 if (!success) 2601 { 2602 return false; 2603 } 2604 2605 if (enabled != nullptr) 2606 { 2607 asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled; 2608 } 2609 2610 if (enterUtilizationPercent != nullptr) 2611 { 2612 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] = 2613 *enterUtilizationPercent; 2614 } 2615 2616 if (enterDwellTime != nullptr) 2617 { 2618 const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime); 2619 asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2620 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2621 .count(); 2622 } 2623 2624 if (exitUtilizationPercent != nullptr) 2625 { 2626 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] = 2627 *exitUtilizationPercent; 2628 } 2629 2630 if (exitDwellTime != nullptr) 2631 { 2632 const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime); 2633 asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2634 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2635 .count(); 2636 } 2637 2638 return true; 2639 } 2640 2641 /** 2642 * @brief Retrieves host watchdog timer properties over DBUS 2643 * 2644 * @param[in] asyncResp Shared pointer for completing asynchronous calls. 2645 * 2646 * @return None. 2647 */ 2648 inline void 2649 getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2650 { 2651 BMCWEB_LOG_DEBUG("Get idle power saver parameters"); 2652 2653 // Get IdlePowerSaver object path: 2654 constexpr std::array<std::string_view, 1> interfaces = { 2655 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2656 dbus::utility::getSubTree( 2657 "/", 0, interfaces, 2658 [asyncResp](const boost::system::error_code& ec, 2659 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2660 if (ec) 2661 { 2662 BMCWEB_LOG_DEBUG( 2663 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2664 ec); 2665 messages::internalError(asyncResp->res); 2666 return; 2667 } 2668 if (subtree.empty()) 2669 { 2670 // This is an optional interface so just return 2671 // if there is no instance found 2672 BMCWEB_LOG_DEBUG("No instances found"); 2673 return; 2674 } 2675 if (subtree.size() > 1) 2676 { 2677 // More then one PowerIdlePowerSaver object is not supported and 2678 // is an error 2679 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus " 2680 "Power.IdlePowerSaver objects: {}", 2681 subtree.size()); 2682 messages::internalError(asyncResp->res); 2683 return; 2684 } 2685 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2686 { 2687 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2688 messages::internalError(asyncResp->res); 2689 return; 2690 } 2691 const std::string& path = subtree[0].first; 2692 const std::string& service = subtree[0].second.begin()->first; 2693 if (service.empty()) 2694 { 2695 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2696 messages::internalError(asyncResp->res); 2697 return; 2698 } 2699 2700 // Valid IdlePowerSaver object found, now read the current values 2701 sdbusplus::asio::getAllProperties( 2702 *crow::connections::systemBus, service, path, 2703 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2704 [asyncResp](const boost::system::error_code& ec2, 2705 const dbus::utility::DBusPropertiesMap& properties) { 2706 if (ec2) 2707 { 2708 BMCWEB_LOG_ERROR( 2709 "DBUS response error on IdlePowerSaver GetAll: {}", ec2); 2710 messages::internalError(asyncResp->res); 2711 return; 2712 } 2713 2714 if (!parseIpsProperties(asyncResp, properties)) 2715 { 2716 messages::internalError(asyncResp->res); 2717 return; 2718 } 2719 }); 2720 }); 2721 2722 BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters"); 2723 } 2724 2725 /** 2726 * @brief Sets Idle Power Saver properties. 2727 * 2728 * @param[in] asyncResp Shared pointer for generating response message. 2729 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2730 * RF request. 2731 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2732 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2733 * before entering idle state. 2734 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2735 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2736 * before exiting idle state 2737 * 2738 * @return None. 2739 */ 2740 inline void 2741 setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2742 const std::optional<bool> ipsEnable, 2743 const std::optional<uint8_t> ipsEnterUtil, 2744 const std::optional<uint64_t> ipsEnterTime, 2745 const std::optional<uint8_t> ipsExitUtil, 2746 const std::optional<uint64_t> ipsExitTime) 2747 { 2748 BMCWEB_LOG_DEBUG("Set idle power saver properties"); 2749 2750 // Get IdlePowerSaver object path: 2751 constexpr std::array<std::string_view, 1> interfaces = { 2752 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; 2753 dbus::utility::getSubTree( 2754 "/", 0, interfaces, 2755 [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2756 ipsExitTime](const boost::system::error_code& ec, 2757 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2758 if (ec) 2759 { 2760 BMCWEB_LOG_DEBUG( 2761 "DBUS response error on Power.IdlePowerSaver GetSubTree {}", 2762 ec); 2763 messages::internalError(asyncResp->res); 2764 return; 2765 } 2766 if (subtree.empty()) 2767 { 2768 // This is an optional D-Bus object, but user attempted to patch 2769 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 2770 "IdlePowerSaver"); 2771 return; 2772 } 2773 if (subtree.size() > 1) 2774 { 2775 // More then one PowerIdlePowerSaver object is not supported and 2776 // is an error 2777 BMCWEB_LOG_DEBUG( 2778 "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}", 2779 subtree.size()); 2780 messages::internalError(asyncResp->res); 2781 return; 2782 } 2783 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2784 { 2785 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!"); 2786 messages::internalError(asyncResp->res); 2787 return; 2788 } 2789 const std::string& path = subtree[0].first; 2790 const std::string& service = subtree[0].second.begin()->first; 2791 if (service.empty()) 2792 { 2793 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!"); 2794 messages::internalError(asyncResp->res); 2795 return; 2796 } 2797 2798 // Valid Power IdlePowerSaver object found, now set any values that 2799 // need to be updated 2800 2801 if (ipsEnable) 2802 { 2803 sdbusplus::asio::setProperty( 2804 *crow::connections::systemBus, service, path, 2805 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled", 2806 *ipsEnable, [asyncResp](const boost::system::error_code& ec2) { 2807 if (ec2) 2808 { 2809 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 2810 messages::internalError(asyncResp->res); 2811 return; 2812 } 2813 }); 2814 } 2815 if (ipsEnterUtil) 2816 { 2817 sdbusplus::asio::setProperty( 2818 *crow::connections::systemBus, service, path, 2819 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2820 "EnterUtilizationPercent", *ipsEnterUtil, 2821 [asyncResp](const boost::system::error_code& ec2) { 2822 if (ec2) 2823 { 2824 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 2825 messages::internalError(asyncResp->res); 2826 return; 2827 } 2828 }); 2829 } 2830 if (ipsEnterTime) 2831 { 2832 // Convert from seconds into milliseconds for DBus 2833 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2834 sdbusplus::asio::setProperty( 2835 *crow::connections::systemBus, service, path, 2836 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2837 "EnterDwellTime", timeMilliseconds, 2838 [asyncResp](const boost::system::error_code& ec2) { 2839 if (ec2) 2840 { 2841 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 2842 messages::internalError(asyncResp->res); 2843 return; 2844 } 2845 }); 2846 } 2847 if (ipsExitUtil) 2848 { 2849 sdbusplus::asio::setProperty( 2850 *crow::connections::systemBus, service, path, 2851 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2852 "ExitUtilizationPercent", *ipsExitUtil, 2853 [asyncResp](const boost::system::error_code& ec2) { 2854 if (ec2) 2855 { 2856 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 2857 messages::internalError(asyncResp->res); 2858 return; 2859 } 2860 }); 2861 } 2862 if (ipsExitTime) 2863 { 2864 // Convert from seconds into milliseconds for DBus 2865 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2866 sdbusplus::asio::setProperty( 2867 *crow::connections::systemBus, service, path, 2868 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2869 "ExitDwellTime", timeMilliseconds, 2870 [asyncResp](const boost::system::error_code& ec2) { 2871 if (ec2) 2872 { 2873 BMCWEB_LOG_DEBUG("DBUS response error {}", ec2); 2874 messages::internalError(asyncResp->res); 2875 return; 2876 } 2877 }); 2878 } 2879 }); 2880 2881 BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters"); 2882 } 2883 2884 inline void handleComputerSystemCollectionHead( 2885 crow::App& app, const crow::Request& req, 2886 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2887 { 2888 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2889 { 2890 return; 2891 } 2892 asyncResp->res.addHeader( 2893 boost::beast::http::field::link, 2894 "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby"); 2895 } 2896 2897 inline void handleComputerSystemCollectionGet( 2898 crow::App& app, const crow::Request& req, 2899 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2900 { 2901 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 2902 { 2903 return; 2904 } 2905 2906 asyncResp->res.addHeader( 2907 boost::beast::http::field::link, 2908 "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby"); 2909 asyncResp->res.jsonValue["@odata.type"] = 2910 "#ComputerSystemCollection.ComputerSystemCollection"; 2911 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2912 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2913 2914 nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"]; 2915 ifaceArray = nlohmann::json::array(); 2916 if constexpr (bmcwebEnableMultiHost) 2917 { 2918 asyncResp->res.jsonValue["Members@odata.count"] = 0; 2919 // Option currently returns no systems. TBD 2920 return; 2921 } 2922 asyncResp->res.jsonValue["Members@odata.count"] = 1; 2923 nlohmann::json::object_t system; 2924 system["@odata.id"] = "/redfish/v1/Systems/system"; 2925 ifaceArray.emplace_back(std::move(system)); 2926 sdbusplus::asio::getProperty<std::string>( 2927 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 2928 "/xyz/openbmc_project/network/hypervisor", 2929 "xyz.openbmc_project.Network.SystemConfiguration", "HostName", 2930 [asyncResp](const boost::system::error_code& ec2, 2931 const std::string& /*hostName*/) { 2932 if (ec2) 2933 { 2934 return; 2935 } 2936 auto val = asyncResp->res.jsonValue.find("Members@odata.count"); 2937 if (val == asyncResp->res.jsonValue.end()) 2938 { 2939 BMCWEB_LOG_CRITICAL("Count wasn't found??"); 2940 return; 2941 } 2942 uint64_t* count = val->get_ptr<uint64_t*>(); 2943 if (count == nullptr) 2944 { 2945 BMCWEB_LOG_CRITICAL("Count wasn't found??"); 2946 return; 2947 } 2948 *count = *count + 1; 2949 BMCWEB_LOG_DEBUG("Hypervisor is available"); 2950 nlohmann::json& ifaceArray2 = asyncResp->res.jsonValue["Members"]; 2951 nlohmann::json::object_t hypervisor; 2952 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor"; 2953 ifaceArray2.emplace_back(std::move(hypervisor)); 2954 }); 2955 } 2956 2957 /** 2958 * Function transceives data with dbus directly. 2959 */ 2960 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2961 { 2962 constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2963 constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2964 constexpr const char* interfaceName = 2965 "xyz.openbmc_project.Control.Host.NMI"; 2966 constexpr const char* method = "NMI"; 2967 2968 crow::connections::systemBus->async_method_call( 2969 [asyncResp](const boost::system::error_code& ec) { 2970 if (ec) 2971 { 2972 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec); 2973 messages::internalError(asyncResp->res); 2974 return; 2975 } 2976 messages::success(asyncResp->res); 2977 }, 2978 serviceName, objectPath, interfaceName, method); 2979 } 2980 2981 /** 2982 * Handle error responses from d-bus for system power requests 2983 */ 2984 inline void handleSystemActionResetError(const boost::system::error_code& ec, 2985 const sdbusplus::message_t& eMsg, 2986 std::string_view resetType, 2987 crow::Response& res) 2988 { 2989 if (ec.value() == boost::asio::error::invalid_argument) 2990 { 2991 messages::actionParameterNotSupported(res, resetType, "Reset"); 2992 return; 2993 } 2994 2995 if (eMsg.get_error() == nullptr) 2996 { 2997 BMCWEB_LOG_ERROR("D-Bus response error: {}", ec); 2998 messages::internalError(res); 2999 return; 3000 } 3001 std::string_view errorMessage = eMsg.get_error()->name; 3002 3003 // If operation failed due to BMC not being in Ready state, tell 3004 // user to retry in a bit 3005 if ((errorMessage == 3006 std::string_view( 3007 "xyz.openbmc_project.State.Chassis.Error.BMCNotReady")) || 3008 (errorMessage == 3009 std::string_view("xyz.openbmc_project.State.Host.Error.BMCNotReady"))) 3010 { 3011 BMCWEB_LOG_DEBUG("BMC not ready, operation not allowed right now"); 3012 messages::serviceTemporarilyUnavailable(res, "10"); 3013 return; 3014 } 3015 3016 BMCWEB_LOG_ERROR("System Action Reset transition fail {} sdbusplus:{}", ec, 3017 errorMessage); 3018 messages::internalError(res); 3019 } 3020 3021 inline void handleComputerSystemResetActionPost( 3022 crow::App& app, const crow::Request& req, 3023 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3024 const std::string& systemName) 3025 { 3026 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3027 { 3028 return; 3029 } 3030 if (systemName != "system") 3031 { 3032 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3033 systemName); 3034 return; 3035 } 3036 if constexpr (bmcwebEnableMultiHost) 3037 { 3038 // Option currently returns no systems. TBD 3039 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3040 systemName); 3041 return; 3042 } 3043 std::string resetType; 3044 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType)) 3045 { 3046 return; 3047 } 3048 3049 // Get the command and host vs. chassis 3050 std::string command; 3051 bool hostCommand = true; 3052 if ((resetType == "On") || (resetType == "ForceOn")) 3053 { 3054 command = "xyz.openbmc_project.State.Host.Transition.On"; 3055 hostCommand = true; 3056 } 3057 else if (resetType == "ForceOff") 3058 { 3059 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 3060 hostCommand = false; 3061 } 3062 else if (resetType == "ForceRestart") 3063 { 3064 command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 3065 hostCommand = true; 3066 } 3067 else if (resetType == "GracefulShutdown") 3068 { 3069 command = "xyz.openbmc_project.State.Host.Transition.Off"; 3070 hostCommand = true; 3071 } 3072 else if (resetType == "GracefulRestart") 3073 { 3074 command = 3075 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 3076 hostCommand = true; 3077 } 3078 else if (resetType == "PowerCycle") 3079 { 3080 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 3081 hostCommand = true; 3082 } 3083 else if (resetType == "Nmi") 3084 { 3085 doNMI(asyncResp); 3086 return; 3087 } 3088 else 3089 { 3090 messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); 3091 return; 3092 } 3093 3094 if (hostCommand) 3095 { 3096 sdbusplus::asio::setProperty( 3097 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 3098 "/xyz/openbmc_project/state/host0", 3099 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 3100 command, 3101 [asyncResp, resetType](const boost::system::error_code& ec, 3102 sdbusplus::message_t& sdbusErrMsg) { 3103 if (ec) 3104 { 3105 handleSystemActionResetError(ec, sdbusErrMsg, resetType, 3106 asyncResp->res); 3107 3108 return; 3109 } 3110 messages::success(asyncResp->res); 3111 }); 3112 } 3113 else 3114 { 3115 sdbusplus::asio::setProperty( 3116 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 3117 "/xyz/openbmc_project/state/chassis0", 3118 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 3119 command, 3120 [asyncResp, resetType](const boost::system::error_code& ec, 3121 sdbusplus::message_t& sdbusErrMsg) { 3122 if (ec) 3123 { 3124 handleSystemActionResetError(ec, sdbusErrMsg, resetType, 3125 asyncResp->res); 3126 return; 3127 } 3128 messages::success(asyncResp->res); 3129 }); 3130 } 3131 } 3132 3133 inline void handleComputerSystemHead( 3134 App& app, const crow::Request& req, 3135 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3136 const std::string& /*systemName*/) 3137 { 3138 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3139 { 3140 return; 3141 } 3142 3143 asyncResp->res.addHeader( 3144 boost::beast::http::field::link, 3145 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3146 } 3147 3148 inline void afterPortRequest( 3149 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3150 const boost::system::error_code& ec, 3151 const std::vector<std::tuple<std::string, std::string, bool>>& socketData) 3152 { 3153 if (ec) 3154 { 3155 messages::internalError(asyncResp->res); 3156 return; 3157 } 3158 for (const auto& data : socketData) 3159 { 3160 const std::string& socketPath = get<0>(data); 3161 const std::string& protocolName = get<1>(data); 3162 bool isProtocolEnabled = get<2>(data); 3163 nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"]; 3164 dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled; 3165 // need to retrieve port number for 3166 // obmc-console-ssh service 3167 if (protocolName == "SSH") 3168 { 3169 getPortNumber(socketPath, [asyncResp, protocolName]( 3170 const boost::system::error_code& ec1, 3171 int portNumber) { 3172 if (ec1) 3173 { 3174 messages::internalError(asyncResp->res); 3175 return; 3176 } 3177 nlohmann::json& dataJson1 = 3178 asyncResp->res.jsonValue["SerialConsole"]; 3179 dataJson1[protocolName]["Port"] = portNumber; 3180 }); 3181 } 3182 } 3183 } 3184 3185 inline void 3186 handleComputerSystemGet(crow::App& app, const crow::Request& req, 3187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3188 const std::string& systemName) 3189 { 3190 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3191 { 3192 return; 3193 } 3194 3195 if constexpr (bmcwebEnableMultiHost) 3196 { 3197 // Option currently returns no systems. TBD 3198 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3199 systemName); 3200 return; 3201 } 3202 3203 if (systemName == "hypervisor") 3204 { 3205 handleHypervisorSystemGet(asyncResp); 3206 return; 3207 } 3208 3209 if (systemName != "system") 3210 { 3211 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3212 systemName); 3213 return; 3214 } 3215 asyncResp->res.addHeader( 3216 boost::beast::http::field::link, 3217 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3218 asyncResp->res.jsonValue["@odata.type"] = 3219 "#ComputerSystem.v1_16_0.ComputerSystem"; 3220 asyncResp->res.jsonValue["Name"] = "system"; 3221 asyncResp->res.jsonValue["Id"] = "system"; 3222 asyncResp->res.jsonValue["SystemType"] = "Physical"; 3223 asyncResp->res.jsonValue["Description"] = "Computer System"; 3224 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 3225 if constexpr (bmcwebEnableProcMemStatus) 3226 { 3227 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 3228 "Disabled"; 3229 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 3230 "Disabled"; 3231 } 3232 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 3233 double(0); 3234 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 3235 3236 asyncResp->res.jsonValue["Processors"]["@odata.id"] = 3237 "/redfish/v1/Systems/system/Processors"; 3238 asyncResp->res.jsonValue["Memory"]["@odata.id"] = 3239 "/redfish/v1/Systems/system/Memory"; 3240 asyncResp->res.jsonValue["Storage"]["@odata.id"] = 3241 "/redfish/v1/Systems/system/Storage"; 3242 asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = 3243 "/redfish/v1/Systems/system/FabricAdapters"; 3244 3245 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = 3246 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"; 3247 asyncResp->res 3248 .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = 3249 "/redfish/v1/Systems/system/ResetActionInfo"; 3250 3251 asyncResp->res.jsonValue["LogServices"]["@odata.id"] = 3252 "/redfish/v1/Systems/system/LogServices"; 3253 asyncResp->res.jsonValue["Bios"]["@odata.id"] = 3254 "/redfish/v1/Systems/system/Bios"; 3255 3256 nlohmann::json::array_t managedBy; 3257 nlohmann::json& manager = managedBy.emplace_back(); 3258 manager["@odata.id"] = "/redfish/v1/Managers/bmc"; 3259 asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); 3260 asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 3261 asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 3262 3263 // Fill in SerialConsole info 3264 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 3265 asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true; 3266 3267 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true; 3268 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; 3269 asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = 3270 "Press ~. to exit console"; 3271 getPortStatusAndPath(std::span{protocolToDBusForSystems}, 3272 std::bind_front(afterPortRequest, asyncResp)); 3273 3274 #ifdef BMCWEB_ENABLE_KVM 3275 // Fill in GraphicalConsole info 3276 asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 3277 asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; 3278 asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = 3279 nlohmann::json::array_t({"KVMIP"}); 3280 3281 #endif // BMCWEB_ENABLE_KVM 3282 3283 auto health = std::make_shared<HealthPopulate>(asyncResp); 3284 if constexpr (bmcwebEnableHealthPopulate) 3285 { 3286 constexpr std::array<std::string_view, 4> inventoryForSystems{ 3287 "xyz.openbmc_project.Inventory.Item.Dimm", 3288 "xyz.openbmc_project.Inventory.Item.Cpu", 3289 "xyz.openbmc_project.Inventory.Item.Drive", 3290 "xyz.openbmc_project.Inventory.Item.StorageController"}; 3291 3292 dbus::utility::getSubTreePaths( 3293 "/", 0, inventoryForSystems, 3294 [health](const boost::system::error_code& ec, 3295 const std::vector<std::string>& resp) { 3296 if (ec) 3297 { 3298 // no inventory 3299 return; 3300 } 3301 3302 health->inventory = resp; 3303 }); 3304 health->populate(); 3305 } 3306 3307 getMainChassisId(asyncResp, 3308 [](const std::string& chassisId, 3309 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 3310 nlohmann::json::array_t chassisArray; 3311 nlohmann::json& chassis = chassisArray.emplace_back(); 3312 chassis["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}", 3313 chassisId); 3314 aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); 3315 }); 3316 3317 getLocationIndicatorActive(asyncResp); 3318 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 3319 getIndicatorLedState(asyncResp); 3320 getComputerSystem(asyncResp, health); 3321 getHostState(asyncResp); 3322 getBootProperties(asyncResp); 3323 getBootProgress(asyncResp); 3324 getBootProgressLastStateTime(asyncResp); 3325 pcie_util::getPCIeDeviceList(asyncResp, "PCIeDevices"); 3326 getHostWatchdogTimer(asyncResp); 3327 getPowerRestorePolicy(asyncResp); 3328 getStopBootOnFault(asyncResp); 3329 getAutomaticRetryPolicy(asyncResp); 3330 getLastResetTime(asyncResp); 3331 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 3332 getProvisioningStatus(asyncResp); 3333 #endif 3334 getTrustedModuleRequiredToBoot(asyncResp); 3335 getPowerMode(asyncResp); 3336 getIdlePowerSaver(asyncResp); 3337 } 3338 3339 inline void handleComputerSystemPatch( 3340 crow::App& app, const crow::Request& req, 3341 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3342 const std::string& systemName) 3343 { 3344 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3345 { 3346 return; 3347 } 3348 if constexpr (bmcwebEnableMultiHost) 3349 { 3350 // Option currently returns no systems. TBD 3351 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3352 systemName); 3353 return; 3354 } 3355 if (systemName != "system") 3356 { 3357 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3358 systemName); 3359 return; 3360 } 3361 3362 asyncResp->res.addHeader( 3363 boost::beast::http::field::link, 3364 "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); 3365 3366 std::optional<bool> locationIndicatorActive; 3367 std::optional<std::string> indicatorLed; 3368 std::optional<std::string> assetTag; 3369 std::optional<std::string> powerRestorePolicy; 3370 std::optional<std::string> powerMode; 3371 std::optional<bool> wdtEnable; 3372 std::optional<std::string> wdtTimeOutAction; 3373 std::optional<std::string> bootSource; 3374 std::optional<std::string> bootType; 3375 std::optional<std::string> bootEnable; 3376 std::optional<std::string> bootAutomaticRetry; 3377 std::optional<uint32_t> bootAutomaticRetryAttempts; 3378 std::optional<bool> bootTrustedModuleRequired; 3379 std::optional<std::string> stopBootOnFault; 3380 std::optional<bool> ipsEnable; 3381 std::optional<uint8_t> ipsEnterUtil; 3382 std::optional<uint64_t> ipsEnterTime; 3383 std::optional<uint8_t> ipsExitUtil; 3384 std::optional<uint64_t> ipsExitTime; 3385 3386 // clang-format off 3387 if (!json_util::readJsonPatch( 3388 req, asyncResp->res, 3389 "IndicatorLED", indicatorLed, 3390 "LocationIndicatorActive", locationIndicatorActive, 3391 "AssetTag", assetTag, 3392 "PowerRestorePolicy", powerRestorePolicy, 3393 "PowerMode", powerMode, 3394 "HostWatchdogTimer/FunctionEnabled", wdtEnable, 3395 "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction, 3396 "Boot/BootSourceOverrideTarget", bootSource, 3397 "Boot/BootSourceOverrideMode", bootType, 3398 "Boot/BootSourceOverrideEnabled", bootEnable, 3399 "Boot/AutomaticRetryConfig", bootAutomaticRetry, 3400 "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts, 3401 "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired, 3402 "Boot/StopBootOnFault", stopBootOnFault, 3403 "IdlePowerSaver/Enabled", ipsEnable, 3404 "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil, 3405 "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime, 3406 "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil, 3407 "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime)) 3408 { 3409 return; 3410 } 3411 // clang-format on 3412 3413 asyncResp->res.result(boost::beast::http::status::no_content); 3414 3415 if (assetTag) 3416 { 3417 setAssetTag(asyncResp, *assetTag); 3418 } 3419 3420 if (wdtEnable || wdtTimeOutAction) 3421 { 3422 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3423 } 3424 3425 if (bootSource || bootType || bootEnable) 3426 { 3427 setBootProperties(asyncResp, bootSource, bootType, bootEnable); 3428 } 3429 if (bootAutomaticRetry) 3430 { 3431 setAutomaticRetry(asyncResp, *bootAutomaticRetry); 3432 } 3433 3434 if (bootAutomaticRetryAttempts) 3435 { 3436 setAutomaticRetryAttempts(asyncResp, 3437 bootAutomaticRetryAttempts.value()); 3438 } 3439 3440 if (bootTrustedModuleRequired) 3441 { 3442 setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired); 3443 } 3444 3445 if (stopBootOnFault) 3446 { 3447 setStopBootOnFault(asyncResp, *stopBootOnFault); 3448 } 3449 3450 if (locationIndicatorActive) 3451 { 3452 setLocationIndicatorActive(asyncResp, *locationIndicatorActive); 3453 } 3454 3455 // TODO (Gunnar): Remove IndicatorLED after enough time has 3456 // passed 3457 if (indicatorLed) 3458 { 3459 setIndicatorLedState(asyncResp, *indicatorLed); 3460 asyncResp->res.addHeader(boost::beast::http::field::warning, 3461 "299 - \"IndicatorLED is deprecated. Use " 3462 "LocationIndicatorActive instead.\""); 3463 } 3464 3465 if (powerRestorePolicy) 3466 { 3467 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3468 } 3469 3470 if (powerMode) 3471 { 3472 setPowerMode(asyncResp, *powerMode); 3473 } 3474 3475 if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime) 3476 { 3477 setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, 3478 ipsExitUtil, ipsExitTime); 3479 } 3480 } 3481 3482 inline void handleSystemCollectionResetActionHead( 3483 crow::App& app, const crow::Request& req, 3484 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3485 const std::string& /*systemName*/) 3486 { 3487 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3488 { 3489 return; 3490 } 3491 asyncResp->res.addHeader( 3492 boost::beast::http::field::link, 3493 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3494 } 3495 inline void handleSystemCollectionResetActionGet( 3496 crow::App& app, const crow::Request& req, 3497 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 3498 const std::string& systemName) 3499 { 3500 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 3501 { 3502 return; 3503 } 3504 if constexpr (bmcwebEnableMultiHost) 3505 { 3506 // Option currently returns no systems. TBD 3507 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3508 systemName); 3509 return; 3510 } 3511 3512 if (systemName == "hypervisor") 3513 { 3514 handleHypervisorResetActionGet(asyncResp); 3515 return; 3516 } 3517 3518 if (systemName != "system") 3519 { 3520 messages::resourceNotFound(asyncResp->res, "ComputerSystem", 3521 systemName); 3522 return; 3523 } 3524 3525 asyncResp->res.addHeader( 3526 boost::beast::http::field::link, 3527 "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); 3528 3529 asyncResp->res.jsonValue["@odata.id"] = 3530 "/redfish/v1/Systems/system/ResetActionInfo"; 3531 asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; 3532 asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 3533 asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 3534 3535 nlohmann::json::array_t parameters; 3536 nlohmann::json::object_t parameter; 3537 3538 parameter["Name"] = "ResetType"; 3539 parameter["Required"] = true; 3540 parameter["DataType"] = "String"; 3541 nlohmann::json::array_t allowableValues; 3542 allowableValues.emplace_back("On"); 3543 allowableValues.emplace_back("ForceOff"); 3544 allowableValues.emplace_back("ForceOn"); 3545 allowableValues.emplace_back("ForceRestart"); 3546 allowableValues.emplace_back("GracefulRestart"); 3547 allowableValues.emplace_back("GracefulShutdown"); 3548 allowableValues.emplace_back("PowerCycle"); 3549 allowableValues.emplace_back("Nmi"); 3550 parameter["AllowableValues"] = std::move(allowableValues); 3551 parameters.emplace_back(std::move(parameter)); 3552 3553 asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 3554 } 3555 /** 3556 * SystemResetActionInfo derived class for delivering Computer Systems 3557 * ResetType AllowableValues using ResetInfo schema. 3558 */ 3559 inline void requestRoutesSystems(App& app) 3560 { 3561 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3562 .privileges(redfish::privileges::headComputerSystemCollection) 3563 .methods(boost::beast::http::verb::head)( 3564 std::bind_front(handleComputerSystemCollectionHead, std::ref(app))); 3565 3566 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 3567 .privileges(redfish::privileges::getComputerSystemCollection) 3568 .methods(boost::beast::http::verb::get)( 3569 std::bind_front(handleComputerSystemCollectionGet, std::ref(app))); 3570 3571 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3572 .privileges(redfish::privileges::headComputerSystem) 3573 .methods(boost::beast::http::verb::head)( 3574 std::bind_front(handleComputerSystemHead, std::ref(app))); 3575 3576 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3577 .privileges(redfish::privileges::getComputerSystem) 3578 .methods(boost::beast::http::verb::get)( 3579 std::bind_front(handleComputerSystemGet, std::ref(app))); 3580 3581 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") 3582 .privileges(redfish::privileges::patchComputerSystem) 3583 .methods(boost::beast::http::verb::patch)( 3584 std::bind_front(handleComputerSystemPatch, std::ref(app))); 3585 3586 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/") 3587 .privileges(redfish::privileges::postComputerSystem) 3588 .methods(boost::beast::http::verb::post)(std::bind_front( 3589 handleComputerSystemResetActionPost, std::ref(app))); 3590 3591 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3592 .privileges(redfish::privileges::headActionInfo) 3593 .methods(boost::beast::http::verb::head)(std::bind_front( 3594 handleSystemCollectionResetActionHead, std::ref(app))); 3595 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") 3596 .privileges(redfish::privileges::getActionInfo) 3597 .methods(boost::beast::http::verb::get)(std::bind_front( 3598 handleSystemCollectionResetActionGet, std::ref(app))); 3599 } 3600 } // namespace redfish 3601