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