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