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