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