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 <boost/container/flat_map.hpp> 24 #include <node.hpp> 25 #include <utils/fw_utils.hpp> 26 #include <utils/json_utils.hpp> 27 28 #include <variant> 29 30 namespace redfish 31 { 32 33 /** 34 * @brief Updates the Functional State of DIMMs 35 * 36 * @param[in] aResp Shared pointer for completing asynchronous calls 37 * @param[in] dimmState Dimm's Functional state, true/false 38 * 39 * @return None. 40 */ 41 inline void updateDimmProperties(const std::shared_ptr<AsyncResp>& aResp, 42 const std::variant<bool>& dimmState) 43 { 44 const bool* isDimmFunctional = std::get_if<bool>(&dimmState); 45 if (isDimmFunctional == nullptr) 46 { 47 messages::internalError(aResp->res); 48 return; 49 } 50 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 51 52 // Set it as Enabled if at least one DIMM is functional 53 // Update STATE only if previous State was DISABLED and current Dimm is 54 // ENABLED. 55 nlohmann::json& prevMemSummary = 56 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 57 if (prevMemSummary == "Disabled") 58 { 59 if (*isDimmFunctional == true) 60 { 61 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 62 "Enabled"; 63 } 64 } 65 } 66 67 /* 68 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 69 * 70 * @param[in] aResp Shared pointer for completing asynchronous calls 71 * @param[in] cpuPresenceState CPU present or not 72 * 73 * @return None. 74 */ 75 inline void modifyCpuPresenceState(const std::shared_ptr<AsyncResp>& aResp, 76 const std::variant<bool>& cpuPresenceState) 77 { 78 const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState); 79 80 if (isCpuPresent == nullptr) 81 { 82 messages::internalError(aResp->res); 83 return; 84 } 85 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 86 87 if (*isCpuPresent == true) 88 { 89 nlohmann::json& procCount = 90 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 91 auto procCountPtr = 92 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 93 if (procCountPtr != nullptr) 94 { 95 // shouldn't be possible to be nullptr 96 *procCountPtr += 1; 97 } 98 } 99 } 100 101 /* 102 * @brief Update "ProcessorSummary" "Status" "State" based on 103 * CPU Functional State 104 * 105 * @param[in] aResp Shared pointer for completing asynchronous calls 106 * @param[in] cpuFunctionalState is CPU functional true/false 107 * 108 * @return None. 109 */ 110 inline void 111 modifyCpuFunctionalState(const std::shared_ptr<AsyncResp>& aResp, 112 const std::variant<bool>& cpuFunctionalState) 113 { 114 const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 115 116 if (isCpuFunctional == nullptr) 117 { 118 messages::internalError(aResp->res); 119 return; 120 } 121 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 122 123 nlohmann::json& prevProcState = 124 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 125 126 // Set it as Enabled if at least one CPU is functional 127 // Update STATE only if previous State was Non_Functional and current CPU is 128 // Functional. 129 if (prevProcState == "Disabled") 130 { 131 if (*isCpuFunctional == true) 132 { 133 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 134 "Enabled"; 135 } 136 } 137 } 138 139 /* 140 * @brief Retrieves computer system properties over dbus 141 * 142 * @param[in] aResp Shared pointer for completing asynchronous calls 143 * @param[in] systemHealth Shared HealthPopulate pointer 144 * 145 * @return None. 146 */ 147 inline void 148 getComputerSystem(const std::shared_ptr<AsyncResp>& aResp, 149 const std::shared_ptr<HealthPopulate>& systemHealth) 150 { 151 BMCWEB_LOG_DEBUG << "Get available system components."; 152 153 crow::connections::systemBus->async_method_call( 154 [aResp, systemHealth]( 155 const boost::system::error_code ec, 156 const std::vector<std::pair< 157 std::string, 158 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 159 subtree) { 160 if (ec) 161 { 162 BMCWEB_LOG_DEBUG << "DBUS response error"; 163 messages::internalError(aResp->res); 164 return; 165 } 166 // Iterate over all retrieved ObjectPaths. 167 for (const std::pair<std::string, 168 std::vector<std::pair< 169 std::string, std::vector<std::string>>>>& 170 object : subtree) 171 { 172 const std::string& path = object.first; 173 BMCWEB_LOG_DEBUG << "Got path: " << path; 174 const std::vector< 175 std::pair<std::string, std::vector<std::string>>>& 176 connectionNames = object.second; 177 if (connectionNames.size() < 1) 178 { 179 continue; 180 } 181 182 auto memoryHealth = std::make_shared<HealthPopulate>( 183 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 184 185 auto cpuHealth = std::make_shared<HealthPopulate>( 186 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 187 188 systemHealth->children.emplace_back(memoryHealth); 189 systemHealth->children.emplace_back(cpuHealth); 190 191 // This is not system, so check if it's cpu, dimm, UUID or 192 // BiosVer 193 for (const auto& connection : connectionNames) 194 { 195 for (const auto& interfaceName : connection.second) 196 { 197 if (interfaceName == 198 "xyz.openbmc_project.Inventory.Item.Dimm") 199 { 200 BMCWEB_LOG_DEBUG 201 << "Found Dimm, now get its properties."; 202 203 crow::connections::systemBus->async_method_call( 204 [aResp, service{connection.first}, 205 path](const boost::system::error_code ec2, 206 const std::vector< 207 std::pair<std::string, VariantType>>& 208 properties) { 209 if (ec2) 210 { 211 BMCWEB_LOG_ERROR 212 << "DBUS response error " << ec2; 213 messages::internalError(aResp->res); 214 return; 215 } 216 BMCWEB_LOG_DEBUG << "Got " 217 << properties.size() 218 << " Dimm properties."; 219 220 if (properties.size() > 0) 221 { 222 for (const std::pair<std::string, 223 VariantType>& 224 property : properties) 225 { 226 if (property.first != 227 "MemorySizeInKB") 228 { 229 continue; 230 } 231 const uint32_t* value = 232 std::get_if<uint32_t>( 233 &property.second); 234 if (value == nullptr) 235 { 236 BMCWEB_LOG_DEBUG 237 << "Find incorrect type of " 238 "MemorySize"; 239 continue; 240 } 241 nlohmann::json& totalMemory = 242 aResp->res 243 .jsonValue["MemorySummar" 244 "y"] 245 ["TotalSystemMe" 246 "moryGiB"]; 247 uint64_t* preValue = 248 totalMemory 249 .get_ptr<uint64_t*>(); 250 if (preValue == nullptr) 251 { 252 continue; 253 } 254 aResp->res 255 .jsonValue["MemorySummary"] 256 ["TotalSystemMemoryGi" 257 "B"] = 258 *value / (1024 * 1024) + 259 *preValue; 260 aResp->res 261 .jsonValue["MemorySummary"] 262 ["Status"]["State"] = 263 "Enabled"; 264 } 265 } 266 else 267 { 268 auto getDimmProperties = 269 [aResp]( 270 const boost::system::error_code 271 ec3, 272 const std::variant<bool>& 273 dimmState) { 274 if (ec3) 275 { 276 BMCWEB_LOG_ERROR 277 << "DBUS response " 278 "error " 279 << ec3; 280 return; 281 } 282 updateDimmProperties(aResp, 283 dimmState); 284 }; 285 crow::connections::systemBus 286 ->async_method_call( 287 std::move(getDimmProperties), 288 service, path, 289 "org.freedesktop.DBus." 290 "Properties", 291 "Get", 292 "xyz.openbmc_project.State." 293 "Decorator.OperationalStatus", 294 "Functional"); 295 } 296 }, 297 connection.first, path, 298 "org.freedesktop.DBus.Properties", "GetAll", 299 "xyz.openbmc_project.Inventory.Item.Dimm"); 300 301 memoryHealth->inventory.emplace_back(path); 302 } 303 else if (interfaceName == 304 "xyz.openbmc_project.Inventory.Item.Cpu") 305 { 306 BMCWEB_LOG_DEBUG 307 << "Found Cpu, now get its properties."; 308 309 crow::connections::systemBus->async_method_call( 310 [aResp, service{connection.first}, 311 path](const boost::system::error_code ec2, 312 const std::vector< 313 std::pair<std::string, VariantType>>& 314 properties) { 315 if (ec2) 316 { 317 BMCWEB_LOG_ERROR 318 << "DBUS response error " << ec2; 319 messages::internalError(aResp->res); 320 return; 321 } 322 BMCWEB_LOG_DEBUG << "Got " 323 << properties.size() 324 << " Cpu properties."; 325 326 if (properties.size() > 0) 327 { 328 const uint64_t* processorId = nullptr; 329 const std::string* procFamily = nullptr; 330 nlohmann::json& procSummary = 331 aResp->res.jsonValue["ProcessorSumm" 332 "ary"]; 333 nlohmann::json& procCount = 334 procSummary["Count"]; 335 336 auto procCountPtr = procCount.get_ptr< 337 nlohmann::json:: 338 number_integer_t*>(); 339 if (procCountPtr == nullptr) 340 { 341 messages::internalError(aResp->res); 342 return; 343 } 344 for (const auto& property : properties) 345 { 346 347 if (property.first == "Id") 348 { 349 processorId = 350 std::get_if<uint64_t>( 351 &property.second); 352 if (nullptr != procFamily) 353 { 354 break; 355 } 356 continue; 357 } 358 359 if (property.first == "Family") 360 { 361 procFamily = 362 std::get_if<std::string>( 363 &property.second); 364 if (nullptr != processorId) 365 { 366 break; 367 } 368 continue; 369 } 370 } 371 372 if (procFamily != nullptr && 373 processorId != nullptr) 374 { 375 if (procCountPtr != nullptr && 376 *processorId != 0) 377 { 378 *procCountPtr += 1; 379 procSummary["Status"]["State"] = 380 "Enabled"; 381 382 procSummary["Model"] = 383 *procFamily; 384 } 385 } 386 } 387 else 388 { 389 auto getCpuPresenceState = 390 [aResp]( 391 const boost::system::error_code 392 ec3, 393 const std::variant<bool>& 394 cpuPresenceCheck) { 395 if (ec3) 396 { 397 BMCWEB_LOG_ERROR 398 << "DBUS response " 399 "error " 400 << ec3; 401 return; 402 } 403 modifyCpuPresenceState( 404 aResp, cpuPresenceCheck); 405 }; 406 407 auto getCpuFunctionalState = 408 [aResp]( 409 const boost::system::error_code 410 ec3, 411 const std::variant<bool>& 412 cpuFunctionalCheck) { 413 if (ec3) 414 { 415 BMCWEB_LOG_ERROR 416 << "DBUS response " 417 "error " 418 << ec3; 419 return; 420 } 421 modifyCpuFunctionalState( 422 aResp, cpuFunctionalCheck); 423 }; 424 // Get the Presence of CPU 425 crow::connections::systemBus 426 ->async_method_call( 427 std::move(getCpuPresenceState), 428 service, path, 429 "org.freedesktop.DBus." 430 "Properties", 431 "Get", 432 "xyz.openbmc_project.Inventory." 433 "Item", 434 "Present"); 435 436 // Get the Functional State 437 crow::connections::systemBus 438 ->async_method_call( 439 std::move( 440 getCpuFunctionalState), 441 service, path, 442 "org.freedesktop.DBus." 443 "Properties", 444 "Get", 445 "xyz.openbmc_project.State." 446 "Decorator." 447 "OperationalStatus", 448 "Functional"); 449 450 // Get the MODEL from 451 // xyz.openbmc_project.Inventory.Decorator.Asset 452 // support it later as Model is Empty 453 // currently. 454 } 455 }, 456 connection.first, path, 457 "org.freedesktop.DBus.Properties", "GetAll", 458 "xyz.openbmc_project.Inventory.Item.Cpu"); 459 460 cpuHealth->inventory.emplace_back(path); 461 } 462 else if (interfaceName == 463 "xyz.openbmc_project.Common.UUID") 464 { 465 BMCWEB_LOG_DEBUG 466 << "Found UUID, now get its properties."; 467 crow::connections::systemBus->async_method_call( 468 [aResp]( 469 const boost::system::error_code ec3, 470 const std::vector< 471 std::pair<std::string, VariantType>>& 472 properties) { 473 if (ec3) 474 { 475 BMCWEB_LOG_DEBUG 476 << "DBUS response error " << ec3; 477 messages::internalError(aResp->res); 478 return; 479 } 480 BMCWEB_LOG_DEBUG << "Got " 481 << properties.size() 482 << " UUID properties."; 483 for (const std::pair<std::string, 484 VariantType>& 485 property : properties) 486 { 487 if (property.first == "UUID") 488 { 489 const std::string* value = 490 std::get_if<std::string>( 491 &property.second); 492 493 if (value != nullptr) 494 { 495 std::string valueStr = *value; 496 if (valueStr.size() == 32) 497 { 498 valueStr.insert(8, 1, '-'); 499 valueStr.insert(13, 1, '-'); 500 valueStr.insert(18, 1, '-'); 501 valueStr.insert(23, 1, '-'); 502 } 503 BMCWEB_LOG_DEBUG << "UUID = " 504 << valueStr; 505 aResp->res.jsonValue["UUID"] = 506 valueStr; 507 } 508 } 509 } 510 }, 511 connection.first, path, 512 "org.freedesktop.DBus.Properties", "GetAll", 513 "xyz.openbmc_project.Common.UUID"); 514 } 515 else if (interfaceName == 516 "xyz.openbmc_project.Inventory.Item.System") 517 { 518 crow::connections::systemBus->async_method_call( 519 [aResp]( 520 const boost::system::error_code ec2, 521 const std::vector< 522 std::pair<std::string, VariantType>>& 523 propertiesList) { 524 if (ec2) 525 { 526 // doesn't have to include this 527 // interface 528 return; 529 } 530 BMCWEB_LOG_DEBUG 531 << "Got " << propertiesList.size() 532 << " properties for system"; 533 for (const std::pair<std::string, 534 VariantType>& 535 property : propertiesList) 536 { 537 const std::string& propertyName = 538 property.first; 539 if ((propertyName == "PartNumber") || 540 (propertyName == "SerialNumber") || 541 (propertyName == "Manufacturer") || 542 (propertyName == "Model") || 543 (propertyName == "SubModel")) 544 { 545 const std::string* value = 546 std::get_if<std::string>( 547 &property.second); 548 if (value != nullptr) 549 { 550 aResp->res 551 .jsonValue[propertyName] = 552 *value; 553 } 554 } 555 } 556 557 // Grab the bios version 558 fw_util::populateFirmwareInformation( 559 aResp, fw_util::biosPurpose, 560 "BiosVersion", false); 561 }, 562 connection.first, path, 563 "org.freedesktop.DBus.Properties", "GetAll", 564 "xyz.openbmc_project.Inventory.Decorator." 565 "Asset"); 566 567 crow::connections::systemBus->async_method_call( 568 [aResp]( 569 const boost::system::error_code ec2, 570 const std::variant<std::string>& property) { 571 if (ec2) 572 { 573 // doesn't have to include this 574 // interface 575 return; 576 } 577 578 const std::string* value = 579 std::get_if<std::string>(&property); 580 if (value != nullptr) 581 { 582 aResp->res.jsonValue["AssetTag"] = 583 *value; 584 } 585 }, 586 connection.first, path, 587 "org.freedesktop.DBus.Properties", "Get", 588 "xyz.openbmc_project.Inventory.Decorator." 589 "AssetTag", 590 "AssetTag"); 591 } 592 } 593 } 594 } 595 }, 596 "xyz.openbmc_project.ObjectMapper", 597 "/xyz/openbmc_project/object_mapper", 598 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 599 "/xyz/openbmc_project/inventory", int32_t(0), 600 std::array<const char*, 5>{ 601 "xyz.openbmc_project.Inventory.Decorator.Asset", 602 "xyz.openbmc_project.Inventory.Item.Cpu", 603 "xyz.openbmc_project.Inventory.Item.Dimm", 604 "xyz.openbmc_project.Inventory.Item.System", 605 "xyz.openbmc_project.Common.UUID", 606 }); 607 } 608 609 /** 610 * @brief Retrieves host state properties over dbus 611 * 612 * @param[in] aResp Shared pointer for completing asynchronous calls. 613 * 614 * @return None. 615 */ 616 inline void getHostState(const std::shared_ptr<AsyncResp>& aResp) 617 { 618 BMCWEB_LOG_DEBUG << "Get host information."; 619 crow::connections::systemBus->async_method_call( 620 [aResp](const boost::system::error_code ec, 621 const std::variant<std::string>& hostState) { 622 if (ec) 623 { 624 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 625 messages::internalError(aResp->res); 626 return; 627 } 628 629 const std::string* s = std::get_if<std::string>(&hostState); 630 BMCWEB_LOG_DEBUG << "Host state: " << *s; 631 if (s != nullptr) 632 { 633 // Verify Host State 634 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 635 { 636 aResp->res.jsonValue["PowerState"] = "On"; 637 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 638 } 639 else if (*s == "xyz.openbmc_project.State.Host.HostState." 640 "Quiesced") 641 { 642 aResp->res.jsonValue["PowerState"] = "On"; 643 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 644 } 645 else if (*s == "xyz.openbmc_project.State.Host.HostState." 646 "DiagnosticMode") 647 { 648 aResp->res.jsonValue["PowerState"] = "On"; 649 aResp->res.jsonValue["Status"]["State"] = "InTest"; 650 } 651 else 652 { 653 aResp->res.jsonValue["PowerState"] = "Off"; 654 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 655 } 656 } 657 }, 658 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 659 "org.freedesktop.DBus.Properties", "Get", 660 "xyz.openbmc_project.State.Host", "CurrentHostState"); 661 } 662 663 /** 664 * @brief Translates boot source DBUS property value to redfish. 665 * 666 * @param[in] dbusSource The boot source in DBUS speak. 667 * 668 * @return Returns as a string, the boot source in Redfish terms. If translation 669 * cannot be done, returns an empty string. 670 */ 671 inline std::string dbusToRfBootSource(const std::string& dbusSource) 672 { 673 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 674 { 675 return "None"; 676 } 677 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 678 { 679 return "Hdd"; 680 } 681 if (dbusSource == 682 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 683 { 684 return "Cd"; 685 } 686 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 687 { 688 return "Pxe"; 689 } 690 if (dbusSource == 691 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 692 { 693 return "Usb"; 694 } 695 return ""; 696 } 697 698 /** 699 * @brief Translates boot mode DBUS property value to redfish. 700 * 701 * @param[in] dbusMode The boot mode in DBUS speak. 702 * 703 * @return Returns as a string, the boot mode in Redfish terms. If translation 704 * cannot be done, returns an empty string. 705 */ 706 inline std::string dbusToRfBootMode(const std::string& dbusMode) 707 { 708 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 709 { 710 return "None"; 711 } 712 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 713 { 714 return "Diags"; 715 } 716 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 717 { 718 return "BiosSetup"; 719 } 720 return ""; 721 } 722 723 /** 724 * @brief Translates boot source from Redfish to the DBus boot paths. 725 * 726 * @param[in] rfSource The boot source in Redfish. 727 * @param[out] bootSource The DBus source 728 * @param[out] bootMode the DBus boot mode 729 * 730 * @return Integer error code. 731 */ 732 inline int assignBootParameters(const std::shared_ptr<AsyncResp>& aResp, 733 const std::string& rfSource, 734 std::string& bootSource, std::string& bootMode) 735 { 736 // The caller has initialized the bootSource and bootMode to: 737 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 738 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 739 // Only modify the bootSource/bootMode variable needed to achieve the 740 // desired boot action. 741 742 if (rfSource == "None") 743 { 744 return 0; 745 } 746 if (rfSource == "Pxe") 747 { 748 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 749 } 750 else if (rfSource == "Hdd") 751 { 752 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 753 } 754 else if (rfSource == "Diags") 755 { 756 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 757 } 758 else if (rfSource == "Cd") 759 { 760 bootSource = 761 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 762 } 763 else if (rfSource == "BiosSetup") 764 { 765 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 766 } 767 else if (rfSource == "Usb") 768 { 769 bootSource = 770 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 771 } 772 else 773 { 774 BMCWEB_LOG_DEBUG << "Invalid property value for " 775 "BootSourceOverrideTarget: " 776 << bootSource; 777 messages::propertyValueNotInList(aResp->res, rfSource, 778 "BootSourceTargetOverride"); 779 return -1; 780 } 781 return 0; 782 } 783 /** 784 * @brief Retrieves boot progress of the system 785 * 786 * @param[in] aResp Shared pointer for generating response message. 787 * 788 * @return None. 789 */ 790 inline void getBootProgress(const std::shared_ptr<AsyncResp>& aResp) 791 { 792 crow::connections::systemBus->async_method_call( 793 [aResp](const boost::system::error_code ec, 794 const std::variant<std::string>& bootProgress) { 795 if (ec) 796 { 797 // BootProgress is an optional object so just do nothing if 798 // not found 799 return; 800 } 801 802 const std::string* bootProgressStr = 803 std::get_if<std::string>(&bootProgress); 804 805 if (!bootProgressStr) 806 { 807 // Interface implemented but property not found, return error 808 // for that 809 messages::internalError(aResp->res); 810 return; 811 } 812 813 BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr; 814 815 // Now convert the D-Bus BootProgress to the appropriate Redfish 816 // enum 817 std::string rfBpLastState = "None"; 818 if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress." 819 "ProgressStages.Unspecified") 820 { 821 rfBpLastState = "None"; 822 } 823 else if (*bootProgressStr == 824 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 825 "PrimaryProcInit") 826 { 827 rfBpLastState = "PrimaryProcessorInitializationStarted"; 828 } 829 else if (*bootProgressStr == 830 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 831 "BusInit") 832 { 833 rfBpLastState = "BusInitializationStarted"; 834 } 835 else if (*bootProgressStr == 836 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 837 "MemoryInit") 838 { 839 rfBpLastState = "MemoryInitializationStarted"; 840 } 841 else if (*bootProgressStr == 842 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 843 "SecondaryProcInit") 844 { 845 rfBpLastState = "SecondaryProcessorInitializationStarted"; 846 } 847 else if (*bootProgressStr == 848 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 849 "PCIInit") 850 { 851 rfBpLastState = "PCIResourceConfigStarted"; 852 } 853 else if (*bootProgressStr == 854 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 855 "SystemInitComplete") 856 { 857 rfBpLastState = "SystemHardwareInitializationComplete"; 858 } 859 else if (*bootProgressStr == 860 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 861 "OSStart") 862 { 863 rfBpLastState = "OSBootStarted"; 864 } 865 else if (*bootProgressStr == 866 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 867 "OSRunning") 868 { 869 rfBpLastState = "OSRunning"; 870 } 871 else 872 { 873 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 874 << *bootProgressStr; 875 // Just return the default 876 } 877 878 aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState; 879 }, 880 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 881 "org.freedesktop.DBus.Properties", "Get", 882 "xyz.openbmc_project.State.Boot.Progress", "BootProgress"); 883 } 884 885 /** 886 * @brief Retrieves boot mode over DBUS and fills out the response 887 * 888 * @param[in] aResp Shared pointer for generating response message. 889 * @param[in] bootDbusObj The dbus object to query for boot properties. 890 * 891 * @return None. 892 */ 893 inline void getBootMode(const std::shared_ptr<AsyncResp>& aResp, 894 const std::string& bootDbusObj) 895 { 896 crow::connections::systemBus->async_method_call( 897 [aResp](const boost::system::error_code ec, 898 const std::variant<std::string>& bootMode) { 899 if (ec) 900 { 901 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 902 messages::internalError(aResp->res); 903 return; 904 } 905 906 const std::string* bootModeStr = 907 std::get_if<std::string>(&bootMode); 908 909 if (!bootModeStr) 910 { 911 messages::internalError(aResp->res); 912 return; 913 } 914 915 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 916 917 // TODO (Santosh): Do we need to support override mode? 918 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 919 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 920 "AllowableValues"] = { 921 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 922 923 if (*bootModeStr != 924 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 925 { 926 auto rfMode = dbusToRfBootMode(*bootModeStr); 927 if (!rfMode.empty()) 928 { 929 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 930 rfMode; 931 } 932 } 933 934 // If the BootSourceOverrideTarget is still "None" at the end, 935 // reset the BootSourceOverrideEnabled to indicate that 936 // overrides are disabled 937 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 938 "None") 939 { 940 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 941 "Disabled"; 942 } 943 }, 944 "xyz.openbmc_project.Settings", bootDbusObj, 945 "org.freedesktop.DBus.Properties", "Get", 946 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 947 } 948 949 /** 950 * @brief Retrieves boot source over DBUS 951 * 952 * @param[in] aResp Shared pointer for generating response message. 953 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 954 * 955 * @return None. 956 */ 957 inline void getBootSource(const std::shared_ptr<AsyncResp>& aResp, 958 bool oneTimeEnabled) 959 { 960 std::string bootDbusObj = 961 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 962 : "/xyz/openbmc_project/control/host0/boot"; 963 964 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 965 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 966 (oneTimeEnabled) ? "Once" : "Continuous"; 967 968 crow::connections::systemBus->async_method_call( 969 [aResp, bootDbusObj](const boost::system::error_code ec, 970 const std::variant<std::string>& bootSource) { 971 if (ec) 972 { 973 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 974 messages::internalError(aResp->res); 975 return; 976 } 977 978 const std::string* bootSourceStr = 979 std::get_if<std::string>(&bootSource); 980 981 if (!bootSourceStr) 982 { 983 messages::internalError(aResp->res); 984 return; 985 } 986 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 987 988 auto rfSource = dbusToRfBootSource(*bootSourceStr); 989 if (!rfSource.empty()) 990 { 991 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 992 rfSource; 993 } 994 }, 995 "xyz.openbmc_project.Settings", bootDbusObj, 996 "org.freedesktop.DBus.Properties", "Get", 997 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 998 getBootMode(aResp, bootDbusObj); 999 } 1000 1001 /** 1002 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1003 * get boot source and boot mode. 1004 * 1005 * @param[in] aResp Shared pointer for generating response message. 1006 * 1007 * @return None. 1008 */ 1009 inline void getBootProperties(const std::shared_ptr<AsyncResp>& aResp) 1010 { 1011 BMCWEB_LOG_DEBUG << "Get boot information."; 1012 1013 crow::connections::systemBus->async_method_call( 1014 [aResp](const boost::system::error_code ec, 1015 const std::variant<bool>& oneTime) { 1016 if (ec) 1017 { 1018 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1019 // not an error, don't have to have the interface 1020 return; 1021 } 1022 1023 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1024 1025 if (!oneTimePtr) 1026 { 1027 messages::internalError(aResp->res); 1028 return; 1029 } 1030 getBootSource(aResp, *oneTimePtr); 1031 }, 1032 "xyz.openbmc_project.Settings", 1033 "/xyz/openbmc_project/control/host0/boot/one_time", 1034 "org.freedesktop.DBus.Properties", "Get", 1035 "xyz.openbmc_project.Object.Enable", "Enabled"); 1036 } 1037 1038 /** 1039 * @brief Retrieves the Last Reset Time 1040 * 1041 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1042 * and power off. Even though this is the "system" Redfish object look at the 1043 * chassis D-Bus interface for the LastStateChangeTime since this has the 1044 * last power operation time. 1045 * 1046 * @param[in] aResp Shared pointer for generating response message. 1047 * 1048 * @return None. 1049 */ 1050 inline void getLastResetTime(const std::shared_ptr<AsyncResp>& aResp) 1051 { 1052 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1053 1054 crow::connections::systemBus->async_method_call( 1055 [aResp](const boost::system::error_code ec, 1056 std::variant<uint64_t>& lastResetTime) { 1057 if (ec) 1058 { 1059 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1060 return; 1061 } 1062 1063 const uint64_t* lastResetTimePtr = 1064 std::get_if<uint64_t>(&lastResetTime); 1065 1066 if (!lastResetTimePtr) 1067 { 1068 messages::internalError(aResp->res); 1069 return; 1070 } 1071 // LastStateChangeTime is epoch time, in milliseconds 1072 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1073 time_t lastResetTimeStamp = 1074 static_cast<time_t>(*lastResetTimePtr / 1000); 1075 1076 // Convert to ISO 8601 standard 1077 aResp->res.jsonValue["LastResetTime"] = 1078 crow::utility::getDateTime(lastResetTimeStamp); 1079 }, 1080 "xyz.openbmc_project.State.Chassis", 1081 "/xyz/openbmc_project/state/chassis0", 1082 "org.freedesktop.DBus.Properties", "Get", 1083 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1084 } 1085 1086 /** 1087 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1088 * 1089 * @param[in] aResp Shared pointer for generating response message. 1090 * 1091 * @return None. 1092 */ 1093 inline void getAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp) 1094 { 1095 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1096 1097 crow::connections::systemBus->async_method_call( 1098 [aResp](const boost::system::error_code ec, 1099 std::variant<bool>& autoRebootEnabled) { 1100 if (ec) 1101 { 1102 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1103 return; 1104 } 1105 1106 const bool* autoRebootEnabledPtr = 1107 std::get_if<bool>(&autoRebootEnabled); 1108 1109 if (!autoRebootEnabledPtr) 1110 { 1111 messages::internalError(aResp->res); 1112 return; 1113 } 1114 1115 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1116 if (*autoRebootEnabledPtr == true) 1117 { 1118 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1119 "RetryAttempts"; 1120 // If AutomaticRetry (AutoReboot) is enabled see how many 1121 // attempts are left 1122 crow::connections::systemBus->async_method_call( 1123 [aResp](const boost::system::error_code ec2, 1124 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1125 if (ec2) 1126 { 1127 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1128 return; 1129 } 1130 1131 const uint32_t* autoRebootAttemptsLeftPtr = 1132 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1133 1134 if (!autoRebootAttemptsLeftPtr) 1135 { 1136 messages::internalError(aResp->res); 1137 return; 1138 } 1139 1140 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1141 << *autoRebootAttemptsLeftPtr; 1142 1143 aResp->res 1144 .jsonValue["Boot"] 1145 ["RemainingAutomaticRetryAttempts"] = 1146 *autoRebootAttemptsLeftPtr; 1147 }, 1148 "xyz.openbmc_project.State.Host", 1149 "/xyz/openbmc_project/state/host0", 1150 "org.freedesktop.DBus.Properties", "Get", 1151 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1152 "AttemptsLeft"); 1153 } 1154 else 1155 { 1156 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1157 "Disabled"; 1158 } 1159 1160 // Not on D-Bus. Hardcoded here: 1161 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1162 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1163 1164 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1165 // and RetryAttempts. OpenBMC only supports Disabled and 1166 // RetryAttempts. 1167 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1168 "AllowableValues"] = {"Disabled", 1169 "RetryAttempts"}; 1170 }, 1171 "xyz.openbmc_project.Settings", 1172 "/xyz/openbmc_project/control/host0/auto_reboot", 1173 "org.freedesktop.DBus.Properties", "Get", 1174 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1175 } 1176 1177 /** 1178 * @brief Retrieves power restore policy over DBUS. 1179 * 1180 * @param[in] aResp Shared pointer for generating response message. 1181 * 1182 * @return None. 1183 */ 1184 inline void getPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp) 1185 { 1186 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1187 1188 crow::connections::systemBus->async_method_call( 1189 [aResp](const boost::system::error_code ec, 1190 std::variant<std::string>& policy) { 1191 if (ec) 1192 { 1193 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1194 return; 1195 } 1196 1197 const boost::container::flat_map<std::string, std::string> 1198 policyMaps = { 1199 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1200 "AlwaysOn", 1201 "AlwaysOn"}, 1202 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1203 "AlwaysOff", 1204 "AlwaysOff"}, 1205 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1206 "LastState", 1207 "LastState"}}; 1208 1209 const std::string* policyPtr = std::get_if<std::string>(&policy); 1210 1211 if (!policyPtr) 1212 { 1213 messages::internalError(aResp->res); 1214 return; 1215 } 1216 1217 auto policyMapsIt = policyMaps.find(*policyPtr); 1218 if (policyMapsIt == policyMaps.end()) 1219 { 1220 messages::internalError(aResp->res); 1221 return; 1222 } 1223 1224 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1225 }, 1226 "xyz.openbmc_project.Settings", 1227 "/xyz/openbmc_project/control/host0/power_restore_policy", 1228 "org.freedesktop.DBus.Properties", "Get", 1229 "xyz.openbmc_project.Control.Power.RestorePolicy", 1230 "PowerRestorePolicy"); 1231 } 1232 1233 /** 1234 * @brief Sets boot properties into DBUS object(s). 1235 * 1236 * @param[in] aResp Shared pointer for generating response message. 1237 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 1238 * @param[in] bootSource The boot source to set. 1239 * @param[in] bootEnable The source override "enable" to set. 1240 * 1241 * @return Integer error code. 1242 */ 1243 inline void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 1244 bool oneTimeEnabled, 1245 const std::optional<std::string>& bootSource, 1246 const std::optional<std::string>& bootEnable) 1247 { 1248 std::string bootSourceStr = 1249 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1250 std::string bootModeStr = 1251 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1252 bool oneTimeSetting = oneTimeEnabled; 1253 bool useBootSource = true; 1254 1255 // Validate incoming parameters 1256 if (bootEnable) 1257 { 1258 if (*bootEnable == "Once") 1259 { 1260 oneTimeSetting = true; 1261 } 1262 else if (*bootEnable == "Continuous") 1263 { 1264 oneTimeSetting = false; 1265 } 1266 else if (*bootEnable == "Disabled") 1267 { 1268 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1269 oneTimeSetting = false; 1270 useBootSource = false; 1271 } 1272 else 1273 { 1274 BMCWEB_LOG_DEBUG << "Unsupported value for " 1275 "BootSourceOverrideEnabled: " 1276 << *bootEnable; 1277 messages::propertyValueNotInList(aResp->res, *bootEnable, 1278 "BootSourceOverrideEnabled"); 1279 return; 1280 } 1281 } 1282 1283 if (bootSource && useBootSource) 1284 { 1285 // Source target specified 1286 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1287 // Figure out which DBUS interface and property to use 1288 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1289 bootModeStr)) 1290 { 1291 BMCWEB_LOG_DEBUG 1292 << "Invalid property value for BootSourceOverrideTarget: " 1293 << *bootSource; 1294 messages::propertyValueNotInList(aResp->res, *bootSource, 1295 "BootSourceTargetOverride"); 1296 return; 1297 } 1298 } 1299 1300 // Act on validated parameters 1301 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1302 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1303 const char* bootObj = 1304 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1305 : "/xyz/openbmc_project/control/host0/boot"; 1306 1307 crow::connections::systemBus->async_method_call( 1308 [aResp](const boost::system::error_code ec) { 1309 if (ec) 1310 { 1311 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1312 messages::internalError(aResp->res); 1313 return; 1314 } 1315 BMCWEB_LOG_DEBUG << "Boot source update done."; 1316 }, 1317 "xyz.openbmc_project.Settings", bootObj, 1318 "org.freedesktop.DBus.Properties", "Set", 1319 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1320 std::variant<std::string>(bootSourceStr)); 1321 1322 crow::connections::systemBus->async_method_call( 1323 [aResp](const boost::system::error_code ec) { 1324 if (ec) 1325 { 1326 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1327 messages::internalError(aResp->res); 1328 return; 1329 } 1330 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1331 }, 1332 "xyz.openbmc_project.Settings", bootObj, 1333 "org.freedesktop.DBus.Properties", "Set", 1334 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1335 std::variant<std::string>(bootModeStr)); 1336 1337 crow::connections::systemBus->async_method_call( 1338 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1339 if (ec) 1340 { 1341 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1342 messages::internalError(aResp->res); 1343 return; 1344 } 1345 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1346 }, 1347 "xyz.openbmc_project.Settings", 1348 "/xyz/openbmc_project/control/host0/boot/one_time", 1349 "org.freedesktop.DBus.Properties", "Set", 1350 "xyz.openbmc_project.Object.Enable", "Enabled", 1351 std::variant<bool>(oneTimeSetting)); 1352 } 1353 1354 /** 1355 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1356 * set boot source/boot mode properties. 1357 * 1358 * @param[in] aResp Shared pointer for generating response message. 1359 * @param[in] bootSource The boot source from incoming RF request. 1360 * @param[in] bootEnable The boot override enable from incoming RF request. 1361 * 1362 * @return Integer error code. 1363 */ 1364 inline void setBootSourceProperties(const std::shared_ptr<AsyncResp>& aResp, 1365 std::optional<std::string> bootSource, 1366 std::optional<std::string> bootEnable) 1367 { 1368 BMCWEB_LOG_DEBUG << "Set boot information."; 1369 1370 crow::connections::systemBus->async_method_call( 1371 [aResp, bootSource{std::move(bootSource)}, 1372 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1373 const std::variant<bool>& oneTime) { 1374 if (ec) 1375 { 1376 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1377 messages::internalError(aResp->res); 1378 return; 1379 } 1380 1381 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1382 1383 if (!oneTimePtr) 1384 { 1385 messages::internalError(aResp->res); 1386 return; 1387 } 1388 1389 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1390 1391 setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable); 1392 }, 1393 "xyz.openbmc_project.Settings", 1394 "/xyz/openbmc_project/control/host0/boot/one_time", 1395 "org.freedesktop.DBus.Properties", "Get", 1396 "xyz.openbmc_project.Object.Enable", "Enabled"); 1397 } 1398 1399 /** 1400 * @brief Sets AssetTag 1401 * 1402 * @param[in] aResp Shared pointer for generating response message. 1403 * @param[in] assetTag "AssetTag" from request. 1404 * 1405 * @return None. 1406 */ 1407 inline void setAssetTag(const std::shared_ptr<AsyncResp>& aResp, 1408 const std::string& assetTag) 1409 { 1410 crow::connections::systemBus->async_method_call( 1411 [aResp, assetTag]( 1412 const boost::system::error_code ec, 1413 const std::vector<std::pair< 1414 std::string, 1415 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1416 subtree) { 1417 if (ec) 1418 { 1419 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1420 messages::internalError(aResp->res); 1421 return; 1422 } 1423 if (subtree.size() == 0) 1424 { 1425 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1426 messages::internalError(aResp->res); 1427 return; 1428 } 1429 // Assume only 1 system D-Bus object 1430 // Throw an error if there is more than 1 1431 if (subtree.size() > 1) 1432 { 1433 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1434 messages::internalError(aResp->res); 1435 return; 1436 } 1437 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1438 { 1439 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1440 messages::internalError(aResp->res); 1441 return; 1442 } 1443 1444 const std::string& path = subtree[0].first; 1445 const std::string& service = subtree[0].second.begin()->first; 1446 1447 if (service.empty()) 1448 { 1449 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1450 messages::internalError(aResp->res); 1451 return; 1452 } 1453 1454 crow::connections::systemBus->async_method_call( 1455 [aResp](const boost::system::error_code ec2) { 1456 if (ec2) 1457 { 1458 BMCWEB_LOG_DEBUG 1459 << "D-Bus response error on AssetTag Set " << ec2; 1460 messages::internalError(aResp->res); 1461 return; 1462 } 1463 }, 1464 service, path, "org.freedesktop.DBus.Properties", "Set", 1465 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1466 std::variant<std::string>(assetTag)); 1467 }, 1468 "xyz.openbmc_project.ObjectMapper", 1469 "/xyz/openbmc_project/object_mapper", 1470 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1471 "/xyz/openbmc_project/inventory", int32_t(0), 1472 std::array<const char*, 1>{ 1473 "xyz.openbmc_project.Inventory.Item.System"}); 1474 } 1475 1476 /** 1477 * @brief Sets automaticRetry (Auto Reboot) 1478 * 1479 * @param[in] aResp Shared pointer for generating response message. 1480 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1481 * 1482 * @return None. 1483 */ 1484 inline void setAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp, 1485 const std::string& automaticRetryConfig) 1486 { 1487 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1488 1489 // OpenBMC only supports "Disabled" and "RetryAttempts". 1490 bool autoRebootEnabled; 1491 1492 if (automaticRetryConfig == "Disabled") 1493 { 1494 autoRebootEnabled = false; 1495 } 1496 else if (automaticRetryConfig == "RetryAttempts") 1497 { 1498 autoRebootEnabled = true; 1499 } 1500 else 1501 { 1502 BMCWEB_LOG_DEBUG << "Invalid property value for " 1503 "AutomaticRetryConfig: " 1504 << automaticRetryConfig; 1505 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1506 "AutomaticRetryConfig"); 1507 return; 1508 } 1509 1510 crow::connections::systemBus->async_method_call( 1511 [aResp](const boost::system::error_code ec) { 1512 if (ec) 1513 { 1514 messages::internalError(aResp->res); 1515 return; 1516 } 1517 }, 1518 "xyz.openbmc_project.Settings", 1519 "/xyz/openbmc_project/control/host0/auto_reboot", 1520 "org.freedesktop.DBus.Properties", "Set", 1521 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1522 std::variant<bool>(autoRebootEnabled)); 1523 } 1524 1525 /** 1526 * @brief Sets power restore policy properties. 1527 * 1528 * @param[in] aResp Shared pointer for generating response message. 1529 * @param[in] policy power restore policy properties from request. 1530 * 1531 * @return None. 1532 */ 1533 inline void setPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp, 1534 std::optional<std::string> policy) 1535 { 1536 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1537 1538 const boost::container::flat_map<std::string, std::string> policyMaps = { 1539 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1540 "AlwaysOn"}, 1541 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1542 "AlwaysOff"}, 1543 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1544 "LastState"}}; 1545 1546 std::string powerRestorPolicy; 1547 1548 auto policyMapsIt = policyMaps.find(*policy); 1549 if (policyMapsIt == policyMaps.end()) 1550 { 1551 messages::internalError(aResp->res); 1552 return; 1553 } 1554 1555 powerRestorPolicy = policyMapsIt->second; 1556 1557 crow::connections::systemBus->async_method_call( 1558 [aResp](const boost::system::error_code ec) { 1559 if (ec) 1560 { 1561 messages::internalError(aResp->res); 1562 return; 1563 } 1564 }, 1565 "xyz.openbmc_project.Settings", 1566 "/xyz/openbmc_project/control/host0/power_restore_policy", 1567 "org.freedesktop.DBus.Properties", "Set", 1568 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1569 std::variant<std::string>(powerRestorPolicy)); 1570 } 1571 1572 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1573 /** 1574 * @brief Retrieves provisioning status 1575 * 1576 * @param[in] aResp Shared pointer for completing asynchronous calls. 1577 * 1578 * @return None. 1579 */ 1580 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1581 { 1582 BMCWEB_LOG_DEBUG << "Get OEM information."; 1583 crow::connections::systemBus->async_method_call( 1584 [aResp](const boost::system::error_code ec, 1585 const std::vector<std::pair<std::string, VariantType>>& 1586 propertiesList) { 1587 nlohmann::json& oemPFR = 1588 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1589 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1590 "#OemComputerSystem.OpenBmc"; 1591 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1592 1593 if (ec) 1594 { 1595 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1596 // not an error, don't have to have the interface 1597 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1598 return; 1599 } 1600 1601 const bool* provState = nullptr; 1602 const bool* lockState = nullptr; 1603 for (const std::pair<std::string, VariantType>& property : 1604 propertiesList) 1605 { 1606 if (property.first == "UfmProvisioned") 1607 { 1608 provState = std::get_if<bool>(&property.second); 1609 } 1610 else if (property.first == "UfmLocked") 1611 { 1612 lockState = std::get_if<bool>(&property.second); 1613 } 1614 } 1615 1616 if ((provState == nullptr) || (lockState == nullptr)) 1617 { 1618 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1619 messages::internalError(aResp->res); 1620 return; 1621 } 1622 1623 if (*provState == true) 1624 { 1625 if (*lockState == true) 1626 { 1627 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1628 } 1629 else 1630 { 1631 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1632 } 1633 } 1634 else 1635 { 1636 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1637 } 1638 }, 1639 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1640 "org.freedesktop.DBus.Properties", "GetAll", 1641 "xyz.openbmc_project.PFR.Attributes"); 1642 } 1643 #endif 1644 1645 /** 1646 * @brief Translates watchdog timeout action DBUS property value to redfish. 1647 * 1648 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1649 * 1650 * @return Returns as a string, the timeout action in Redfish terms. If 1651 * translation cannot be done, returns an empty string. 1652 */ 1653 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 1654 { 1655 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1656 { 1657 return "None"; 1658 } 1659 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1660 { 1661 return "ResetSystem"; 1662 } 1663 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1664 { 1665 return "PowerDown"; 1666 } 1667 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1668 { 1669 return "PowerCycle"; 1670 } 1671 1672 return ""; 1673 } 1674 1675 /** 1676 *@brief Translates timeout action from Redfish to DBUS property value. 1677 * 1678 *@param[in] rfAction The timeout action in Redfish. 1679 * 1680 *@return Returns as a string, the time_out action as expected by DBUS. 1681 *If translation cannot be done, returns an empty string. 1682 */ 1683 1684 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 1685 { 1686 if (rfAction == "None") 1687 { 1688 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1689 } 1690 if (rfAction == "PowerCycle") 1691 { 1692 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1693 } 1694 if (rfAction == "PowerDown") 1695 { 1696 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1697 } 1698 if (rfAction == "ResetSystem") 1699 { 1700 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1701 } 1702 1703 return ""; 1704 } 1705 1706 /** 1707 * @brief Retrieves host watchdog timer properties over DBUS 1708 * 1709 * @param[in] aResp Shared pointer for completing asynchronous calls. 1710 * 1711 * @return None. 1712 */ 1713 inline void getHostWatchdogTimer(const std::shared_ptr<AsyncResp>& aResp) 1714 { 1715 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1716 crow::connections::systemBus->async_method_call( 1717 [aResp](const boost::system::error_code ec, 1718 PropertiesType& properties) { 1719 if (ec) 1720 { 1721 // watchdog service is stopped 1722 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1723 return; 1724 } 1725 1726 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1727 1728 nlohmann::json& hostWatchdogTimer = 1729 aResp->res.jsonValue["HostWatchdogTimer"]; 1730 1731 // watchdog service is running/enabled 1732 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1733 1734 for (const auto& property : properties) 1735 { 1736 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1737 if (property.first == "Enabled") 1738 { 1739 const bool* state = std::get_if<bool>(&property.second); 1740 1741 if (!state) 1742 { 1743 messages::internalError(aResp->res); 1744 continue; 1745 } 1746 1747 hostWatchdogTimer["FunctionEnabled"] = *state; 1748 } 1749 else if (property.first == "ExpireAction") 1750 { 1751 const std::string* s = 1752 std::get_if<std::string>(&property.second); 1753 if (!s) 1754 { 1755 messages::internalError(aResp->res); 1756 continue; 1757 } 1758 1759 std::string action = dbusToRfWatchdogAction(*s); 1760 if (action.empty()) 1761 { 1762 messages::internalError(aResp->res); 1763 continue; 1764 } 1765 hostWatchdogTimer["TimeoutAction"] = action; 1766 } 1767 } 1768 }, 1769 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1770 "org.freedesktop.DBus.Properties", "GetAll", 1771 "xyz.openbmc_project.State.Watchdog"); 1772 } 1773 1774 /** 1775 * @brief Sets Host WatchDog Timer properties. 1776 * 1777 * @param[in] aResp Shared pointer for generating response message. 1778 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1779 * RF request. 1780 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1781 * 1782 * @return None. 1783 */ 1784 inline void setWDTProperties(const std::shared_ptr<AsyncResp>& aResp, 1785 const std::optional<bool> wdtEnable, 1786 const std::optional<std::string>& wdtTimeOutAction) 1787 { 1788 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1789 1790 if (wdtTimeOutAction) 1791 { 1792 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1793 // check if TimeOut Action is Valid 1794 if (wdtTimeOutActStr.empty()) 1795 { 1796 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1797 << *wdtTimeOutAction; 1798 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1799 "TimeoutAction"); 1800 return; 1801 } 1802 1803 crow::connections::systemBus->async_method_call( 1804 [aResp](const boost::system::error_code ec) { 1805 if (ec) 1806 { 1807 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1808 messages::internalError(aResp->res); 1809 return; 1810 } 1811 }, 1812 "xyz.openbmc_project.Watchdog", 1813 "/xyz/openbmc_project/watchdog/host0", 1814 "org.freedesktop.DBus.Properties", "Set", 1815 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1816 std::variant<std::string>(wdtTimeOutActStr)); 1817 } 1818 1819 if (wdtEnable) 1820 { 1821 crow::connections::systemBus->async_method_call( 1822 [aResp](const boost::system::error_code ec) { 1823 if (ec) 1824 { 1825 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1826 messages::internalError(aResp->res); 1827 return; 1828 } 1829 }, 1830 "xyz.openbmc_project.Watchdog", 1831 "/xyz/openbmc_project/watchdog/host0", 1832 "org.freedesktop.DBus.Properties", "Set", 1833 "xyz.openbmc_project.State.Watchdog", "Enabled", 1834 std::variant<bool>(*wdtEnable)); 1835 } 1836 } 1837 1838 /** 1839 * SystemsCollection derived class for delivering ComputerSystems Collection 1840 * Schema 1841 */ 1842 class SystemsCollection : public Node 1843 { 1844 public: 1845 SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/") 1846 { 1847 entityPrivileges = { 1848 {boost::beast::http::verb::get, {{"Login"}}}, 1849 {boost::beast::http::verb::head, {{"Login"}}}, 1850 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1851 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1852 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1853 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1854 } 1855 1856 private: 1857 void doGet(crow::Response& res, const crow::Request&, 1858 const std::vector<std::string>&) override 1859 { 1860 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1861 res.jsonValue["@odata.type"] = 1862 "#ComputerSystemCollection.ComputerSystemCollection"; 1863 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1864 res.jsonValue["Name"] = "Computer System Collection"; 1865 1866 crow::connections::systemBus->async_method_call( 1867 [asyncResp](const boost::system::error_code ec, 1868 const std::variant<std::string>& /*hostName*/) { 1869 nlohmann::json& ifaceArray = 1870 asyncResp->res.jsonValue["Members"]; 1871 ifaceArray = nlohmann::json::array(); 1872 auto& count = asyncResp->res.jsonValue["Members@odata.count"]; 1873 ifaceArray.push_back( 1874 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1875 count = ifaceArray.size(); 1876 if (!ec) 1877 { 1878 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1879 ifaceArray.push_back( 1880 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1881 count = ifaceArray.size(); 1882 return; 1883 } 1884 }, 1885 "xyz.openbmc_project.Settings", 1886 "/xyz/openbmc_project/network/hypervisor", 1887 "org.freedesktop.DBus.Properties", "Get", 1888 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1889 } 1890 }; 1891 1892 /** 1893 * SystemActionsReset class supports handle POST method for Reset action. 1894 * The class retrieves and sends data directly to D-Bus. 1895 */ 1896 class SystemActionsReset : public Node 1897 { 1898 public: 1899 SystemActionsReset(App& app) : 1900 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1901 { 1902 entityPrivileges = { 1903 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1904 } 1905 1906 private: 1907 /** 1908 * Function handles POST method request. 1909 * Analyzes POST body message before sends Reset request data to D-Bus. 1910 */ 1911 void doPost(crow::Response& res, const crow::Request& req, 1912 const std::vector<std::string>&) override 1913 { 1914 auto asyncResp = std::make_shared<AsyncResp>(res); 1915 1916 std::string resetType; 1917 if (!json_util::readJson(req, res, "ResetType", resetType)) 1918 { 1919 return; 1920 } 1921 1922 // Get the command and host vs. chassis 1923 std::string command; 1924 bool hostCommand; 1925 if ((resetType == "On") || (resetType == "ForceOn")) 1926 { 1927 command = "xyz.openbmc_project.State.Host.Transition.On"; 1928 hostCommand = true; 1929 } 1930 else if (resetType == "ForceOff") 1931 { 1932 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1933 hostCommand = false; 1934 } 1935 else if (resetType == "ForceRestart") 1936 { 1937 command = 1938 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1939 hostCommand = true; 1940 } 1941 else if (resetType == "GracefulShutdown") 1942 { 1943 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1944 hostCommand = true; 1945 } 1946 else if (resetType == "GracefulRestart") 1947 { 1948 command = 1949 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1950 hostCommand = true; 1951 } 1952 else if (resetType == "PowerCycle") 1953 { 1954 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1955 hostCommand = true; 1956 } 1957 else if (resetType == "Nmi") 1958 { 1959 doNMI(asyncResp); 1960 return; 1961 } 1962 else 1963 { 1964 messages::actionParameterUnknown(res, "Reset", resetType); 1965 return; 1966 } 1967 1968 if (hostCommand) 1969 { 1970 crow::connections::systemBus->async_method_call( 1971 [asyncResp, resetType](const boost::system::error_code ec) { 1972 if (ec) 1973 { 1974 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1975 if (ec.value() == boost::asio::error::invalid_argument) 1976 { 1977 messages::actionParameterNotSupported( 1978 asyncResp->res, resetType, "Reset"); 1979 } 1980 else 1981 { 1982 messages::internalError(asyncResp->res); 1983 } 1984 return; 1985 } 1986 messages::success(asyncResp->res); 1987 }, 1988 "xyz.openbmc_project.State.Host", 1989 "/xyz/openbmc_project/state/host0", 1990 "org.freedesktop.DBus.Properties", "Set", 1991 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1992 std::variant<std::string>{command}); 1993 } 1994 else 1995 { 1996 crow::connections::systemBus->async_method_call( 1997 [asyncResp, resetType](const boost::system::error_code ec) { 1998 if (ec) 1999 { 2000 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2001 if (ec.value() == boost::asio::error::invalid_argument) 2002 { 2003 messages::actionParameterNotSupported( 2004 asyncResp->res, resetType, "Reset"); 2005 } 2006 else 2007 { 2008 messages::internalError(asyncResp->res); 2009 } 2010 return; 2011 } 2012 messages::success(asyncResp->res); 2013 }, 2014 "xyz.openbmc_project.State.Chassis", 2015 "/xyz/openbmc_project/state/chassis0", 2016 "org.freedesktop.DBus.Properties", "Set", 2017 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 2018 std::variant<std::string>{command}); 2019 } 2020 } 2021 /** 2022 * Function transceives data with dbus directly. 2023 */ 2024 void doNMI(const std::shared_ptr<AsyncResp>& asyncResp) 2025 { 2026 constexpr char const* serviceName = 2027 "xyz.openbmc_project.Control.Host.NMI"; 2028 constexpr char const* objectPath = 2029 "/xyz/openbmc_project/control/host0/nmi"; 2030 constexpr char const* interfaceName = 2031 "xyz.openbmc_project.Control.Host.NMI"; 2032 constexpr char const* method = "NMI"; 2033 2034 crow::connections::systemBus->async_method_call( 2035 [asyncResp](const boost::system::error_code ec) { 2036 if (ec) 2037 { 2038 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2039 messages::internalError(asyncResp->res); 2040 return; 2041 } 2042 messages::success(asyncResp->res); 2043 }, 2044 serviceName, objectPath, interfaceName, method); 2045 } 2046 }; 2047 2048 /** 2049 * Systems derived class for delivering Computer Systems Schema. 2050 */ 2051 class Systems : public Node 2052 { 2053 public: 2054 /* 2055 * Default Constructor 2056 */ 2057 Systems(App& app) : Node(app, "/redfish/v1/Systems/system/") 2058 { 2059 entityPrivileges = { 2060 {boost::beast::http::verb::get, {{"Login"}}}, 2061 {boost::beast::http::verb::head, {{"Login"}}}, 2062 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2063 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2064 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2065 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2066 } 2067 2068 private: 2069 /** 2070 * Functions triggers appropriate requests on DBus 2071 */ 2072 void doGet(crow::Response& res, const crow::Request&, 2073 const std::vector<std::string>&) override 2074 { 2075 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_13_0.ComputerSystem"; 2076 res.jsonValue["Name"] = "system"; 2077 res.jsonValue["Id"] = "system"; 2078 res.jsonValue["SystemType"] = "Physical"; 2079 res.jsonValue["Description"] = "Computer System"; 2080 res.jsonValue["ProcessorSummary"]["Count"] = 0; 2081 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 2082 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 2083 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 2084 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 2085 2086 res.jsonValue["Processors"] = { 2087 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2088 res.jsonValue["Memory"] = { 2089 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2090 res.jsonValue["Storage"] = { 2091 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2092 2093 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2094 {"target", 2095 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2096 {"@Redfish.ActionInfo", 2097 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2098 2099 res.jsonValue["LogServices"] = { 2100 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2101 2102 res.jsonValue["Bios"] = { 2103 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2104 2105 res.jsonValue["Links"]["ManagedBy"] = { 2106 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2107 2108 res.jsonValue["Status"] = { 2109 {"Health", "OK"}, 2110 {"State", "Enabled"}, 2111 }; 2112 auto asyncResp = std::make_shared<AsyncResp>(res); 2113 2114 constexpr const std::array<const char*, 4> inventoryForSystems = { 2115 "xyz.openbmc_project.Inventory.Item.Dimm", 2116 "xyz.openbmc_project.Inventory.Item.Cpu", 2117 "xyz.openbmc_project.Inventory.Item.Drive", 2118 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2119 2120 auto health = std::make_shared<HealthPopulate>(asyncResp); 2121 crow::connections::systemBus->async_method_call( 2122 [health](const boost::system::error_code ec, 2123 std::vector<std::string>& resp) { 2124 if (ec) 2125 { 2126 // no inventory 2127 return; 2128 } 2129 2130 health->inventory = std::move(resp); 2131 }, 2132 "xyz.openbmc_project.ObjectMapper", 2133 "/xyz/openbmc_project/object_mapper", 2134 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2135 int32_t(0), inventoryForSystems); 2136 2137 health->populate(); 2138 2139 getMainChassisId(asyncResp, [](const std::string& chassisId, 2140 const std::shared_ptr<AsyncResp>& aRsp) { 2141 aRsp->res.jsonValue["Links"]["Chassis"] = { 2142 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2143 }); 2144 2145 getLocationIndicatorActive(asyncResp); 2146 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2147 getIndicatorLedState(asyncResp); 2148 getComputerSystem(asyncResp, health); 2149 getHostState(asyncResp); 2150 getBootProperties(asyncResp); 2151 getBootProgress(asyncResp); 2152 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2153 getHostWatchdogTimer(asyncResp); 2154 getPowerRestorePolicy(asyncResp); 2155 getAutomaticRetry(asyncResp); 2156 getLastResetTime(asyncResp); 2157 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2158 getProvisioningStatus(asyncResp); 2159 #endif 2160 } 2161 2162 void doPatch(crow::Response& res, const crow::Request& req, 2163 const std::vector<std::string>&) override 2164 { 2165 std::optional<bool> locationIndicatorActive; 2166 std::optional<std::string> indicatorLed; 2167 std::optional<nlohmann::json> bootProps; 2168 std::optional<nlohmann::json> wdtTimerProps; 2169 std::optional<std::string> assetTag; 2170 std::optional<std::string> powerRestorePolicy; 2171 auto asyncResp = std::make_shared<AsyncResp>(res); 2172 2173 if (!json_util::readJson( 2174 req, res, "IndicatorLED", indicatorLed, 2175 "LocationIndicatorActive", locationIndicatorActive, "Boot", 2176 bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy", 2177 powerRestorePolicy, "AssetTag", assetTag)) 2178 { 2179 return; 2180 } 2181 2182 res.result(boost::beast::http::status::no_content); 2183 2184 if (assetTag) 2185 { 2186 setAssetTag(asyncResp, *assetTag); 2187 } 2188 2189 if (wdtTimerProps) 2190 { 2191 std::optional<bool> wdtEnable; 2192 std::optional<std::string> wdtTimeOutAction; 2193 2194 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2195 "FunctionEnabled", wdtEnable, 2196 "TimeoutAction", wdtTimeOutAction)) 2197 { 2198 return; 2199 } 2200 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2201 } 2202 2203 if (bootProps) 2204 { 2205 std::optional<std::string> bootSource; 2206 std::optional<std::string> bootEnable; 2207 std::optional<std::string> automaticRetryConfig; 2208 2209 if (!json_util::readJson( 2210 *bootProps, asyncResp->res, "BootSourceOverrideTarget", 2211 bootSource, "BootSourceOverrideEnabled", bootEnable, 2212 "AutomaticRetryConfig", automaticRetryConfig)) 2213 { 2214 return; 2215 } 2216 if (bootSource || bootEnable) 2217 { 2218 setBootSourceProperties(asyncResp, std::move(bootSource), 2219 std::move(bootEnable)); 2220 } 2221 if (automaticRetryConfig) 2222 { 2223 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2224 } 2225 } 2226 2227 if (locationIndicatorActive) 2228 { 2229 setLocationIndicatorActive(asyncResp, *locationIndicatorActive); 2230 } 2231 2232 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2233 if (indicatorLed) 2234 { 2235 setIndicatorLedState(asyncResp, *indicatorLed); 2236 } 2237 2238 if (powerRestorePolicy) 2239 { 2240 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 2241 } 2242 } 2243 }; 2244 2245 /** 2246 * SystemResetActionInfo derived class for delivering Computer Systems 2247 * ResetType AllowableValues using ResetInfo schema. 2248 */ 2249 class SystemResetActionInfo : public Node 2250 { 2251 public: 2252 /* 2253 * Default Constructor 2254 */ 2255 SystemResetActionInfo(App& app) : 2256 Node(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2257 { 2258 entityPrivileges = { 2259 {boost::beast::http::verb::get, {{"Login"}}}, 2260 {boost::beast::http::verb::head, {{"Login"}}}, 2261 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2262 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2263 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2264 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2265 } 2266 2267 private: 2268 /** 2269 * Functions triggers appropriate requests on DBus 2270 */ 2271 void doGet(crow::Response& res, const crow::Request&, 2272 const std::vector<std::string>&) override 2273 { 2274 res.jsonValue = { 2275 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2276 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2277 {"Name", "Reset Action Info"}, 2278 {"Id", "ResetActionInfo"}, 2279 {"Parameters", 2280 {{{"Name", "ResetType"}, 2281 {"Required", true}, 2282 {"DataType", "String"}, 2283 {"AllowableValues", 2284 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 2285 "GracefulShutdown", "PowerCycle", "Nmi"}}}}}}; 2286 res.end(); 2287 } 2288 }; 2289 } // namespace redfish 2290