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