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