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