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