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