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