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