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