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