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 std::string modeString; 1888 1889 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 1890 { 1891 aResp->res.jsonValue["PowerMode"] = "Static"; 1892 } 1893 else if ( 1894 modeValue == 1895 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 1896 { 1897 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1898 } 1899 else if (modeValue == 1900 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 1901 { 1902 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1903 } 1904 else if (modeValue == 1905 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 1906 { 1907 aResp->res.jsonValue["PowerMode"] = "OEM"; 1908 } 1909 else 1910 { 1911 // Any other values would be invalid 1912 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 1913 messages::internalError(aResp->res); 1914 } 1915 } 1916 1917 /** 1918 * @brief Retrieves system power mode 1919 * 1920 * @param[in] aResp Shared pointer for generating response message. 1921 * 1922 * @return None. 1923 */ 1924 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1925 { 1926 BMCWEB_LOG_DEBUG << "Get power mode."; 1927 1928 // Get Power Mode object path: 1929 crow::connections::systemBus->async_method_call( 1930 [aResp](const boost::system::error_code ec, 1931 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1932 if (ec) 1933 { 1934 BMCWEB_LOG_DEBUG 1935 << "DBUS response error on Power.Mode GetSubTree " << ec; 1936 // This is an optional D-Bus object so just return if 1937 // error occurs 1938 return; 1939 } 1940 if (subtree.empty()) 1941 { 1942 // As noted above, this is an optional interface so just return 1943 // if there is no instance found 1944 return; 1945 } 1946 if (subtree.size() > 1) 1947 { 1948 // More then one PowerMode object is not supported and is an 1949 // error 1950 BMCWEB_LOG_DEBUG 1951 << "Found more than 1 system D-Bus Power.Mode objects: " 1952 << subtree.size(); 1953 messages::internalError(aResp->res); 1954 return; 1955 } 1956 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1957 { 1958 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1959 messages::internalError(aResp->res); 1960 return; 1961 } 1962 const std::string& path = subtree[0].first; 1963 const std::string& service = subtree[0].second.begin()->first; 1964 if (service.empty()) 1965 { 1966 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1967 messages::internalError(aResp->res); 1968 return; 1969 } 1970 // Valid Power Mode object found, now read the current value 1971 sdbusplus::asio::getProperty<std::string>( 1972 *crow::connections::systemBus, service, path, 1973 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 1974 [aResp](const boost::system::error_code ec, 1975 const std::string& pmode) { 1976 if (ec) 1977 { 1978 BMCWEB_LOG_DEBUG 1979 << "DBUS response error on PowerMode Get: " << ec; 1980 messages::internalError(aResp->res); 1981 return; 1982 } 1983 1984 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 1985 {"Static", "MaximumPerformance", "PowerSaving"}; 1986 1987 BMCWEB_LOG_DEBUG << "Current power mode: " << pmode; 1988 translatePowerMode(aResp, pmode); 1989 }); 1990 }, 1991 "xyz.openbmc_project.ObjectMapper", 1992 "/xyz/openbmc_project/object_mapper", 1993 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1994 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 1995 } 1996 1997 /** 1998 * @brief Validate the specified mode is valid and return the PowerMode 1999 * name associated with that string 2000 * 2001 * @param[in] aResp Shared pointer for generating response message. 2002 * @param[in] modeString String representing the desired PowerMode 2003 * 2004 * @return PowerMode value or empty string if mode is not valid 2005 */ 2006 inline std::string 2007 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2008 const std::string& modeString) 2009 { 2010 std::string mode; 2011 2012 if (modeString == "Static") 2013 { 2014 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 2015 } 2016 else if (modeString == "MaximumPerformance") 2017 { 2018 mode = 2019 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2020 } 2021 else if (modeString == "PowerSaving") 2022 { 2023 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2024 } 2025 else 2026 { 2027 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2028 } 2029 return mode; 2030 } 2031 2032 /** 2033 * @brief Sets system power mode. 2034 * 2035 * @param[in] aResp Shared pointer for generating response message. 2036 * @param[in] pmode System power mode from request. 2037 * 2038 * @return None. 2039 */ 2040 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2041 const std::string& pmode) 2042 { 2043 BMCWEB_LOG_DEBUG << "Set power mode."; 2044 2045 std::string powerMode = validatePowerMode(aResp, pmode); 2046 if (powerMode.empty()) 2047 { 2048 return; 2049 } 2050 2051 // Get Power Mode object path: 2052 crow::connections::systemBus->async_method_call( 2053 [aResp, 2054 powerMode](const boost::system::error_code ec, 2055 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2056 if (ec) 2057 { 2058 BMCWEB_LOG_DEBUG 2059 << "DBUS response error on Power.Mode GetSubTree " << ec; 2060 // This is an optional D-Bus object, but user attempted to patch 2061 messages::internalError(aResp->res); 2062 return; 2063 } 2064 if (subtree.empty()) 2065 { 2066 // This is an optional D-Bus object, but user attempted to patch 2067 messages::resourceNotFound(aResp->res, "ComputerSystem", 2068 "PowerMode"); 2069 return; 2070 } 2071 if (subtree.size() > 1) 2072 { 2073 // More then one PowerMode object is not supported and is an 2074 // error 2075 BMCWEB_LOG_DEBUG 2076 << "Found more than 1 system D-Bus Power.Mode objects: " 2077 << subtree.size(); 2078 messages::internalError(aResp->res); 2079 return; 2080 } 2081 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2082 { 2083 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2084 messages::internalError(aResp->res); 2085 return; 2086 } 2087 const std::string& path = subtree[0].first; 2088 const std::string& service = subtree[0].second.begin()->first; 2089 if (service.empty()) 2090 { 2091 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2092 messages::internalError(aResp->res); 2093 return; 2094 } 2095 2096 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2097 << path; 2098 2099 // Set the Power Mode property 2100 crow::connections::systemBus->async_method_call( 2101 [aResp](const boost::system::error_code ec) { 2102 if (ec) 2103 { 2104 messages::internalError(aResp->res); 2105 return; 2106 } 2107 }, 2108 service, path, "org.freedesktop.DBus.Properties", "Set", 2109 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2110 dbus::utility::DbusVariantType(powerMode)); 2111 }, 2112 "xyz.openbmc_project.ObjectMapper", 2113 "/xyz/openbmc_project/object_mapper", 2114 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2115 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2116 } 2117 2118 /** 2119 * @brief Translates watchdog timeout action DBUS property value to redfish. 2120 * 2121 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2122 * 2123 * @return Returns as a string, the timeout action in Redfish terms. If 2124 * translation cannot be done, returns an empty string. 2125 */ 2126 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2127 { 2128 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2129 { 2130 return "None"; 2131 } 2132 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2133 { 2134 return "ResetSystem"; 2135 } 2136 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2137 { 2138 return "PowerDown"; 2139 } 2140 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2141 { 2142 return "PowerCycle"; 2143 } 2144 2145 return ""; 2146 } 2147 2148 /** 2149 *@brief Translates timeout action from Redfish to DBUS property value. 2150 * 2151 *@param[in] rfAction The timeout action in Redfish. 2152 * 2153 *@return Returns as a string, the time_out action as expected by DBUS. 2154 *If translation cannot be done, returns an empty string. 2155 */ 2156 2157 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2158 { 2159 if (rfAction == "None") 2160 { 2161 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2162 } 2163 if (rfAction == "PowerCycle") 2164 { 2165 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2166 } 2167 if (rfAction == "PowerDown") 2168 { 2169 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2170 } 2171 if (rfAction == "ResetSystem") 2172 { 2173 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2174 } 2175 2176 return ""; 2177 } 2178 2179 /** 2180 * @brief Retrieves host watchdog timer properties over DBUS 2181 * 2182 * @param[in] aResp Shared pointer for completing asynchronous calls. 2183 * 2184 * @return None. 2185 */ 2186 inline void 2187 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2188 { 2189 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2190 crow::connections::systemBus->async_method_call( 2191 [aResp](const boost::system::error_code ec, 2192 const dbus::utility::DBusPropertiesMap& properties) { 2193 if (ec) 2194 { 2195 // watchdog service is stopped 2196 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2197 return; 2198 } 2199 2200 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2201 2202 nlohmann::json& hostWatchdogTimer = 2203 aResp->res.jsonValue["HostWatchdogTimer"]; 2204 2205 // watchdog service is running/enabled 2206 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2207 2208 for (const auto& property : properties) 2209 { 2210 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2211 if (property.first == "Enabled") 2212 { 2213 const bool* state = std::get_if<bool>(&property.second); 2214 2215 if (state == nullptr) 2216 { 2217 messages::internalError(aResp->res); 2218 return; 2219 } 2220 2221 hostWatchdogTimer["FunctionEnabled"] = *state; 2222 } 2223 else if (property.first == "ExpireAction") 2224 { 2225 const std::string* s = 2226 std::get_if<std::string>(&property.second); 2227 if (s == nullptr) 2228 { 2229 messages::internalError(aResp->res); 2230 return; 2231 } 2232 2233 std::string action = dbusToRfWatchdogAction(*s); 2234 if (action.empty()) 2235 { 2236 messages::internalError(aResp->res); 2237 return; 2238 } 2239 hostWatchdogTimer["TimeoutAction"] = action; 2240 } 2241 } 2242 }, 2243 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2244 "org.freedesktop.DBus.Properties", "GetAll", 2245 "xyz.openbmc_project.State.Watchdog"); 2246 } 2247 2248 /** 2249 * @brief Sets Host WatchDog Timer properties. 2250 * 2251 * @param[in] aResp Shared pointer for generating response message. 2252 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2253 * RF request. 2254 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2255 * 2256 * @return None. 2257 */ 2258 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2259 const std::optional<bool> wdtEnable, 2260 const std::optional<std::string>& wdtTimeOutAction) 2261 { 2262 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2263 2264 if (wdtTimeOutAction) 2265 { 2266 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2267 // check if TimeOut Action is Valid 2268 if (wdtTimeOutActStr.empty()) 2269 { 2270 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2271 << *wdtTimeOutAction; 2272 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2273 "TimeoutAction"); 2274 return; 2275 } 2276 2277 crow::connections::systemBus->async_method_call( 2278 [aResp](const boost::system::error_code ec) { 2279 if (ec) 2280 { 2281 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2282 messages::internalError(aResp->res); 2283 return; 2284 } 2285 }, 2286 "xyz.openbmc_project.Watchdog", 2287 "/xyz/openbmc_project/watchdog/host0", 2288 "org.freedesktop.DBus.Properties", "Set", 2289 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2290 dbus::utility::DbusVariantType(wdtTimeOutActStr)); 2291 } 2292 2293 if (wdtEnable) 2294 { 2295 crow::connections::systemBus->async_method_call( 2296 [aResp](const boost::system::error_code ec) { 2297 if (ec) 2298 { 2299 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2300 messages::internalError(aResp->res); 2301 return; 2302 } 2303 }, 2304 "xyz.openbmc_project.Watchdog", 2305 "/xyz/openbmc_project/watchdog/host0", 2306 "org.freedesktop.DBus.Properties", "Set", 2307 "xyz.openbmc_project.State.Watchdog", "Enabled", 2308 dbus::utility::DbusVariantType(*wdtEnable)); 2309 } 2310 } 2311 2312 using ipsPropertiesType = 2313 std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>; 2314 /** 2315 * @brief Parse the Idle Power Saver properties into json 2316 * 2317 * @param[in] aResp Shared pointer for completing asynchronous calls. 2318 * @param[in] properties IPS property data from DBus. 2319 * 2320 * @return true if successful 2321 */ 2322 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2323 ipsPropertiesType& properties) 2324 { 2325 for (const auto& property : properties) 2326 { 2327 if (property.first == "Enabled") 2328 { 2329 const bool* state = std::get_if<bool>(&property.second); 2330 if (state == nullptr) 2331 { 2332 return false; 2333 } 2334 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state; 2335 } 2336 else if (property.first == "EnterUtilizationPercent") 2337 { 2338 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2339 if (util == nullptr) 2340 { 2341 return false; 2342 } 2343 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2344 } 2345 else if (property.first == "EnterDwellTime") 2346 { 2347 // Convert Dbus time from milliseconds to seconds 2348 const uint64_t* timeMilliseconds = 2349 std::get_if<uint64_t>(&property.second); 2350 if (timeMilliseconds == nullptr) 2351 { 2352 return false; 2353 } 2354 const std::chrono::duration<uint64_t, std::milli> ms( 2355 *timeMilliseconds); 2356 aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = 2357 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2358 .count(); 2359 } 2360 else if (property.first == "ExitUtilizationPercent") 2361 { 2362 const uint8_t* util = std::get_if<uint8_t>(&property.second); 2363 if (util == nullptr) 2364 { 2365 return false; 2366 } 2367 aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util; 2368 } 2369 else if (property.first == "ExitDwellTime") 2370 { 2371 // Convert Dbus time from milliseconds to seconds 2372 const uint64_t* timeMilliseconds = 2373 std::get_if<uint64_t>(&property.second); 2374 if (timeMilliseconds == nullptr) 2375 { 2376 return false; 2377 } 2378 const std::chrono::duration<uint64_t, std::milli> ms( 2379 *timeMilliseconds); 2380 aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = 2381 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) 2382 .count(); 2383 } 2384 else 2385 { 2386 BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: " 2387 << property.first; 2388 } 2389 } 2390 2391 return true; 2392 } 2393 2394 /** 2395 * @brief Retrieves host watchdog timer properties over DBUS 2396 * 2397 * @param[in] aResp Shared pointer for completing asynchronous calls. 2398 * 2399 * @return None. 2400 */ 2401 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2402 { 2403 BMCWEB_LOG_DEBUG << "Get idle power saver parameters"; 2404 2405 // Get IdlePowerSaver object path: 2406 crow::connections::systemBus->async_method_call( 2407 [aResp](const boost::system::error_code ec, 2408 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2409 if (ec) 2410 { 2411 BMCWEB_LOG_DEBUG 2412 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2413 << ec; 2414 messages::internalError(aResp->res); 2415 return; 2416 } 2417 if (subtree.empty()) 2418 { 2419 // This is an optional interface so just return 2420 // if there is no instance found 2421 BMCWEB_LOG_DEBUG << "No instances found"; 2422 return; 2423 } 2424 if (subtree.size() > 1) 2425 { 2426 // More then one PowerIdlePowerSaver object is not supported and 2427 // is an error 2428 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus " 2429 "Power.IdlePowerSaver objects: " 2430 << subtree.size(); 2431 messages::internalError(aResp->res); 2432 return; 2433 } 2434 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2435 { 2436 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2437 messages::internalError(aResp->res); 2438 return; 2439 } 2440 const std::string& path = subtree[0].first; 2441 const std::string& service = subtree[0].second.begin()->first; 2442 if (service.empty()) 2443 { 2444 BMCWEB_LOG_DEBUG 2445 << "Power.IdlePowerSaver service mapper error!"; 2446 messages::internalError(aResp->res); 2447 return; 2448 } 2449 2450 // Valid IdlePowerSaver object found, now read the current values 2451 crow::connections::systemBus->async_method_call( 2452 [aResp](const boost::system::error_code ec, 2453 ipsPropertiesType& properties) { 2454 if (ec) 2455 { 2456 BMCWEB_LOG_ERROR 2457 << "DBUS response error on IdlePowerSaver GetAll: " 2458 << ec; 2459 messages::internalError(aResp->res); 2460 return; 2461 } 2462 2463 if (!parseIpsProperties(aResp, properties)) 2464 { 2465 messages::internalError(aResp->res); 2466 return; 2467 } 2468 }, 2469 service, path, "org.freedesktop.DBus.Properties", "GetAll", 2470 "xyz.openbmc_project.Control.Power.IdlePowerSaver"); 2471 }, 2472 "xyz.openbmc_project.ObjectMapper", 2473 "/xyz/openbmc_project/object_mapper", 2474 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2475 std::array<const char*, 1>{ 2476 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2477 2478 BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters"; 2479 } 2480 2481 /** 2482 * @brief Sets Idle Power Saver properties. 2483 * 2484 * @param[in] aResp Shared pointer for generating response message. 2485 * @param[in] ipsEnable The IPS Enable value (true/false) from incoming 2486 * RF request. 2487 * @param[in] ipsEnterUtil The utilization limit to enter idle state. 2488 * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil 2489 * before entering idle state. 2490 * @param[in] ipsExitUtil The utilization limit when exiting idle state. 2491 * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil 2492 * before exiting idle state 2493 * 2494 * @return None. 2495 */ 2496 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2497 const std::optional<bool> ipsEnable, 2498 const std::optional<uint8_t> ipsEnterUtil, 2499 const std::optional<uint64_t> ipsEnterTime, 2500 const std::optional<uint8_t> ipsExitUtil, 2501 const std::optional<uint64_t> ipsExitTime) 2502 { 2503 BMCWEB_LOG_DEBUG << "Set idle power saver properties"; 2504 2505 // Get IdlePowerSaver object path: 2506 crow::connections::systemBus->async_method_call( 2507 [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, 2508 ipsExitTime](const boost::system::error_code ec, 2509 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2510 if (ec) 2511 { 2512 BMCWEB_LOG_DEBUG 2513 << "DBUS response error on Power.IdlePowerSaver GetSubTree " 2514 << ec; 2515 messages::internalError(aResp->res); 2516 return; 2517 } 2518 if (subtree.empty()) 2519 { 2520 // This is an optional D-Bus object, but user attempted to patch 2521 messages::resourceNotFound(aResp->res, "ComputerSystem", 2522 "IdlePowerSaver"); 2523 return; 2524 } 2525 if (subtree.size() > 1) 2526 { 2527 // More then one PowerIdlePowerSaver object is not supported and 2528 // is an error 2529 BMCWEB_LOG_DEBUG 2530 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: " 2531 << subtree.size(); 2532 messages::internalError(aResp->res); 2533 return; 2534 } 2535 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2536 { 2537 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; 2538 messages::internalError(aResp->res); 2539 return; 2540 } 2541 const std::string& path = subtree[0].first; 2542 const std::string& service = subtree[0].second.begin()->first; 2543 if (service.empty()) 2544 { 2545 BMCWEB_LOG_DEBUG 2546 << "Power.IdlePowerSaver service mapper error!"; 2547 messages::internalError(aResp->res); 2548 return; 2549 } 2550 2551 // Valid Power IdlePowerSaver object found, now set any values that 2552 // need to be updated 2553 2554 if (ipsEnable) 2555 { 2556 crow::connections::systemBus->async_method_call( 2557 [aResp](const boost::system::error_code ec) { 2558 if (ec) 2559 { 2560 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2561 messages::internalError(aResp->res); 2562 return; 2563 } 2564 }, 2565 service, path, "org.freedesktop.DBus.Properties", "Set", 2566 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2567 "Enabled", dbus::utility::DbusVariantType(*ipsEnable)); 2568 } 2569 if (ipsEnterUtil) 2570 { 2571 crow::connections::systemBus->async_method_call( 2572 [aResp](const boost::system::error_code ec) { 2573 if (ec) 2574 { 2575 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2576 messages::internalError(aResp->res); 2577 return; 2578 } 2579 }, 2580 service, path, "org.freedesktop.DBus.Properties", "Set", 2581 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2582 "EnterUtilizationPercent", 2583 dbus::utility::DbusVariantType(*ipsEnterUtil)); 2584 } 2585 if (ipsEnterTime) 2586 { 2587 // Convert from seconds into milliseconds for DBus 2588 const uint64_t timeMilliseconds = *ipsEnterTime * 1000; 2589 crow::connections::systemBus->async_method_call( 2590 [aResp](const boost::system::error_code ec) { 2591 if (ec) 2592 { 2593 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2594 messages::internalError(aResp->res); 2595 return; 2596 } 2597 }, 2598 service, path, "org.freedesktop.DBus.Properties", "Set", 2599 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2600 "EnterDwellTime", 2601 dbus::utility::DbusVariantType(timeMilliseconds)); 2602 } 2603 if (ipsExitUtil) 2604 { 2605 crow::connections::systemBus->async_method_call( 2606 [aResp](const boost::system::error_code ec) { 2607 if (ec) 2608 { 2609 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2610 messages::internalError(aResp->res); 2611 return; 2612 } 2613 }, 2614 service, path, "org.freedesktop.DBus.Properties", "Set", 2615 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2616 "ExitUtilizationPercent", 2617 dbus::utility::DbusVariantType(*ipsExitUtil)); 2618 } 2619 if (ipsExitTime) 2620 { 2621 // Convert from seconds into milliseconds for DBus 2622 const uint64_t timeMilliseconds = *ipsExitTime * 1000; 2623 crow::connections::systemBus->async_method_call( 2624 [aResp](const boost::system::error_code ec) { 2625 if (ec) 2626 { 2627 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2628 messages::internalError(aResp->res); 2629 return; 2630 } 2631 }, 2632 service, path, "org.freedesktop.DBus.Properties", "Set", 2633 "xyz.openbmc_project.Control.Power.IdlePowerSaver", 2634 "ExitDwellTime", 2635 dbus::utility::DbusVariantType(timeMilliseconds)); 2636 } 2637 }, 2638 "xyz.openbmc_project.ObjectMapper", 2639 "/xyz/openbmc_project/object_mapper", 2640 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2641 std::array<const char*, 1>{ 2642 "xyz.openbmc_project.Control.Power.IdlePowerSaver"}); 2643 2644 BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters"; 2645 } 2646 2647 /** 2648 * SystemsCollection derived class for delivering ComputerSystems Collection 2649 * Schema 2650 */ 2651 inline void requestRoutesSystemsCollection(App& app) 2652 { 2653 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2654 .privileges(redfish::privileges::getComputerSystemCollection) 2655 .methods(boost::beast::http::verb::get)( 2656 [&app](const crow::Request& req, 2657 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2658 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res)) 2659 { 2660 return; 2661 } 2662 asyncResp->res.jsonValue["@odata.type"] = 2663 "#ComputerSystemCollection.ComputerSystemCollection"; 2664 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2665 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2666 2667 sdbusplus::asio::getProperty<std::string>( 2668 *crow::connections::systemBus, 2669 "xyz.openbmc_project.Settings", 2670 "/xyz/openbmc_project/network/hypervisor", 2671 "xyz.openbmc_project.Network.SystemConfiguration", 2672 "HostName", 2673 [asyncResp](const boost::system::error_code ec, 2674 const std::string& /*hostName*/) { 2675 nlohmann::json& ifaceArray = 2676 asyncResp->res.jsonValue["Members"]; 2677 ifaceArray = nlohmann::json::array(); 2678 auto& count = 2679 asyncResp->res.jsonValue["Members@odata.count"]; 2680 ifaceArray.push_back( 2681 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2682 count = ifaceArray.size(); 2683 if (!ec) 2684 { 2685 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2686 ifaceArray.push_back( 2687 {{"@odata.id", 2688 "/redfish/v1/Systems/hypervisor"}}); 2689 count = ifaceArray.size(); 2690 } 2691 }); 2692 }); 2693 } 2694 2695 /** 2696 * Function transceives data with dbus directly. 2697 */ 2698 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2699 { 2700 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2701 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2702 constexpr char const* interfaceName = 2703 "xyz.openbmc_project.Control.Host.NMI"; 2704 constexpr char const* method = "NMI"; 2705 2706 crow::connections::systemBus->async_method_call( 2707 [asyncResp](const boost::system::error_code ec) { 2708 if (ec) 2709 { 2710 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2711 messages::internalError(asyncResp->res); 2712 return; 2713 } 2714 messages::success(asyncResp->res); 2715 }, 2716 serviceName, objectPath, interfaceName, method); 2717 } 2718 2719 /** 2720 * SystemActionsReset class supports handle POST method for Reset action. 2721 * The class retrieves and sends data directly to D-Bus. 2722 */ 2723 inline void requestRoutesSystemActionsReset(App& app) 2724 { 2725 /** 2726 * Function handles POST method request. 2727 * Analyzes POST body message before sends Reset request data to D-Bus. 2728 */ 2729 BMCWEB_ROUTE(app, 2730 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2731 .privileges(redfish::privileges::postComputerSystem) 2732 .methods( 2733 boost::beast::http::verb:: 2734 post)([](const crow::Request& req, 2735 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2736 std::string resetType; 2737 if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", 2738 resetType)) 2739 { 2740 return; 2741 } 2742 2743 // Get the command and host vs. chassis 2744 std::string command; 2745 bool hostCommand = true; 2746 if ((resetType == "On") || (resetType == "ForceOn")) 2747 { 2748 command = "xyz.openbmc_project.State.Host.Transition.On"; 2749 hostCommand = true; 2750 } 2751 else if (resetType == "ForceOff") 2752 { 2753 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2754 hostCommand = false; 2755 } 2756 else if (resetType == "ForceRestart") 2757 { 2758 command = 2759 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2760 hostCommand = true; 2761 } 2762 else if (resetType == "GracefulShutdown") 2763 { 2764 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2765 hostCommand = true; 2766 } 2767 else if (resetType == "GracefulRestart") 2768 { 2769 command = 2770 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 2771 hostCommand = true; 2772 } 2773 else if (resetType == "PowerCycle") 2774 { 2775 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2776 hostCommand = true; 2777 } 2778 else if (resetType == "Nmi") 2779 { 2780 doNMI(asyncResp); 2781 return; 2782 } 2783 else 2784 { 2785 messages::actionParameterUnknown(asyncResp->res, "Reset", 2786 resetType); 2787 return; 2788 } 2789 2790 if (hostCommand) 2791 { 2792 crow::connections::systemBus->async_method_call( 2793 [asyncResp, resetType](const boost::system::error_code ec) { 2794 if (ec) 2795 { 2796 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2797 if (ec.value() == 2798 boost::asio::error::invalid_argument) 2799 { 2800 messages::actionParameterNotSupported( 2801 asyncResp->res, resetType, "Reset"); 2802 } 2803 else 2804 { 2805 messages::internalError(asyncResp->res); 2806 } 2807 return; 2808 } 2809 messages::success(asyncResp->res); 2810 }, 2811 "xyz.openbmc_project.State.Host", 2812 "/xyz/openbmc_project/state/host0", 2813 "org.freedesktop.DBus.Properties", "Set", 2814 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2815 dbus::utility::DbusVariantType{command}); 2816 } 2817 else 2818 { 2819 crow::connections::systemBus->async_method_call( 2820 [asyncResp, resetType](const boost::system::error_code ec) { 2821 if (ec) 2822 { 2823 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2824 if (ec.value() == 2825 boost::asio::error::invalid_argument) 2826 { 2827 messages::actionParameterNotSupported( 2828 asyncResp->res, resetType, "Reset"); 2829 } 2830 else 2831 { 2832 messages::internalError(asyncResp->res); 2833 } 2834 return; 2835 } 2836 messages::success(asyncResp->res); 2837 }, 2838 "xyz.openbmc_project.State.Chassis", 2839 "/xyz/openbmc_project/state/chassis0", 2840 "org.freedesktop.DBus.Properties", "Set", 2841 "xyz.openbmc_project.State.Chassis", 2842 "RequestedPowerTransition", 2843 dbus::utility::DbusVariantType{command}); 2844 } 2845 }); 2846 } 2847 2848 /** 2849 * Systems derived class for delivering Computer Systems Schema. 2850 */ 2851 inline void requestRoutesSystems(App& app) 2852 { 2853 2854 /** 2855 * Functions triggers appropriate requests on DBus 2856 */ 2857 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2858 .privileges(redfish::privileges::getComputerSystem) 2859 .methods( 2860 boost::beast::http::verb:: 2861 get)([](const crow::Request&, 2862 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2863 asyncResp->res.jsonValue["@odata.type"] = 2864 "#ComputerSystem.v1_16_0.ComputerSystem"; 2865 asyncResp->res.jsonValue["Name"] = "system"; 2866 asyncResp->res.jsonValue["Id"] = "system"; 2867 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2868 asyncResp->res.jsonValue["Description"] = "Computer System"; 2869 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2870 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2871 "Disabled"; 2872 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2873 uint64_t(0); 2874 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2875 "Disabled"; 2876 asyncResp->res.jsonValue["@odata.id"] = 2877 "/redfish/v1/Systems/system"; 2878 2879 asyncResp->res.jsonValue["Processors"] = { 2880 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2881 asyncResp->res.jsonValue["Memory"] = { 2882 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2883 asyncResp->res.jsonValue["Storage"] = { 2884 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2885 2886 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2887 {"target", 2888 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2889 {"@Redfish.ActionInfo", 2890 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2891 2892 asyncResp->res.jsonValue["LogServices"] = { 2893 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2894 2895 asyncResp->res.jsonValue["Bios"] = { 2896 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2897 2898 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2899 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2900 2901 asyncResp->res.jsonValue["Status"] = { 2902 {"Health", "OK"}, 2903 {"State", "Enabled"}, 2904 }; 2905 2906 // Fill in SerialConsole info 2907 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2908 15; 2909 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2910 {"ServiceEnabled", true}, 2911 }; 2912 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2913 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2914 {"ServiceEnabled", true}, 2915 {"Port", 2200}, 2916 // https://github.com/openbmc/docs/blob/master/console.md 2917 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2918 }; 2919 2920 #ifdef BMCWEB_ENABLE_KVM 2921 // Fill in GraphicalConsole info 2922 asyncResp->res.jsonValue["GraphicalConsole"] = { 2923 {"ServiceEnabled", true}, 2924 {"MaxConcurrentSessions", 4}, 2925 {"ConnectTypesSupported", {"KVMIP"}}, 2926 }; 2927 #endif // BMCWEB_ENABLE_KVM 2928 constexpr const std::array<const char*, 4> inventoryForSystems = { 2929 "xyz.openbmc_project.Inventory.Item.Dimm", 2930 "xyz.openbmc_project.Inventory.Item.Cpu", 2931 "xyz.openbmc_project.Inventory.Item.Drive", 2932 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2933 2934 auto health = std::make_shared<HealthPopulate>(asyncResp); 2935 crow::connections::systemBus->async_method_call( 2936 [health](const boost::system::error_code ec, 2937 const std::vector<std::string>& resp) { 2938 if (ec) 2939 { 2940 // no inventory 2941 return; 2942 } 2943 2944 health->inventory = resp; 2945 }, 2946 "xyz.openbmc_project.ObjectMapper", 2947 "/xyz/openbmc_project/object_mapper", 2948 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2949 int32_t(0), inventoryForSystems); 2950 2951 health->populate(); 2952 2953 getMainChassisId( 2954 asyncResp, [](const std::string& chassisId, 2955 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2956 aRsp->res.jsonValue["Links"]["Chassis"] = { 2957 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2958 }); 2959 2960 getLocationIndicatorActive(asyncResp); 2961 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2962 getIndicatorLedState(asyncResp); 2963 getComputerSystem(asyncResp, health); 2964 getHostState(asyncResp); 2965 getBootProperties(asyncResp); 2966 getBootProgress(asyncResp); 2967 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2968 getHostWatchdogTimer(asyncResp); 2969 getPowerRestorePolicy(asyncResp); 2970 getAutomaticRetry(asyncResp); 2971 getLastResetTime(asyncResp); 2972 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2973 getProvisioningStatus(asyncResp); 2974 #endif 2975 getTrustedModuleRequiredToBoot(asyncResp); 2976 getPowerMode(asyncResp); 2977 getIdlePowerSaver(asyncResp); 2978 }); 2979 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2980 .privileges(redfish::privileges::patchComputerSystem) 2981 .methods(boost::beast::http::verb::patch)( 2982 [](const crow::Request& req, 2983 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2984 std::optional<bool> locationIndicatorActive; 2985 std::optional<std::string> indicatorLed; 2986 std::optional<nlohmann::json> bootProps; 2987 std::optional<nlohmann::json> wdtTimerProps; 2988 std::optional<std::string> assetTag; 2989 std::optional<std::string> powerRestorePolicy; 2990 std::optional<std::string> powerMode; 2991 std::optional<nlohmann::json> ipsProps; 2992 if (!json_util::readJsonPatch( 2993 req, asyncResp->res, "IndicatorLED", indicatorLed, 2994 "LocationIndicatorActive", locationIndicatorActive, 2995 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2996 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2997 assetTag, "PowerMode", powerMode, "IdlePowerSaver", 2998 ipsProps)) 2999 { 3000 return; 3001 } 3002 3003 asyncResp->res.result(boost::beast::http::status::no_content); 3004 3005 if (assetTag) 3006 { 3007 setAssetTag(asyncResp, *assetTag); 3008 } 3009 3010 if (wdtTimerProps) 3011 { 3012 std::optional<bool> wdtEnable; 3013 std::optional<std::string> wdtTimeOutAction; 3014 3015 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 3016 "FunctionEnabled", wdtEnable, 3017 "TimeoutAction", wdtTimeOutAction)) 3018 { 3019 return; 3020 } 3021 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 3022 } 3023 3024 if (bootProps) 3025 { 3026 std::optional<std::string> bootSource; 3027 std::optional<std::string> bootType; 3028 std::optional<std::string> bootEnable; 3029 std::optional<std::string> automaticRetryConfig; 3030 std::optional<bool> trustedModuleRequiredToBoot; 3031 3032 if (!json_util::readJson( 3033 *bootProps, asyncResp->res, 3034 "BootSourceOverrideTarget", bootSource, 3035 "BootSourceOverrideMode", bootType, 3036 "BootSourceOverrideEnabled", bootEnable, 3037 "AutomaticRetryConfig", automaticRetryConfig, 3038 "TrustedModuleRequiredToBoot", 3039 trustedModuleRequiredToBoot)) 3040 { 3041 return; 3042 } 3043 3044 if (bootSource || bootType || bootEnable) 3045 { 3046 setBootProperties(asyncResp, bootSource, bootType, 3047 bootEnable); 3048 } 3049 if (automaticRetryConfig) 3050 { 3051 setAutomaticRetry(asyncResp, *automaticRetryConfig); 3052 } 3053 3054 if (trustedModuleRequiredToBoot) 3055 { 3056 setTrustedModuleRequiredToBoot( 3057 asyncResp, *trustedModuleRequiredToBoot); 3058 } 3059 } 3060 3061 if (locationIndicatorActive) 3062 { 3063 setLocationIndicatorActive(asyncResp, 3064 *locationIndicatorActive); 3065 } 3066 3067 // TODO (Gunnar): Remove IndicatorLED after enough time has 3068 // passed 3069 if (indicatorLed) 3070 { 3071 setIndicatorLedState(asyncResp, *indicatorLed); 3072 asyncResp->res.addHeader( 3073 boost::beast::http::field::warning, 3074 "299 - \"IndicatorLED is deprecated. Use " 3075 "LocationIndicatorActive instead.\""); 3076 } 3077 3078 if (powerRestorePolicy) 3079 { 3080 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 3081 } 3082 3083 if (powerMode) 3084 { 3085 setPowerMode(asyncResp, *powerMode); 3086 } 3087 3088 if (ipsProps) 3089 { 3090 std::optional<bool> ipsEnable; 3091 std::optional<uint8_t> ipsEnterUtil; 3092 std::optional<uint64_t> ipsEnterTime; 3093 std::optional<uint8_t> ipsExitUtil; 3094 std::optional<uint64_t> ipsExitTime; 3095 3096 if (!json_util::readJson( 3097 *ipsProps, asyncResp->res, "Enabled", ipsEnable, 3098 "EnterUtilizationPercent", ipsEnterUtil, 3099 "EnterDwellTimeSeconds", ipsEnterTime, 3100 "ExitUtilizationPercent", ipsExitUtil, 3101 "ExitDwellTimeSeconds", ipsExitTime)) 3102 { 3103 return; 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 /** 3119 * Functions triggers appropriate requests on DBus 3120 */ 3121 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 3122 .privileges(redfish::privileges::getActionInfo) 3123 .methods(boost::beast::http::verb::get)( 3124 [](const crow::Request&, 3125 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3126 asyncResp->res.jsonValue = { 3127 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 3128 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 3129 {"Name", "Reset Action Info"}, 3130 {"Id", "ResetActionInfo"}, 3131 {"Parameters", 3132 {{{"Name", "ResetType"}, 3133 {"Required", true}, 3134 {"DataType", "String"}, 3135 {"AllowableValues", 3136 {"On", "ForceOff", "ForceOn", "ForceRestart", 3137 "GracefulRestart", "GracefulShutdown", "PowerCycle", 3138 "Nmi"}}}}}}; 3139 }); 3140 } 3141 } // namespace redfish 3142