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