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