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 #include "utils/time_utils.hpp" 25 26 #include <app.hpp> 27 #include <boost/container/flat_map.hpp> 28 #include <dbus_utility.hpp> 29 #include <registries/privilege_registry.hpp> 30 #include <sdbusplus/asio/property.hpp> 31 #include <utils/json_utils.hpp> 32 #include <utils/sw_utils.hpp> 33 34 #include <variant> 35 36 namespace redfish 37 { 38 39 /** 40 * @brief Updates the Functional State of DIMMs 41 * 42 * @param[in] aResp Shared pointer for completing asynchronous calls 43 * @param[in] dimmState Dimm's Functional state, true/false 44 * 45 * @return None. 46 */ 47 inline void 48 updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 49 bool isDimmFunctional) 50 { 51 BMCWEB_LOG_DEBUG << "Dimm Functional: " << isDimmFunctional; 52 53 // Set it as Enabled if at least one DIMM is functional 54 // Update STATE only if previous State was DISABLED and current Dimm is 55 // ENABLED. 56 const nlohmann::json& prevMemSummary = 57 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 58 if (prevMemSummary == "Disabled") 59 { 60 if (isDimmFunctional) 61 { 62 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 63 "Enabled"; 64 } 65 } 66 } 67 68 /* 69 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 70 * 71 * @param[in] aResp Shared pointer for completing asynchronous calls 72 * @param[in] cpuPresenceState CPU present or not 73 * 74 * @return None. 75 */ 76 inline void 77 modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 78 bool isCpuPresent) 79 { 80 BMCWEB_LOG_DEBUG << "Cpu Present: " << isCpuPresent; 81 82 if (isCpuPresent) 83 { 84 nlohmann::json& procCount = 85 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 86 auto* procCountPtr = 87 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 88 if (procCountPtr != nullptr) 89 { 90 // shouldn't be possible to be nullptr 91 *procCountPtr += 1; 92 } 93 } 94 } 95 96 /* 97 * @brief Update "ProcessorSummary" "Status" "State" based on 98 * CPU Functional State 99 * 100 * @param[in] aResp Shared pointer for completing asynchronous calls 101 * @param[in] cpuFunctionalState is CPU functional true/false 102 * 103 * @return None. 104 */ 105 inline void 106 modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 107 bool isCpuFunctional) 108 { 109 BMCWEB_LOG_DEBUG << "Cpu Functional: " << isCpuFunctional; 110 111 const nlohmann::json& prevProcState = 112 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 113 114 // Set it as Enabled if at least one CPU is functional 115 // Update STATE only if previous State was Non_Functional and current CPU is 116 // Functional. 117 if (prevProcState == "Disabled") 118 { 119 if (isCpuFunctional) 120 { 121 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 122 "Enabled"; 123 } 124 } 125 } 126 127 inline void 128 getProcessorProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 129 const std::string& service, const std::string& path, 130 const dbus::utility::DBusPropertiesMap& properties) 131 { 132 133 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties."; 134 135 auto getCpuPresenceState = [aResp](const boost::system::error_code ec3, 136 const bool cpuPresenceCheck) { 137 if (ec3) 138 { 139 BMCWEB_LOG_ERROR << "DBUS response error " << ec3; 140 return; 141 } 142 modifyCpuPresenceState(aResp, cpuPresenceCheck); 143 }; 144 145 auto getCpuFunctionalState = [aResp](const boost::system::error_code ec3, 146 const bool cpuFunctionalCheck) { 147 if (ec3) 148 { 149 BMCWEB_LOG_ERROR << "DBUS response error " << ec3; 150 return; 151 } 152 modifyCpuFunctionalState(aResp, cpuFunctionalCheck); 153 }; 154 155 // Get the Presence of CPU 156 sdbusplus::asio::getProperty<bool>( 157 *crow::connections::systemBus, service, path, 158 "xyz.openbmc_project.Inventory.Item", "Present", 159 std::move(getCpuPresenceState)); 160 161 // Get the Functional State 162 sdbusplus::asio::getProperty<bool>( 163 *crow::connections::systemBus, service, path, 164 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 165 std::move(getCpuFunctionalState)); 166 167 for (const auto& property : properties) 168 { 169 170 // TODO: Get Model 171 172 // Get CoreCount 173 if (property.first == "CoreCount") 174 { 175 176 // Get CPU CoreCount and add it to the total 177 const uint16_t* coreCountVal = 178 std::get_if<uint16_t>(&property.second); 179 180 if (coreCountVal == nullptr) 181 { 182 messages::internalError(aResp->res); 183 return; 184 } 185 186 nlohmann::json& coreCount = 187 aResp->res.jsonValue["ProcessorSummary"]["CoreCount"]; 188 uint64_t* coreCountPtr = coreCount.get_ptr<uint64_t*>(); 189 190 if (coreCountPtr == nullptr) 191 { 192 coreCount = *coreCountVal; 193 } 194 else 195 { 196 *coreCountPtr += *coreCountVal; 197 } 198 } 199 } 200 } 201 202 /* 203 * @brief Get ProcessorSummary fields 204 * 205 * @param[in] aResp Shared pointer for completing asynchronous calls 206 * @param[in] service dbus service for Cpu Information 207 * @param[in] path dbus path for Cpu 208 * 209 * @return None. 210 */ 211 inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 212 const std::string& service, 213 const std::string& path) 214 { 215 216 crow::connections::systemBus->async_method_call( 217 [aResp, service, 218 path](const boost::system::error_code ec2, 219 const dbus::utility::DBusPropertiesMap& properties) { 220 if (ec2) 221 { 222 BMCWEB_LOG_ERROR << "DBUS response error " << ec2; 223 messages::internalError(aResp->res); 224 return; 225 } 226 getProcessorProperties(aResp, service, path, properties); 227 }, 228 service, path, "org.freedesktop.DBus.Properties", "GetAll", 229 "xyz.openbmc_project.Inventory.Item.Cpu"); 230 } 231 232 /* 233 * @brief Retrieves computer system properties over dbus 234 * 235 * @param[in] aResp Shared pointer for completing asynchronous calls 236 * @param[in] systemHealth Shared HealthPopulate pointer 237 * 238 * @return None. 239 */ 240 inline void 241 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 242 const std::shared_ptr<HealthPopulate>& systemHealth) 243 { 244 BMCWEB_LOG_DEBUG << "Get available system components."; 245 246 crow::connections::systemBus->async_method_call( 247 [aResp, 248 systemHealth](const boost::system::error_code ec, 249 const dbus::utility::MapperGetSubTreeResponse& subtree) { 250 if (ec) 251 { 252 BMCWEB_LOG_DEBUG << "DBUS response error"; 253 messages::internalError(aResp->res); 254 return; 255 } 256 // Iterate over all retrieved ObjectPaths. 257 for (const std::pair< 258 std::string, 259 std::vector<std::pair<std::string, std::vector<std::string>>>>& 260 object : subtree) 261 { 262 const std::string& path = object.first; 263 BMCWEB_LOG_DEBUG << "Got path: " << path; 264 const std::vector<std::pair<std::string, std::vector<std::string>>>& 265 connectionNames = object.second; 266 if (connectionNames.empty()) 267 { 268 continue; 269 } 270 271 auto memoryHealth = std::make_shared<HealthPopulate>( 272 aResp, "/MemorySummary/Status"_json_pointer); 273 274 auto cpuHealth = std::make_shared<HealthPopulate>( 275 aResp, "/ProcessorSummary/Status"_json_pointer); 276 277 systemHealth->children.emplace_back(memoryHealth); 278 systemHealth->children.emplace_back(cpuHealth); 279 280 // This is not system, so check if it's cpu, dimm, UUID or 281 // BiosVer 282 for (const auto& connection : connectionNames) 283 { 284 for (const auto& interfaceName : connection.second) 285 { 286 if (interfaceName == 287 "xyz.openbmc_project.Inventory.Item.Dimm") 288 { 289 BMCWEB_LOG_DEBUG 290 << "Found Dimm, now get its properties."; 291 292 crow::connections::systemBus->async_method_call( 293 [aResp, service{connection.first}, 294 path](const boost::system::error_code ec2, 295 const dbus::utility::DBusPropertiesMap& 296 properties) { 297 if (ec2) 298 { 299 BMCWEB_LOG_ERROR << "DBUS response error " 300 << ec2; 301 messages::internalError(aResp->res); 302 return; 303 } 304 BMCWEB_LOG_DEBUG << "Got " << properties.size() 305 << " Dimm properties."; 306 307 if (!properties.empty()) 308 { 309 for (const std::pair< 310 std::string, 311 dbus::utility::DbusVariantType>& 312 property : properties) 313 { 314 if (property.first != "MemorySizeInKB") 315 { 316 continue; 317 } 318 const uint32_t* value = 319 std::get_if<uint32_t>(&property.second); 320 if (value == nullptr) 321 { 322 BMCWEB_LOG_DEBUG 323 << "Find incorrect type of MemorySize"; 324 continue; 325 } 326 nlohmann::json& totalMemory = 327 aResp->res 328 .jsonValue["MemorySummary"] 329 ["TotalSystemMemoryGiB"]; 330 const uint64_t* preValue = 331 totalMemory.get_ptr<const uint64_t*>(); 332 if (preValue == nullptr) 333 { 334 continue; 335 } 336 aResp->res 337 .jsonValue["MemorySummary"] 338 ["TotalSystemMemoryGiB"] = 339 *value / (1024 * 1024) + *preValue; 340 aResp->res.jsonValue["MemorySummary"] 341 ["Status"]["State"] = 342 "Enabled"; 343 } 344 } 345 else 346 { 347 sdbusplus::asio::getProperty<bool>( 348 *crow::connections::systemBus, service, 349 path, 350 "xyz.openbmc_project.State." 351 "Decorator.OperationalStatus", 352 "Functional", 353 [aResp](const boost::system::error_code ec3, 354 bool dimmState) { 355 if (ec3) 356 { 357 BMCWEB_LOG_ERROR 358 << "DBUS response error " << ec3; 359 return; 360 } 361 updateDimmProperties(aResp, dimmState); 362 }); 363 } 364 }, 365 connection.first, path, 366 "org.freedesktop.DBus.Properties", "GetAll", 367 "xyz.openbmc_project.Inventory.Item.Dimm"); 368 369 memoryHealth->inventory.emplace_back(path); 370 } 371 else if (interfaceName == 372 "xyz.openbmc_project.Inventory.Item.Cpu") 373 { 374 BMCWEB_LOG_DEBUG 375 << "Found Cpu, now get its properties."; 376 377 getProcessorSummary(aResp, connection.first, path); 378 379 cpuHealth->inventory.emplace_back(path); 380 } 381 else if (interfaceName == "xyz.openbmc_project.Common.UUID") 382 { 383 BMCWEB_LOG_DEBUG 384 << "Found UUID, now get its properties."; 385 crow::connections::systemBus->async_method_call( 386 [aResp](const boost::system::error_code ec3, 387 const dbus::utility::DBusPropertiesMap& 388 properties) { 389 if (ec3) 390 { 391 BMCWEB_LOG_DEBUG << "DBUS response error " 392 << ec3; 393 messages::internalError(aResp->res); 394 return; 395 } 396 BMCWEB_LOG_DEBUG << "Got " << properties.size() 397 << " UUID properties."; 398 for (const std::pair< 399 std::string, 400 dbus::utility::DbusVariantType>& property : 401 properties) 402 { 403 if (property.first == "UUID") 404 { 405 const std::string* value = 406 std::get_if<std::string>( 407 &property.second); 408 409 if (value != nullptr) 410 { 411 std::string valueStr = *value; 412 if (valueStr.size() == 32) 413 { 414 valueStr.insert(8, 1, '-'); 415 valueStr.insert(13, 1, '-'); 416 valueStr.insert(18, 1, '-'); 417 valueStr.insert(23, 1, '-'); 418 } 419 BMCWEB_LOG_DEBUG << "UUID = " 420 << valueStr; 421 aResp->res.jsonValue["UUID"] = valueStr; 422 } 423 } 424 } 425 }, 426 connection.first, path, 427 "org.freedesktop.DBus.Properties", "GetAll", 428 "xyz.openbmc_project.Common.UUID"); 429 } 430 else if (interfaceName == 431 "xyz.openbmc_project.Inventory.Item.System") 432 { 433 crow::connections::systemBus->async_method_call( 434 [aResp](const boost::system::error_code ec2, 435 const dbus::utility::DBusPropertiesMap& 436 propertiesList) { 437 if (ec2) 438 { 439 // doesn't have to include this 440 // interface 441 return; 442 } 443 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 444 << " properties for system"; 445 for (const std::pair< 446 std::string, 447 dbus::utility::DbusVariantType>& property : 448 propertiesList) 449 { 450 const std::string& propertyName = 451 property.first; 452 if ((propertyName == "PartNumber") || 453 (propertyName == "SerialNumber") || 454 (propertyName == "Manufacturer") || 455 (propertyName == "Model") || 456 (propertyName == "SubModel")) 457 { 458 const std::string* value = 459 std::get_if<std::string>( 460 &property.second); 461 if (value != nullptr) 462 { 463 aResp->res.jsonValue[propertyName] = 464 *value; 465 } 466 } 467 } 468 469 // Grab the bios version 470 sw_util::populateSoftwareInformation( 471 aResp, sw_util::biosPurpose, "BiosVersion", 472 false); 473 }, 474 connection.first, path, 475 "org.freedesktop.DBus.Properties", "GetAll", 476 "xyz.openbmc_project.Inventory.Decorator.Asset"); 477 478 sdbusplus::asio::getProperty<std::string>( 479 *crow::connections::systemBus, connection.first, 480 path, 481 "xyz.openbmc_project.Inventory.Decorator." 482 "AssetTag", 483 "AssetTag", 484 [aResp](const boost::system::error_code ec2, 485 const std::string& value) { 486 if (ec2) 487 { 488 // doesn't have to include this 489 // interface 490 return; 491 } 492 493 aResp->res.jsonValue["AssetTag"] = value; 494 }); 495 } 496 } 497 } 498 } 499 }, 500 "xyz.openbmc_project.ObjectMapper", 501 "/xyz/openbmc_project/object_mapper", 502 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 503 "/xyz/openbmc_project/inventory", int32_t(0), 504 std::array<const char*, 5>{ 505 "xyz.openbmc_project.Inventory.Decorator.Asset", 506 "xyz.openbmc_project.Inventory.Item.Cpu", 507 "xyz.openbmc_project.Inventory.Item.Dimm", 508 "xyz.openbmc_project.Inventory.Item.System", 509 "xyz.openbmc_project.Common.UUID", 510 }); 511 } 512 513 /** 514 * @brief Retrieves host state properties over dbus 515 * 516 * @param[in] aResp Shared pointer for completing asynchronous calls. 517 * 518 * @return None. 519 */ 520 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 521 { 522 BMCWEB_LOG_DEBUG << "Get host information."; 523 sdbusplus::asio::getProperty<std::string>( 524 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 525 "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host", 526 "CurrentHostState", 527 [aResp](const boost::system::error_code ec, 528 const std::string& hostState) { 529 if (ec) 530 { 531 if (ec == boost::system::errc::host_unreachable) 532 { 533 // Service not available, no error, just don't return 534 // host state info 535 BMCWEB_LOG_DEBUG << "Service not available " << ec; 536 return; 537 } 538 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 539 messages::internalError(aResp->res); 540 return; 541 } 542 543 BMCWEB_LOG_DEBUG << "Host state: " << hostState; 544 // Verify Host State 545 if (hostState == "xyz.openbmc_project.State.Host.HostState.Running") 546 { 547 aResp->res.jsonValue["PowerState"] = "On"; 548 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 549 } 550 else if (hostState == 551 "xyz.openbmc_project.State.Host.HostState.Quiesced") 552 { 553 aResp->res.jsonValue["PowerState"] = "On"; 554 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 555 } 556 else if (hostState == 557 "xyz.openbmc_project.State.Host.HostState.DiagnosticMode") 558 { 559 aResp->res.jsonValue["PowerState"] = "On"; 560 aResp->res.jsonValue["Status"]["State"] = "InTest"; 561 } 562 else if ( 563 hostState == 564 "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning") 565 { 566 aResp->res.jsonValue["PowerState"] = "PoweringOn"; 567 aResp->res.jsonValue["Status"]["State"] = "Starting"; 568 } 569 else if (hostState == 570 "xyz.openbmc_project.State.Host.HostState.TransitioningToOff") 571 { 572 aResp->res.jsonValue["PowerState"] = "PoweringOff"; 573 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 574 } 575 else 576 { 577 aResp->res.jsonValue["PowerState"] = "Off"; 578 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 579 } 580 }); 581 } 582 583 /** 584 * @brief Translates boot source DBUS property value to redfish. 585 * 586 * @param[in] dbusSource The boot source in DBUS speak. 587 * 588 * @return Returns as a string, the boot source in Redfish terms. If translation 589 * cannot be done, returns an empty string. 590 */ 591 inline std::string dbusToRfBootSource(const std::string& dbusSource) 592 { 593 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 594 { 595 return "None"; 596 } 597 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 598 { 599 return "Hdd"; 600 } 601 if (dbusSource == 602 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 603 { 604 return "Cd"; 605 } 606 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 607 { 608 return "Pxe"; 609 } 610 if (dbusSource == 611 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 612 { 613 return "Usb"; 614 } 615 return ""; 616 } 617 618 /** 619 * @brief Translates boot type DBUS property value to redfish. 620 * 621 * @param[in] dbusType The boot type in DBUS speak. 622 * 623 * @return Returns as a string, the boot type in Redfish terms. If translation 624 * cannot be done, returns an empty string. 625 */ 626 inline std::string dbusToRfBootType(const std::string& dbusType) 627 { 628 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy") 629 { 630 return "Legacy"; 631 } 632 if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI") 633 { 634 return "UEFI"; 635 } 636 return ""; 637 } 638 639 /** 640 * @brief Translates boot mode DBUS property value to redfish. 641 * 642 * @param[in] dbusMode The boot mode in DBUS speak. 643 * 644 * @return Returns as a string, the boot mode in Redfish terms. If translation 645 * cannot be done, returns an empty string. 646 */ 647 inline std::string dbusToRfBootMode(const std::string& dbusMode) 648 { 649 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 650 { 651 return "None"; 652 } 653 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 654 { 655 return "Diags"; 656 } 657 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 658 { 659 return "BiosSetup"; 660 } 661 return ""; 662 } 663 664 /** 665 * @brief Translates boot progress DBUS property value to redfish. 666 * 667 * @param[in] dbusBootProgress The boot progress in DBUS speak. 668 * 669 * @return Returns as a string, the boot progress in Redfish terms. If 670 * translation cannot be done, returns "None". 671 */ 672 inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress) 673 { 674 // Now convert the D-Bus BootProgress to the appropriate Redfish 675 // enum 676 std::string rfBpLastState = "None"; 677 if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress." 678 "ProgressStages.Unspecified") 679 { 680 rfBpLastState = "None"; 681 } 682 else if (dbusBootProgress == 683 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 684 "PrimaryProcInit") 685 { 686 rfBpLastState = "PrimaryProcessorInitializationStarted"; 687 } 688 else if (dbusBootProgress == 689 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 690 "BusInit") 691 { 692 rfBpLastState = "BusInitializationStarted"; 693 } 694 else if (dbusBootProgress == 695 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 696 "MemoryInit") 697 { 698 rfBpLastState = "MemoryInitializationStarted"; 699 } 700 else if (dbusBootProgress == 701 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 702 "SecondaryProcInit") 703 { 704 rfBpLastState = "SecondaryProcessorInitializationStarted"; 705 } 706 else if (dbusBootProgress == 707 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 708 "PCIInit") 709 { 710 rfBpLastState = "PCIResourceConfigStarted"; 711 } 712 else if (dbusBootProgress == 713 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 714 "SystemSetup") 715 { 716 rfBpLastState = "SetupEntered"; 717 } 718 else if (dbusBootProgress == 719 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 720 "SystemInitComplete") 721 { 722 rfBpLastState = "SystemHardwareInitializationComplete"; 723 } 724 else if (dbusBootProgress == 725 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 726 "OSStart") 727 { 728 rfBpLastState = "OSBootStarted"; 729 } 730 else if (dbusBootProgress == 731 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 732 "OSRunning") 733 { 734 rfBpLastState = "OSRunning"; 735 } 736 else 737 { 738 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 739 << dbusBootProgress; 740 // Just return the default 741 } 742 return rfBpLastState; 743 } 744 745 /** 746 * @brief Translates boot source from Redfish to the DBus boot paths. 747 * 748 * @param[in] rfSource The boot source in Redfish. 749 * @param[out] bootSource The DBus source 750 * @param[out] bootMode the DBus boot mode 751 * 752 * @return Integer error code. 753 */ 754 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 755 const std::string& rfSource, 756 std::string& bootSource, std::string& bootMode) 757 { 758 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 759 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 760 761 if (rfSource == "None") 762 { 763 return 0; 764 } 765 if (rfSource == "Pxe") 766 { 767 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 768 } 769 else if (rfSource == "Hdd") 770 { 771 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 772 } 773 else if (rfSource == "Diags") 774 { 775 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 776 } 777 else if (rfSource == "Cd") 778 { 779 bootSource = 780 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 781 } 782 else if (rfSource == "BiosSetup") 783 { 784 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 785 } 786 else if (rfSource == "Usb") 787 { 788 bootSource = 789 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 790 } 791 else 792 { 793 BMCWEB_LOG_DEBUG 794 << "Invalid property value for BootSourceOverrideTarget: " 795 << bootSource; 796 messages::propertyValueNotInList(aResp->res, rfSource, 797 "BootSourceTargetOverride"); 798 return -1; 799 } 800 return 0; 801 } 802 803 /** 804 * @brief Retrieves boot progress of the system 805 * 806 * @param[in] aResp Shared pointer for generating response message. 807 * 808 * @return None. 809 */ 810 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 811 { 812 sdbusplus::asio::getProperty<std::string>( 813 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 814 "/xyz/openbmc_project/state/host0", 815 "xyz.openbmc_project.State.Boot.Progress", "BootProgress", 816 [aResp](const boost::system::error_code ec, 817 const std::string& bootProgressStr) { 818 if (ec) 819 { 820 // BootProgress is an optional object so just do nothing if 821 // not found 822 return; 823 } 824 825 BMCWEB_LOG_DEBUG << "Boot Progress: " << bootProgressStr; 826 827 aResp->res.jsonValue["BootProgress"]["LastState"] = 828 dbusToRfBootProgress(bootProgressStr); 829 }); 830 } 831 832 /** 833 * @brief Retrieves boot override type over DBUS and fills out the response 834 * 835 * @param[in] aResp Shared pointer for generating response message. 836 * 837 * @return None. 838 */ 839 840 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 841 { 842 sdbusplus::asio::getProperty<std::string>( 843 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 844 "/xyz/openbmc_project/control/host0/boot", 845 "xyz.openbmc_project.Control.Boot.Type", "BootType", 846 [aResp](const boost::system::error_code ec, 847 const std::string& bootType) { 848 if (ec) 849 { 850 // not an error, don't have to have the interface 851 return; 852 } 853 854 BMCWEB_LOG_DEBUG << "Boot type: " << bootType; 855 856 aResp->res.jsonValue["Boot"] 857 ["BootSourceOverrideMode@Redfish.AllowableValues"] = 858 {"Legacy", "UEFI"}; 859 860 auto rfType = dbusToRfBootType(bootType); 861 if (rfType.empty()) 862 { 863 messages::internalError(aResp->res); 864 return; 865 } 866 867 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType; 868 }); 869 } 870 871 /** 872 * @brief Retrieves boot override mode over DBUS and fills out the response 873 * 874 * @param[in] aResp Shared pointer for generating response message. 875 * 876 * @return None. 877 */ 878 879 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 880 { 881 sdbusplus::asio::getProperty<std::string>( 882 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 883 "/xyz/openbmc_project/control/host0/boot", 884 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 885 [aResp](const boost::system::error_code ec, 886 const std::string& bootModeStr) { 887 if (ec) 888 { 889 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 890 messages::internalError(aResp->res); 891 return; 892 } 893 894 BMCWEB_LOG_DEBUG << "Boot mode: " << bootModeStr; 895 896 aResp->res 897 .jsonValue["Boot"] 898 ["BootSourceOverrideTarget@Redfish.AllowableValues"] = { 899 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 900 901 if (bootModeStr != 902 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 903 { 904 auto rfMode = dbusToRfBootMode(bootModeStr); 905 if (!rfMode.empty()) 906 { 907 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 908 rfMode; 909 } 910 } 911 }); 912 } 913 914 /** 915 * @brief Retrieves boot override source over DBUS 916 * 917 * @param[in] aResp Shared pointer for generating response message. 918 * 919 * @return None. 920 */ 921 922 inline void 923 getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 924 { 925 sdbusplus::asio::getProperty<std::string>( 926 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 927 "/xyz/openbmc_project/control/host0/boot", 928 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 929 [aResp](const boost::system::error_code ec, 930 const std::string& bootSourceStr) { 931 if (ec) 932 { 933 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 934 if (ec.value() == boost::asio::error::host_unreachable) 935 { 936 return; 937 } 938 messages::internalError(aResp->res); 939 return; 940 } 941 942 BMCWEB_LOG_DEBUG << "Boot source: " << bootSourceStr; 943 944 auto rfSource = dbusToRfBootSource(bootSourceStr); 945 if (!rfSource.empty()) 946 { 947 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = rfSource; 948 } 949 950 // Get BootMode as BootSourceOverrideTarget is constructed 951 // from both BootSource and BootMode 952 getBootOverrideMode(aResp); 953 }); 954 } 955 956 /** 957 * @brief This functions abstracts all the logic behind getting a 958 * "BootSourceOverrideEnabled" property from an overall boot override enable 959 * state 960 * 961 * @param[in] aResp Shared pointer for generating response message. 962 * 963 * @return None. 964 */ 965 966 inline void 967 processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 968 const bool bootOverrideEnableSetting) 969 { 970 if (!bootOverrideEnableSetting) 971 { 972 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled"; 973 return; 974 } 975 976 // If boot source override is enabled, we need to check 'one_time' 977 // property to set a correct value for the "BootSourceOverrideEnabled" 978 sdbusplus::asio::getProperty<bool>( 979 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 980 "/xyz/openbmc_project/control/host0/boot/one_time", 981 "xyz.openbmc_project.Object.Enable", "Enabled", 982 [aResp](const boost::system::error_code ec, bool oneTimeSetting) { 983 if (ec) 984 { 985 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 986 messages::internalError(aResp->res); 987 return; 988 } 989 990 if (oneTimeSetting) 991 { 992 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Once"; 993 } 994 else 995 { 996 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 997 "Continuous"; 998 } 999 }); 1000 } 1001 1002 /** 1003 * @brief Retrieves boot override enable over DBUS 1004 * 1005 * @param[in] aResp Shared pointer for generating response message. 1006 * 1007 * @return None. 1008 */ 1009 1010 inline void 1011 getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1012 { 1013 sdbusplus::asio::getProperty<bool>( 1014 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1015 "/xyz/openbmc_project/control/host0/boot", 1016 "xyz.openbmc_project.Object.Enable", "Enabled", 1017 [aResp](const boost::system::error_code ec, 1018 const bool bootOverrideEnable) { 1019 if (ec) 1020 { 1021 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1022 if (ec.value() == boost::asio::error::host_unreachable) 1023 { 1024 return; 1025 } 1026 messages::internalError(aResp->res); 1027 return; 1028 } 1029 1030 processBootOverrideEnable(aResp, bootOverrideEnable); 1031 }); 1032 } 1033 1034 /** 1035 * @brief Retrieves boot source override properties 1036 * 1037 * @param[in] aResp Shared pointer for generating response message. 1038 * 1039 * @return None. 1040 */ 1041 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1042 { 1043 BMCWEB_LOG_DEBUG << "Get boot information."; 1044 1045 getBootOverrideSource(aResp); 1046 getBootOverrideType(aResp); 1047 getBootOverrideEnable(aResp); 1048 } 1049 1050 /** 1051 * @brief Retrieves the Last Reset Time 1052 * 1053 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1054 * and power off. Even though this is the "system" Redfish object look at the 1055 * chassis D-Bus interface for the LastStateChangeTime since this has the 1056 * last power operation time. 1057 * 1058 * @param[in] aResp Shared pointer for generating response message. 1059 * 1060 * @return None. 1061 */ 1062 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1063 { 1064 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1065 1066 sdbusplus::asio::getProperty<uint64_t>( 1067 *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis", 1068 "/xyz/openbmc_project/state/chassis0", 1069 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime", 1070 [aResp](const boost::system::error_code ec, uint64_t lastResetTime) { 1071 if (ec) 1072 { 1073 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1074 return; 1075 } 1076 1077 // LastStateChangeTime is epoch time, in milliseconds 1078 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1079 uint64_t lastResetTimeStamp = lastResetTime / 1000; 1080 1081 // Convert to ISO 8601 standard 1082 aResp->res.jsonValue["LastResetTime"] = 1083 redfish::time_utils::getDateTimeUint(lastResetTimeStamp); 1084 }); 1085 } 1086 1087 /** 1088 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1089 * 1090 * @param[in] aResp Shared pointer for generating response message. 1091 * 1092 * @return None. 1093 */ 1094 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1095 { 1096 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1097 1098 sdbusplus::asio::getProperty<bool>( 1099 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1100 "/xyz/openbmc_project/control/host0/auto_reboot", 1101 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1102 [aResp](const boost::system::error_code ec, bool autoRebootEnabled) { 1103 if (ec) 1104 { 1105 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1106 return; 1107 } 1108 1109 BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled; 1110 if (autoRebootEnabled) 1111 { 1112 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1113 "RetryAttempts"; 1114 // If AutomaticRetry (AutoReboot) is enabled see how many 1115 // attempts are left 1116 sdbusplus::asio::getProperty<uint32_t>( 1117 *crow::connections::systemBus, "xyz.openbmc_project.State.Host", 1118 "/xyz/openbmc_project/state/host0", 1119 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1120 "AttemptsLeft", 1121 [aResp](const boost::system::error_code ec2, 1122 const uint32_t autoRebootAttemptsLeft) { 1123 if (ec2) 1124 { 1125 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1126 return; 1127 } 1128 1129 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1130 << autoRebootAttemptsLeft; 1131 1132 aResp->res 1133 .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] = 1134 autoRebootAttemptsLeft; 1135 }); 1136 } 1137 else 1138 { 1139 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled"; 1140 } 1141 1142 // Not on D-Bus. Hardcoded here: 1143 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1144 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1145 1146 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1147 // and RetryAttempts. OpenBMC only supports Disabled and 1148 // RetryAttempts. 1149 aResp->res.jsonValue["Boot"] 1150 ["AutomaticRetryConfig@Redfish.AllowableValues"] = { 1151 "Disabled", "RetryAttempts"}; 1152 }); 1153 } 1154 1155 /** 1156 * @brief Retrieves power restore policy over DBUS. 1157 * 1158 * @param[in] aResp Shared pointer for generating response message. 1159 * 1160 * @return None. 1161 */ 1162 inline void 1163 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1164 { 1165 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1166 1167 sdbusplus::asio::getProperty<std::string>( 1168 *crow::connections::systemBus, "xyz.openbmc_project.Settings", 1169 "/xyz/openbmc_project/control/host0/power_restore_policy", 1170 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1171 [aResp](const boost::system::error_code ec, const std::string& policy) { 1172 if (ec) 1173 { 1174 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1175 return; 1176 } 1177 1178 const boost::container::flat_map<std::string, std::string> policyMaps = { 1179 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn", 1180 "AlwaysOn"}, 1181 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff", 1182 "AlwaysOff"}, 1183 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore", 1184 "LastState"}, 1185 // Return `AlwaysOff` when power restore policy set to "None" 1186 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None", 1187 "AlwaysOff"}}; 1188 1189 auto policyMapsIt = policyMaps.find(policy); 1190 if (policyMapsIt == policyMaps.end()) 1191 { 1192 messages::internalError(aResp->res); 1193 return; 1194 } 1195 1196 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1197 }); 1198 } 1199 1200 /** 1201 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1202 * TPM is required for booting the host. 1203 * 1204 * @param[in] aResp Shared pointer for generating response message. 1205 * 1206 * @return None. 1207 */ 1208 inline void getTrustedModuleRequiredToBoot( 1209 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1210 { 1211 BMCWEB_LOG_DEBUG << "Get TPM required to boot."; 1212 1213 crow::connections::systemBus->async_method_call( 1214 [aResp](const boost::system::error_code ec, 1215 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1216 if (ec) 1217 { 1218 BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree" 1219 << ec; 1220 // This is an optional D-Bus object so just return if 1221 // error occurs 1222 return; 1223 } 1224 if (subtree.empty()) 1225 { 1226 // As noted above, this is an optional interface so just return 1227 // if there is no instance found 1228 return; 1229 } 1230 1231 /* When there is more than one TPMEnable object... */ 1232 if (subtree.size() > 1) 1233 { 1234 BMCWEB_LOG_DEBUG 1235 << "DBUS response has more than 1 TPM Enable object:" 1236 << subtree.size(); 1237 // Throw an internal Error and return 1238 messages::internalError(aResp->res); 1239 return; 1240 } 1241 1242 // Make sure the Dbus response map has a service and objectPath 1243 // field 1244 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1245 { 1246 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1247 messages::internalError(aResp->res); 1248 return; 1249 } 1250 1251 const std::string& path = subtree[0].first; 1252 const std::string& serv = subtree[0].second.begin()->first; 1253 1254 // Valid TPM Enable object found, now reading the current value 1255 sdbusplus::asio::getProperty<bool>( 1256 *crow::connections::systemBus, serv, path, 1257 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1258 [aResp](const boost::system::error_code ec2, bool tpmRequired) { 1259 if (ec2) 1260 { 1261 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get" 1262 << ec2; 1263 messages::internalError(aResp->res); 1264 return; 1265 } 1266 1267 if (tpmRequired) 1268 { 1269 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1270 "Required"; 1271 } 1272 else 1273 { 1274 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1275 "Disabled"; 1276 } 1277 }); 1278 }, 1279 "xyz.openbmc_project.ObjectMapper", 1280 "/xyz/openbmc_project/object_mapper", 1281 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1282 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1283 } 1284 1285 /** 1286 * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not 1287 * TPM is required for booting the host. 1288 * 1289 * @param[in] aResp Shared pointer for generating response message. 1290 * @param[in] tpmRequired Value to set TPM Required To Boot property to. 1291 * 1292 * @return None. 1293 */ 1294 inline void setTrustedModuleRequiredToBoot( 1295 const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired) 1296 { 1297 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot."; 1298 1299 crow::connections::systemBus->async_method_call( 1300 [aResp, tpmRequired](const boost::system::error_code ec, 1301 dbus::utility::MapperGetSubTreeResponse& subtree) { 1302 if (ec) 1303 { 1304 BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree" 1305 << ec; 1306 messages::internalError(aResp->res); 1307 return; 1308 } 1309 if (subtree.empty()) 1310 { 1311 messages::propertyValueNotInList(aResp->res, "ComputerSystem", 1312 "TrustedModuleRequiredToBoot"); 1313 return; 1314 } 1315 1316 /* When there is more than one TPMEnable object... */ 1317 if (subtree.size() > 1) 1318 { 1319 BMCWEB_LOG_DEBUG 1320 << "DBUS response has more than 1 TPM Enable object:" 1321 << subtree.size(); 1322 // Throw an internal Error and return 1323 messages::internalError(aResp->res); 1324 return; 1325 } 1326 1327 // Make sure the Dbus response map has a service and objectPath 1328 // field 1329 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1330 { 1331 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1332 messages::internalError(aResp->res); 1333 return; 1334 } 1335 1336 const std::string& path = subtree[0].first; 1337 const std::string& serv = subtree[0].second.begin()->first; 1338 1339 if (serv.empty()) 1340 { 1341 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!"; 1342 messages::internalError(aResp->res); 1343 return; 1344 } 1345 1346 // Valid TPM Enable object found, now setting the value 1347 crow::connections::systemBus->async_method_call( 1348 [aResp](const boost::system::error_code ec2) { 1349 if (ec2) 1350 { 1351 BMCWEB_LOG_DEBUG 1352 << "DBUS response error: Set TrustedModuleRequiredToBoot" 1353 << ec2; 1354 messages::internalError(aResp->res); 1355 return; 1356 } 1357 BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done."; 1358 }, 1359 serv, path, "org.freedesktop.DBus.Properties", "Set", 1360 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", 1361 dbus::utility::DbusVariantType(tpmRequired)); 1362 }, 1363 "xyz.openbmc_project.ObjectMapper", 1364 "/xyz/openbmc_project/object_mapper", 1365 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1366 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1367 } 1368 1369 /** 1370 * @brief Sets boot properties into DBUS object(s). 1371 * 1372 * @param[in] aResp Shared pointer for generating response message. 1373 * @param[in] bootType The boot type to set. 1374 * @return Integer error code. 1375 */ 1376 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1377 const std::optional<std::string>& bootType) 1378 { 1379 std::string bootTypeStr; 1380 1381 if (!bootType) 1382 { 1383 return; 1384 } 1385 1386 // Source target specified 1387 BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; 1388 // Figure out which DBUS interface and property to use 1389 if (*bootType == "Legacy") 1390 { 1391 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; 1392 } 1393 else if (*bootType == "UEFI") 1394 { 1395 bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; 1396 } 1397 else 1398 { 1399 BMCWEB_LOG_DEBUG << "Invalid property value for " 1400 "BootSourceOverrideMode: " 1401 << *bootType; 1402 messages::propertyValueNotInList(aResp->res, *bootType, 1403 "BootSourceOverrideMode"); 1404 return; 1405 } 1406 1407 // Act on validated parameters 1408 BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; 1409 1410 crow::connections::systemBus->async_method_call( 1411 [aResp](const boost::system::error_code ec) { 1412 if (ec) 1413 { 1414 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1415 if (ec.value() == boost::asio::error::host_unreachable) 1416 { 1417 messages::resourceNotFound(aResp->res, "Set", "BootType"); 1418 return; 1419 } 1420 messages::internalError(aResp->res); 1421 return; 1422 } 1423 BMCWEB_LOG_DEBUG << "Boot type update done."; 1424 }, 1425 "xyz.openbmc_project.Settings", 1426 "/xyz/openbmc_project/control/host0/boot", 1427 "org.freedesktop.DBus.Properties", "Set", 1428 "xyz.openbmc_project.Control.Boot.Type", "BootType", 1429 dbus::utility::DbusVariantType(bootTypeStr)); 1430 } 1431 1432 /** 1433 * @brief Sets boot properties into DBUS object(s). 1434 * 1435 * @param[in] aResp Shared pointer for generating response message. 1436 * @param[in] bootType The boot type to set. 1437 * @return Integer error code. 1438 */ 1439 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1440 const std::optional<std::string>& bootEnable) 1441 { 1442 if (!bootEnable) 1443 { 1444 return; 1445 } 1446 // Source target specified 1447 BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable; 1448 1449 bool bootOverrideEnable = false; 1450 bool bootOverridePersistent = false; 1451 // Figure out which DBUS interface and property to use 1452 if (*bootEnable == "Disabled") 1453 { 1454 bootOverrideEnable = false; 1455 } 1456 else if (*bootEnable == "Once") 1457 { 1458 bootOverrideEnable = true; 1459 bootOverridePersistent = false; 1460 } 1461 else if (*bootEnable == "Continuous") 1462 { 1463 bootOverrideEnable = true; 1464 bootOverridePersistent = true; 1465 } 1466 else 1467 { 1468 BMCWEB_LOG_DEBUG 1469 << "Invalid property value for BootSourceOverrideEnabled: " 1470 << *bootEnable; 1471 messages::propertyValueNotInList(aResp->res, *bootEnable, 1472 "BootSourceOverrideEnabled"); 1473 return; 1474 } 1475 1476 // Act on validated parameters 1477 BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable; 1478 1479 crow::connections::systemBus->async_method_call( 1480 [aResp](const boost::system::error_code ec2) { 1481 if (ec2) 1482 { 1483 BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; 1484 messages::internalError(aResp->res); 1485 return; 1486 } 1487 BMCWEB_LOG_DEBUG << "Boot override enable update done."; 1488 }, 1489 "xyz.openbmc_project.Settings", 1490 "/xyz/openbmc_project/control/host0/boot", 1491 "org.freedesktop.DBus.Properties", "Set", 1492 "xyz.openbmc_project.Object.Enable", "Enabled", 1493 dbus::utility::DbusVariantType(bootOverrideEnable)); 1494 1495 if (!bootOverrideEnable) 1496 { 1497 return; 1498 } 1499 1500 // In case boot override is enabled we need to set correct value for the 1501 // 'one_time' enable DBus interface 1502 BMCWEB_LOG_DEBUG << "DBUS boot override persistent: " 1503 << bootOverridePersistent; 1504 1505 crow::connections::systemBus->async_method_call( 1506 [aResp](const boost::system::error_code ec) { 1507 if (ec) 1508 { 1509 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1510 messages::internalError(aResp->res); 1511 return; 1512 } 1513 BMCWEB_LOG_DEBUG << "Boot one_time update done."; 1514 }, 1515 "xyz.openbmc_project.Settings", 1516 "/xyz/openbmc_project/control/host0/boot/one_time", 1517 "org.freedesktop.DBus.Properties", "Set", 1518 "xyz.openbmc_project.Object.Enable", "Enabled", 1519 dbus::utility::DbusVariantType(!bootOverridePersistent)); 1520 } 1521 1522 /** 1523 * @brief Sets boot properties into DBUS object(s). 1524 * 1525 * @param[in] aResp Shared pointer for generating response message. 1526 * @param[in] bootSource The boot source to set. 1527 * 1528 * @return Integer error code. 1529 */ 1530 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1531 const std::optional<std::string>& bootSource) 1532 { 1533 std::string bootSourceStr; 1534 std::string bootModeStr; 1535 1536 if (!bootSource) 1537 { 1538 return; 1539 } 1540 1541 // Source target specified 1542 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1543 // Figure out which DBUS interface and property to use 1544 if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) != 1545 0) 1546 { 1547 BMCWEB_LOG_DEBUG 1548 << "Invalid property value for BootSourceOverrideTarget: " 1549 << *bootSource; 1550 messages::propertyValueNotInList(aResp->res, *bootSource, 1551 "BootSourceTargetOverride"); 1552 return; 1553 } 1554 1555 // Act on validated parameters 1556 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1557 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1558 1559 crow::connections::systemBus->async_method_call( 1560 [aResp](const boost::system::error_code ec) { 1561 if (ec) 1562 { 1563 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1564 messages::internalError(aResp->res); 1565 return; 1566 } 1567 BMCWEB_LOG_DEBUG << "Boot source update done."; 1568 }, 1569 "xyz.openbmc_project.Settings", 1570 "/xyz/openbmc_project/control/host0/boot", 1571 "org.freedesktop.DBus.Properties", "Set", 1572 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1573 dbus::utility::DbusVariantType(bootSourceStr)); 1574 1575 crow::connections::systemBus->async_method_call( 1576 [aResp](const boost::system::error_code ec) { 1577 if (ec) 1578 { 1579 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1580 messages::internalError(aResp->res); 1581 return; 1582 } 1583 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1584 }, 1585 "xyz.openbmc_project.Settings", 1586 "/xyz/openbmc_project/control/host0/boot", 1587 "org.freedesktop.DBus.Properties", "Set", 1588 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1589 dbus::utility::DbusVariantType(bootModeStr)); 1590 } 1591 1592 /** 1593 * @brief Sets Boot source override properties. 1594 * 1595 * @param[in] aResp Shared pointer for generating response message. 1596 * @param[in] bootSource The boot source from incoming RF request. 1597 * @param[in] bootType The boot type from incoming RF request. 1598 * @param[in] bootEnable The boot override enable from incoming RF request. 1599 * 1600 * @return Integer error code. 1601 */ 1602 1603 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1604 const std::optional<std::string>& bootSource, 1605 const std::optional<std::string>& bootType, 1606 const std::optional<std::string>& bootEnable) 1607 { 1608 BMCWEB_LOG_DEBUG << "Set boot information."; 1609 1610 setBootModeOrSource(aResp, bootSource); 1611 setBootType(aResp, bootType); 1612 setBootEnable(aResp, bootEnable); 1613 } 1614 1615 /** 1616 * @brief Sets AssetTag 1617 * 1618 * @param[in] aResp Shared pointer for generating response message. 1619 * @param[in] assetTag "AssetTag" from request. 1620 * 1621 * @return None. 1622 */ 1623 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1624 const std::string& assetTag) 1625 { 1626 crow::connections::systemBus->async_method_call( 1627 [aResp, 1628 assetTag](const boost::system::error_code ec, 1629 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1630 if (ec) 1631 { 1632 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1633 messages::internalError(aResp->res); 1634 return; 1635 } 1636 if (subtree.empty()) 1637 { 1638 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1639 messages::internalError(aResp->res); 1640 return; 1641 } 1642 // Assume only 1 system D-Bus object 1643 // Throw an error if there is more than 1 1644 if (subtree.size() > 1) 1645 { 1646 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1647 messages::internalError(aResp->res); 1648 return; 1649 } 1650 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1651 { 1652 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1653 messages::internalError(aResp->res); 1654 return; 1655 } 1656 1657 const std::string& path = subtree[0].first; 1658 const std::string& service = subtree[0].second.begin()->first; 1659 1660 if (service.empty()) 1661 { 1662 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1663 messages::internalError(aResp->res); 1664 return; 1665 } 1666 1667 crow::connections::systemBus->async_method_call( 1668 [aResp](const boost::system::error_code ec2) { 1669 if (ec2) 1670 { 1671 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set " 1672 << ec2; 1673 messages::internalError(aResp->res); 1674 return; 1675 } 1676 }, 1677 service, path, "org.freedesktop.DBus.Properties", "Set", 1678 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1679 dbus::utility::DbusVariantType(assetTag)); 1680 }, 1681 "xyz.openbmc_project.ObjectMapper", 1682 "/xyz/openbmc_project/object_mapper", 1683 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1684 "/xyz/openbmc_project/inventory", int32_t(0), 1685 std::array<const char*, 1>{ 1686 "xyz.openbmc_project.Inventory.Item.System"}); 1687 } 1688 1689 /** 1690 * @brief Sets automaticRetry (Auto Reboot) 1691 * 1692 * @param[in] aResp Shared pointer for generating response message. 1693 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1694 * 1695 * @return None. 1696 */ 1697 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1698 const std::string& automaticRetryConfig) 1699 { 1700 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1701 1702 // OpenBMC only supports "Disabled" and "RetryAttempts". 1703 bool autoRebootEnabled = false; 1704 1705 if (automaticRetryConfig == "Disabled") 1706 { 1707 autoRebootEnabled = false; 1708 } 1709 else if (automaticRetryConfig == "RetryAttempts") 1710 { 1711 autoRebootEnabled = true; 1712 } 1713 else 1714 { 1715 BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: " 1716 << automaticRetryConfig; 1717 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1718 "AutomaticRetryConfig"); 1719 return; 1720 } 1721 1722 crow::connections::systemBus->async_method_call( 1723 [aResp](const boost::system::error_code ec) { 1724 if (ec) 1725 { 1726 messages::internalError(aResp->res); 1727 return; 1728 } 1729 }, 1730 "xyz.openbmc_project.Settings", 1731 "/xyz/openbmc_project/control/host0/auto_reboot", 1732 "org.freedesktop.DBus.Properties", "Set", 1733 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1734 dbus::utility::DbusVariantType(autoRebootEnabled)); 1735 } 1736 1737 /** 1738 * @brief Sets power restore policy properties. 1739 * 1740 * @param[in] aResp Shared pointer for generating response message. 1741 * @param[in] policy power restore policy properties from request. 1742 * 1743 * @return None. 1744 */ 1745 inline void 1746 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1747 const std::string& policy) 1748 { 1749 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1750 1751 const boost::container::flat_map<std::string, std::string> policyMaps = { 1752 {"AlwaysOn", 1753 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"}, 1754 {"AlwaysOff", 1755 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"}, 1756 {"LastState", 1757 "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}}; 1758 1759 std::string powerRestorPolicy; 1760 1761 auto policyMapsIt = policyMaps.find(policy); 1762 if (policyMapsIt == policyMaps.end()) 1763 { 1764 messages::propertyValueNotInList(aResp->res, policy, 1765 "PowerRestorePolicy"); 1766 return; 1767 } 1768 1769 powerRestorPolicy = policyMapsIt->second; 1770 1771 crow::connections::systemBus->async_method_call( 1772 [aResp](const boost::system::error_code ec) { 1773 if (ec) 1774 { 1775 messages::internalError(aResp->res); 1776 return; 1777 } 1778 }, 1779 "xyz.openbmc_project.Settings", 1780 "/xyz/openbmc_project/control/host0/power_restore_policy", 1781 "org.freedesktop.DBus.Properties", "Set", 1782 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1783 dbus::utility::DbusVariantType(powerRestorPolicy)); 1784 } 1785 1786 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1787 /** 1788 * @brief Retrieves provisioning status 1789 * 1790 * @param[in] aResp Shared pointer for completing asynchronous calls. 1791 * 1792 * @return None. 1793 */ 1794 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1795 { 1796 BMCWEB_LOG_DEBUG << "Get OEM information."; 1797 crow::connections::systemBus->async_method_call( 1798 [aResp](const boost::system::error_code ec, 1799 const dbus::utility::DBusPropertiesMap& propertiesList) { 1800 nlohmann::json& oemPFR = 1801 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1802 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1803 "#OemComputerSystem.OpenBmc"; 1804 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1805 1806 if (ec) 1807 { 1808 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1809 // not an error, don't have to have the interface 1810 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1811 return; 1812 } 1813 1814 const bool* provState = nullptr; 1815 const bool* lockState = nullptr; 1816 for (const std::pair<std::string, dbus::utility::DbusVariantType>& 1817 property : propertiesList) 1818 { 1819 if (property.first == "UfmProvisioned") 1820 { 1821 provState = std::get_if<bool>(&property.second); 1822 } 1823 else if (property.first == "UfmLocked") 1824 { 1825 lockState = std::get_if<bool>(&property.second); 1826 } 1827 } 1828 1829 if ((provState == nullptr) || (lockState == nullptr)) 1830 { 1831 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1832 messages::internalError(aResp->res); 1833 return; 1834 } 1835 1836 if (*provState == true) 1837 { 1838 if (*lockState == true) 1839 { 1840 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1841 } 1842 else 1843 { 1844 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1845 } 1846 } 1847 else 1848 { 1849 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1850 } 1851 }, 1852 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1853 "org.freedesktop.DBus.Properties", "GetAll", 1854 "xyz.openbmc_project.PFR.Attributes"); 1855 } 1856 #endif 1857 1858 /** 1859 * @brief Translate the PowerMode to a response message. 1860 * 1861 * @param[in] aResp Shared pointer for generating response message. 1862 * @param[in] modeValue PowerMode value to be translated 1863 * 1864 * @return None. 1865 */ 1866 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1867 const std::string& modeValue) 1868 { 1869 if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") 1870 { 1871 aResp->res.jsonValue["PowerMode"] = "Static"; 1872 } 1873 else if ( 1874 modeValue == 1875 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") 1876 { 1877 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1878 } 1879 else if (modeValue == 1880 "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") 1881 { 1882 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1883 } 1884 else if (modeValue == 1885 "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") 1886 { 1887 aResp->res.jsonValue["PowerMode"] = "OEM"; 1888 } 1889 else 1890 { 1891 // Any other values would be invalid 1892 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 1893 messages::internalError(aResp->res); 1894 } 1895 } 1896 1897 /** 1898 * @brief Retrieves system power mode 1899 * 1900 * @param[in] aResp Shared pointer for generating response message. 1901 * 1902 * @return None. 1903 */ 1904 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1905 { 1906 BMCWEB_LOG_DEBUG << "Get power mode."; 1907 1908 // Get Power Mode object path: 1909 crow::connections::systemBus->async_method_call( 1910 [aResp](const boost::system::error_code ec, 1911 const dbus::utility::MapperGetSubTreeResponse& subtree) { 1912 if (ec) 1913 { 1914 BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree " 1915 << ec; 1916 // This is an optional D-Bus object so just return if 1917 // error occurs 1918 return; 1919 } 1920 if (subtree.empty()) 1921 { 1922 // As noted above, this is an optional interface so just return 1923 // if there is no instance found 1924 return; 1925 } 1926 if (subtree.size() > 1) 1927 { 1928 // More then one PowerMode object is not supported and is an 1929 // error 1930 BMCWEB_LOG_DEBUG 1931 << "Found more than 1 system D-Bus Power.Mode objects: " 1932 << subtree.size(); 1933 messages::internalError(aResp->res); 1934 return; 1935 } 1936 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1937 { 1938 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1939 messages::internalError(aResp->res); 1940 return; 1941 } 1942 const std::string& path = subtree[0].first; 1943 const std::string& service = subtree[0].second.begin()->first; 1944 if (service.empty()) 1945 { 1946 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1947 messages::internalError(aResp->res); 1948 return; 1949 } 1950 // Valid Power Mode object found, now read the current value 1951 sdbusplus::asio::getProperty<std::string>( 1952 *crow::connections::systemBus, service, path, 1953 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 1954 [aResp](const boost::system::error_code ec2, 1955 const std::string& pmode) { 1956 if (ec2) 1957 { 1958 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: " 1959 << ec2; 1960 messages::internalError(aResp->res); 1961 return; 1962 } 1963 1964 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = { 1965 "Static", "MaximumPerformance", "PowerSaving"}; 1966 1967 BMCWEB_LOG_DEBUG << "Current power mode: " << pmode; 1968 translatePowerMode(aResp, pmode); 1969 }); 1970 }, 1971 "xyz.openbmc_project.ObjectMapper", 1972 "/xyz/openbmc_project/object_mapper", 1973 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1974 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 1975 } 1976 1977 /** 1978 * @brief Validate the specified mode is valid and return the PowerMode 1979 * name associated with that string 1980 * 1981 * @param[in] aResp Shared pointer for generating response message. 1982 * @param[in] modeString String representing the desired PowerMode 1983 * 1984 * @return PowerMode value or empty string if mode is not valid 1985 */ 1986 inline std::string 1987 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1988 const std::string& modeString) 1989 { 1990 std::string mode; 1991 1992 if (modeString == "Static") 1993 { 1994 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 1995 } 1996 else if (modeString == "MaximumPerformance") 1997 { 1998 mode = 1999 "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; 2000 } 2001 else if (modeString == "PowerSaving") 2002 { 2003 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 2004 } 2005 else 2006 { 2007 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 2008 } 2009 return mode; 2010 } 2011 2012 /** 2013 * @brief Sets system power mode. 2014 * 2015 * @param[in] aResp Shared pointer for generating response message. 2016 * @param[in] pmode System power mode from request. 2017 * 2018 * @return None. 2019 */ 2020 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2021 const std::string& pmode) 2022 { 2023 BMCWEB_LOG_DEBUG << "Set power mode."; 2024 2025 std::string powerMode = validatePowerMode(aResp, pmode); 2026 if (powerMode.empty()) 2027 { 2028 return; 2029 } 2030 2031 // Get Power Mode object path: 2032 crow::connections::systemBus->async_method_call( 2033 [aResp, 2034 powerMode](const boost::system::error_code ec, 2035 const dbus::utility::MapperGetSubTreeResponse& subtree) { 2036 if (ec) 2037 { 2038 BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree " 2039 << ec; 2040 // This is an optional D-Bus object, but user attempted to patch 2041 messages::internalError(aResp->res); 2042 return; 2043 } 2044 if (subtree.empty()) 2045 { 2046 // This is an optional D-Bus object, but user attempted to patch 2047 messages::resourceNotFound(aResp->res, "ComputerSystem", 2048 "PowerMode"); 2049 return; 2050 } 2051 if (subtree.size() > 1) 2052 { 2053 // More then one PowerMode object is not supported and is an 2054 // error 2055 BMCWEB_LOG_DEBUG 2056 << "Found more than 1 system D-Bus Power.Mode objects: " 2057 << subtree.size(); 2058 messages::internalError(aResp->res); 2059 return; 2060 } 2061 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 2062 { 2063 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 2064 messages::internalError(aResp->res); 2065 return; 2066 } 2067 const std::string& path = subtree[0].first; 2068 const std::string& service = subtree[0].second.begin()->first; 2069 if (service.empty()) 2070 { 2071 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 2072 messages::internalError(aResp->res); 2073 return; 2074 } 2075 2076 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2077 << path; 2078 2079 // Set the Power Mode property 2080 crow::connections::systemBus->async_method_call( 2081 [aResp](const boost::system::error_code ec2) { 2082 if (ec2) 2083 { 2084 messages::internalError(aResp->res); 2085 return; 2086 } 2087 }, 2088 service, path, "org.freedesktop.DBus.Properties", "Set", 2089 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2090 dbus::utility::DbusVariantType(powerMode)); 2091 }, 2092 "xyz.openbmc_project.ObjectMapper", 2093 "/xyz/openbmc_project/object_mapper", 2094 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2095 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2096 } 2097 2098 /** 2099 * @brief Translates watchdog timeout action DBUS property value to redfish. 2100 * 2101 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2102 * 2103 * @return Returns as a string, the timeout action in Redfish terms. If 2104 * translation cannot be done, returns an empty string. 2105 */ 2106 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2107 { 2108 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2109 { 2110 return "None"; 2111 } 2112 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2113 { 2114 return "ResetSystem"; 2115 } 2116 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2117 { 2118 return "PowerDown"; 2119 } 2120 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2121 { 2122 return "PowerCycle"; 2123 } 2124 2125 return ""; 2126 } 2127 2128 /** 2129 *@brief Translates timeout action from Redfish to DBUS property value. 2130 * 2131 *@param[in] rfAction The timeout action in Redfish. 2132 * 2133 *@return Returns as a string, the time_out action as expected by DBUS. 2134 *If translation cannot be done, returns an empty string. 2135 */ 2136 2137 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2138 { 2139 if (rfAction == "None") 2140 { 2141 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2142 } 2143 if (rfAction == "PowerCycle") 2144 { 2145 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2146 } 2147 if (rfAction == "PowerDown") 2148 { 2149 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2150 } 2151 if (rfAction == "ResetSystem") 2152 { 2153 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2154 } 2155 2156 return ""; 2157 } 2158 2159 /** 2160 * @brief Retrieves host watchdog timer properties over DBUS 2161 * 2162 * @param[in] aResp Shared pointer for completing asynchronous calls. 2163 * 2164 * @return None. 2165 */ 2166 inline void 2167 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2168 { 2169 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2170 crow::connections::systemBus->async_method_call( 2171 [aResp](const boost::system::error_code ec, 2172 const dbus::utility::DBusPropertiesMap& properties) { 2173 if (ec) 2174 { 2175 // watchdog service is stopped 2176 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2177 return; 2178 } 2179 2180 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2181 2182 nlohmann::json& hostWatchdogTimer = 2183 aResp->res.jsonValue["HostWatchdogTimer"]; 2184 2185 // watchdog service is running/enabled 2186 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2187 2188 for (const auto& property : properties) 2189 { 2190 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2191 if (property.first == "Enabled") 2192 { 2193 const bool* state = std::get_if<bool>(&property.second); 2194 2195 if (state == nullptr) 2196 { 2197 messages::internalError(aResp->res); 2198 return; 2199 } 2200 2201 hostWatchdogTimer["FunctionEnabled"] = *state; 2202 } 2203 else if (property.first == "ExpireAction") 2204 { 2205 const std::string* s = 2206 std::get_if<std::string>(&property.second); 2207 if (s == nullptr) 2208 { 2209 messages::internalError(aResp->res); 2210 return; 2211 } 2212 2213 std::string action = dbusToRfWatchdogAction(*s); 2214 if (action.empty()) 2215 { 2216 messages::internalError(aResp->res); 2217 return; 2218 } 2219 hostWatchdogTimer["TimeoutAction"] = action; 2220 } 2221 } 2222 }, 2223 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2224 "org.freedesktop.DBus.Properties", "GetAll", 2225 "xyz.openbmc_project.State.Watchdog"); 2226 } 2227 2228 /** 2229 * @brief Sets Host WatchDog Timer properties. 2230 * 2231 * @param[in] aResp Shared pointer for generating response message. 2232 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2233 * RF request. 2234 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2235 * 2236 * @return None. 2237 */ 2238 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2239 const std::optional<bool> wdtEnable, 2240 const std::optional<std::string>& wdtTimeOutAction) 2241 { 2242 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2243 2244 if (wdtTimeOutAction) 2245 { 2246 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2247 // check if TimeOut Action is Valid 2248 if (wdtTimeOutActStr.empty()) 2249 { 2250 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2251 << *wdtTimeOutAction; 2252 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2253 "TimeoutAction"); 2254 return; 2255 } 2256 2257 crow::connections::systemBus->async_method_call( 2258 [aResp](const boost::system::error_code ec) { 2259 if (ec) 2260 { 2261 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2262 messages::internalError(aResp->res); 2263 return; 2264 } 2265 }, 2266 "xyz.openbmc_project.Watchdog", 2267 "/xyz/openbmc_project/watchdog/host0", 2268 "org.freedesktop.DBus.Properties", "Set", 2269 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2270 dbus::utility::DbusVariantType(wdtTimeOutActStr)); 2271 } 2272 2273 if (wdtEnable) 2274 { 2275 crow::connections::systemBus->async_method_call( 2276 [aResp](const boost::system::error_code ec) { 2277 if (ec) 2278 { 2279 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2280 messages::internalError(aResp->res); 2281 return; 2282 } 2283 }, 2284 "xyz.openbmc_project.Watchdog", 2285 "/xyz/openbmc_project/watchdog/host0", 2286 "org.freedesktop.DBus.Properties", "Set", 2287 "xyz.openbmc_project.State.Watchdog", "Enabled", 2288 dbus::utility::DbusVariantType(*wdtEnable)); 2289 } 2290 } 2291 2292 /** 2293 * @brief Parse the Idle Power Saver properties into json 2294 * 2295 * @param[in] aResp Shared pointer for completing asynchronous calls. 2296 * @param[in] properties IPS property data from DBus. 2297 * 2298 * @return true if successful 2299 */ 2300 inline bool 2301 parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2302 const dbus::utility::DBusPropertiesMap& 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 dbus::utility::DBusPropertiesMap& 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