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