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