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