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