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