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