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