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