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 if (*s == "xyz.openbmc_project.State.Host.HostState." 652 "TransitioningToRunning") 653 { 654 aResp->res.jsonValue["PowerState"] = "PoweringOn"; 655 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 656 } 657 else if (*s == "xyz.openbmc_project.State.Host.HostState." 658 "TransitioningToOff") 659 { 660 aResp->res.jsonValue["PowerState"] = "PoweringOff"; 661 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 662 } 663 else 664 { 665 aResp->res.jsonValue["PowerState"] = "Off"; 666 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 667 } 668 } 669 }, 670 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 671 "org.freedesktop.DBus.Properties", "Get", 672 "xyz.openbmc_project.State.Host", "CurrentHostState"); 673 } 674 675 /** 676 * @brief Translates boot source DBUS property value to redfish. 677 * 678 * @param[in] dbusSource The boot source in DBUS speak. 679 * 680 * @return Returns as a string, the boot source in Redfish terms. If translation 681 * cannot be done, returns an empty string. 682 */ 683 inline std::string dbusToRfBootSource(const std::string& dbusSource) 684 { 685 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 686 { 687 return "None"; 688 } 689 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 690 { 691 return "Hdd"; 692 } 693 if (dbusSource == 694 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 695 { 696 return "Cd"; 697 } 698 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 699 { 700 return "Pxe"; 701 } 702 if (dbusSource == 703 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 704 { 705 return "Usb"; 706 } 707 return ""; 708 } 709 710 /** 711 * @brief Translates boot mode DBUS property value to redfish. 712 * 713 * @param[in] dbusMode The boot mode in DBUS speak. 714 * 715 * @return Returns as a string, the boot mode in Redfish terms. If translation 716 * cannot be done, returns an empty string. 717 */ 718 inline std::string dbusToRfBootMode(const std::string& dbusMode) 719 { 720 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 721 { 722 return "None"; 723 } 724 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 725 { 726 return "Diags"; 727 } 728 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 729 { 730 return "BiosSetup"; 731 } 732 return ""; 733 } 734 735 /** 736 * @brief Translates boot source from Redfish to the DBus boot paths. 737 * 738 * @param[in] rfSource The boot source in Redfish. 739 * @param[out] bootSource The DBus source 740 * @param[out] bootMode the DBus boot mode 741 * 742 * @return Integer error code. 743 */ 744 inline int assignBootParameters(const std::shared_ptr<AsyncResp>& aResp, 745 const std::string& rfSource, 746 std::string& bootSource, std::string& bootMode) 747 { 748 // The caller has initialized the bootSource and bootMode to: 749 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 750 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 751 // Only modify the bootSource/bootMode variable needed to achieve the 752 // desired boot action. 753 754 if (rfSource == "None") 755 { 756 return 0; 757 } 758 if (rfSource == "Pxe") 759 { 760 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 761 } 762 else if (rfSource == "Hdd") 763 { 764 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 765 } 766 else if (rfSource == "Diags") 767 { 768 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 769 } 770 else if (rfSource == "Cd") 771 { 772 bootSource = 773 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 774 } 775 else if (rfSource == "BiosSetup") 776 { 777 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 778 } 779 else if (rfSource == "Usb") 780 { 781 bootSource = 782 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 783 } 784 else 785 { 786 BMCWEB_LOG_DEBUG << "Invalid property value for " 787 "BootSourceOverrideTarget: " 788 << bootSource; 789 messages::propertyValueNotInList(aResp->res, rfSource, 790 "BootSourceTargetOverride"); 791 return -1; 792 } 793 return 0; 794 } 795 /** 796 * @brief Retrieves boot progress of the system 797 * 798 * @param[in] aResp Shared pointer for generating response message. 799 * 800 * @return None. 801 */ 802 inline void getBootProgress(const std::shared_ptr<AsyncResp>& aResp) 803 { 804 crow::connections::systemBus->async_method_call( 805 [aResp](const boost::system::error_code ec, 806 const std::variant<std::string>& bootProgress) { 807 if (ec) 808 { 809 // BootProgress is an optional object so just do nothing if 810 // not found 811 return; 812 } 813 814 const std::string* bootProgressStr = 815 std::get_if<std::string>(&bootProgress); 816 817 if (!bootProgressStr) 818 { 819 // Interface implemented but property not found, return error 820 // for that 821 messages::internalError(aResp->res); 822 return; 823 } 824 825 BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr; 826 827 // Now convert the D-Bus BootProgress to the appropriate Redfish 828 // enum 829 std::string rfBpLastState = "None"; 830 if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress." 831 "ProgressStages.Unspecified") 832 { 833 rfBpLastState = "None"; 834 } 835 else if (*bootProgressStr == 836 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 837 "PrimaryProcInit") 838 { 839 rfBpLastState = "PrimaryProcessorInitializationStarted"; 840 } 841 else if (*bootProgressStr == 842 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 843 "BusInit") 844 { 845 rfBpLastState = "BusInitializationStarted"; 846 } 847 else if (*bootProgressStr == 848 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 849 "MemoryInit") 850 { 851 rfBpLastState = "MemoryInitializationStarted"; 852 } 853 else if (*bootProgressStr == 854 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 855 "SecondaryProcInit") 856 { 857 rfBpLastState = "SecondaryProcessorInitializationStarted"; 858 } 859 else if (*bootProgressStr == 860 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 861 "PCIInit") 862 { 863 rfBpLastState = "PCIResourceConfigStarted"; 864 } 865 else if (*bootProgressStr == 866 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 867 "SystemInitComplete") 868 { 869 rfBpLastState = "SystemHardwareInitializationComplete"; 870 } 871 else if (*bootProgressStr == 872 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 873 "OSStart") 874 { 875 rfBpLastState = "OSBootStarted"; 876 } 877 else if (*bootProgressStr == 878 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 879 "OSRunning") 880 { 881 rfBpLastState = "OSRunning"; 882 } 883 else 884 { 885 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 886 << *bootProgressStr; 887 // Just return the default 888 } 889 890 aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState; 891 }, 892 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 893 "org.freedesktop.DBus.Properties", "Get", 894 "xyz.openbmc_project.State.Boot.Progress", "BootProgress"); 895 } 896 897 /** 898 * @brief Retrieves boot mode over DBUS and fills out the response 899 * 900 * @param[in] aResp Shared pointer for generating response message. 901 * @param[in] bootDbusObj The dbus object to query for boot properties. 902 * 903 * @return None. 904 */ 905 inline void getBootMode(const std::shared_ptr<AsyncResp>& aResp, 906 const std::string& bootDbusObj) 907 { 908 crow::connections::systemBus->async_method_call( 909 [aResp](const boost::system::error_code ec, 910 const std::variant<std::string>& bootMode) { 911 if (ec) 912 { 913 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 914 messages::internalError(aResp->res); 915 return; 916 } 917 918 const std::string* bootModeStr = 919 std::get_if<std::string>(&bootMode); 920 921 if (!bootModeStr) 922 { 923 messages::internalError(aResp->res); 924 return; 925 } 926 927 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 928 929 // TODO (Santosh): Do we need to support override mode? 930 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 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 // If the BootSourceOverrideTarget is still "None" at the end, 947 // reset the BootSourceOverrideEnabled to indicate that 948 // overrides are disabled 949 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 950 "None") 951 { 952 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 953 "Disabled"; 954 } 955 }, 956 "xyz.openbmc_project.Settings", bootDbusObj, 957 "org.freedesktop.DBus.Properties", "Get", 958 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 959 } 960 961 /** 962 * @brief Retrieves boot source over DBUS 963 * 964 * @param[in] aResp Shared pointer for generating response message. 965 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 966 * 967 * @return None. 968 */ 969 inline void getBootSource(const std::shared_ptr<AsyncResp>& aResp, 970 bool oneTimeEnabled) 971 { 972 std::string bootDbusObj = 973 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 974 : "/xyz/openbmc_project/control/host0/boot"; 975 976 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 977 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 978 (oneTimeEnabled) ? "Once" : "Continuous"; 979 980 crow::connections::systemBus->async_method_call( 981 [aResp, bootDbusObj](const boost::system::error_code ec, 982 const std::variant<std::string>& bootSource) { 983 if (ec) 984 { 985 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 986 messages::internalError(aResp->res); 987 return; 988 } 989 990 const std::string* bootSourceStr = 991 std::get_if<std::string>(&bootSource); 992 993 if (!bootSourceStr) 994 { 995 messages::internalError(aResp->res); 996 return; 997 } 998 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 999 1000 auto rfSource = dbusToRfBootSource(*bootSourceStr); 1001 if (!rfSource.empty()) 1002 { 1003 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1004 rfSource; 1005 } 1006 }, 1007 "xyz.openbmc_project.Settings", bootDbusObj, 1008 "org.freedesktop.DBus.Properties", "Get", 1009 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 1010 getBootMode(aResp, bootDbusObj); 1011 } 1012 1013 /** 1014 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1015 * get boot source and boot mode. 1016 * 1017 * @param[in] aResp Shared pointer for generating response message. 1018 * 1019 * @return None. 1020 */ 1021 inline void getBootProperties(const std::shared_ptr<AsyncResp>& aResp) 1022 { 1023 BMCWEB_LOG_DEBUG << "Get boot information."; 1024 1025 crow::connections::systemBus->async_method_call( 1026 [aResp](const boost::system::error_code ec, 1027 const std::variant<bool>& oneTime) { 1028 if (ec) 1029 { 1030 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1031 // not an error, don't have to have the interface 1032 return; 1033 } 1034 1035 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1036 1037 if (!oneTimePtr) 1038 { 1039 messages::internalError(aResp->res); 1040 return; 1041 } 1042 getBootSource(aResp, *oneTimePtr); 1043 }, 1044 "xyz.openbmc_project.Settings", 1045 "/xyz/openbmc_project/control/host0/boot/one_time", 1046 "org.freedesktop.DBus.Properties", "Get", 1047 "xyz.openbmc_project.Object.Enable", "Enabled"); 1048 } 1049 1050 /** 1051 * @brief Retrieves the Last Reset Time 1052 * 1053 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1054 * and power off. Even though this is the "system" Redfish object look at the 1055 * chassis D-Bus interface for the LastStateChangeTime since this has the 1056 * last power operation time. 1057 * 1058 * @param[in] aResp Shared pointer for generating response message. 1059 * 1060 * @return None. 1061 */ 1062 inline void getLastResetTime(const std::shared_ptr<AsyncResp>& aResp) 1063 { 1064 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1065 1066 crow::connections::systemBus->async_method_call( 1067 [aResp](const boost::system::error_code ec, 1068 std::variant<uint64_t>& lastResetTime) { 1069 if (ec) 1070 { 1071 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1072 return; 1073 } 1074 1075 const uint64_t* lastResetTimePtr = 1076 std::get_if<uint64_t>(&lastResetTime); 1077 1078 if (!lastResetTimePtr) 1079 { 1080 messages::internalError(aResp->res); 1081 return; 1082 } 1083 // LastStateChangeTime is epoch time, in milliseconds 1084 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1085 time_t lastResetTimeStamp = 1086 static_cast<time_t>(*lastResetTimePtr / 1000); 1087 1088 // Convert to ISO 8601 standard 1089 aResp->res.jsonValue["LastResetTime"] = 1090 crow::utility::getDateTime(lastResetTimeStamp); 1091 }, 1092 "xyz.openbmc_project.State.Chassis", 1093 "/xyz/openbmc_project/state/chassis0", 1094 "org.freedesktop.DBus.Properties", "Get", 1095 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1096 } 1097 1098 /** 1099 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1100 * 1101 * @param[in] aResp Shared pointer for generating response message. 1102 * 1103 * @return None. 1104 */ 1105 inline void getAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp) 1106 { 1107 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1108 1109 crow::connections::systemBus->async_method_call( 1110 [aResp](const boost::system::error_code ec, 1111 std::variant<bool>& autoRebootEnabled) { 1112 if (ec) 1113 { 1114 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1115 return; 1116 } 1117 1118 const bool* autoRebootEnabledPtr = 1119 std::get_if<bool>(&autoRebootEnabled); 1120 1121 if (!autoRebootEnabledPtr) 1122 { 1123 messages::internalError(aResp->res); 1124 return; 1125 } 1126 1127 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1128 if (*autoRebootEnabledPtr == true) 1129 { 1130 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1131 "RetryAttempts"; 1132 // If AutomaticRetry (AutoReboot) is enabled see how many 1133 // attempts are left 1134 crow::connections::systemBus->async_method_call( 1135 [aResp](const boost::system::error_code ec2, 1136 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1137 if (ec2) 1138 { 1139 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1140 return; 1141 } 1142 1143 const uint32_t* autoRebootAttemptsLeftPtr = 1144 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1145 1146 if (!autoRebootAttemptsLeftPtr) 1147 { 1148 messages::internalError(aResp->res); 1149 return; 1150 } 1151 1152 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1153 << *autoRebootAttemptsLeftPtr; 1154 1155 aResp->res 1156 .jsonValue["Boot"] 1157 ["RemainingAutomaticRetryAttempts"] = 1158 *autoRebootAttemptsLeftPtr; 1159 }, 1160 "xyz.openbmc_project.State.Host", 1161 "/xyz/openbmc_project/state/host0", 1162 "org.freedesktop.DBus.Properties", "Get", 1163 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1164 "AttemptsLeft"); 1165 } 1166 else 1167 { 1168 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1169 "Disabled"; 1170 } 1171 1172 // Not on D-Bus. Hardcoded here: 1173 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1174 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1175 1176 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1177 // and RetryAttempts. OpenBMC only supports Disabled and 1178 // RetryAttempts. 1179 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1180 "AllowableValues"] = {"Disabled", 1181 "RetryAttempts"}; 1182 }, 1183 "xyz.openbmc_project.Settings", 1184 "/xyz/openbmc_project/control/host0/auto_reboot", 1185 "org.freedesktop.DBus.Properties", "Get", 1186 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1187 } 1188 1189 /** 1190 * @brief Retrieves power restore policy over DBUS. 1191 * 1192 * @param[in] aResp Shared pointer for generating response message. 1193 * 1194 * @return None. 1195 */ 1196 inline void getPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp) 1197 { 1198 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1199 1200 crow::connections::systemBus->async_method_call( 1201 [aResp](const boost::system::error_code ec, 1202 std::variant<std::string>& policy) { 1203 if (ec) 1204 { 1205 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1206 return; 1207 } 1208 1209 const boost::container::flat_map<std::string, std::string> 1210 policyMaps = { 1211 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1212 "AlwaysOn", 1213 "AlwaysOn"}, 1214 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1215 "AlwaysOff", 1216 "AlwaysOff"}, 1217 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1218 "Restore", 1219 "LastState"}}; 1220 1221 const std::string* policyPtr = std::get_if<std::string>(&policy); 1222 1223 if (!policyPtr) 1224 { 1225 messages::internalError(aResp->res); 1226 return; 1227 } 1228 1229 auto policyMapsIt = policyMaps.find(*policyPtr); 1230 if (policyMapsIt == policyMaps.end()) 1231 { 1232 messages::internalError(aResp->res); 1233 return; 1234 } 1235 1236 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1237 }, 1238 "xyz.openbmc_project.Settings", 1239 "/xyz/openbmc_project/control/host0/power_restore_policy", 1240 "org.freedesktop.DBus.Properties", "Get", 1241 "xyz.openbmc_project.Control.Power.RestorePolicy", 1242 "PowerRestorePolicy"); 1243 } 1244 1245 /** 1246 * @brief Sets boot properties into DBUS object(s). 1247 * 1248 * @param[in] aResp Shared pointer for generating response message. 1249 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 1250 * @param[in] bootSource The boot source to set. 1251 * @param[in] bootEnable The source override "enable" to set. 1252 * 1253 * @return Integer error code. 1254 */ 1255 inline void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 1256 bool oneTimeEnabled, 1257 const std::optional<std::string>& bootSource, 1258 const std::optional<std::string>& bootEnable) 1259 { 1260 std::string bootSourceStr = 1261 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1262 std::string bootModeStr = 1263 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1264 bool oneTimeSetting = oneTimeEnabled; 1265 bool useBootSource = true; 1266 1267 // Validate incoming parameters 1268 if (bootEnable) 1269 { 1270 if (*bootEnable == "Once") 1271 { 1272 oneTimeSetting = true; 1273 } 1274 else if (*bootEnable == "Continuous") 1275 { 1276 oneTimeSetting = false; 1277 } 1278 else if (*bootEnable == "Disabled") 1279 { 1280 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1281 oneTimeSetting = false; 1282 useBootSource = false; 1283 } 1284 else 1285 { 1286 BMCWEB_LOG_DEBUG << "Unsupported value for " 1287 "BootSourceOverrideEnabled: " 1288 << *bootEnable; 1289 messages::propertyValueNotInList(aResp->res, *bootEnable, 1290 "BootSourceOverrideEnabled"); 1291 return; 1292 } 1293 } 1294 1295 if (bootSource && useBootSource) 1296 { 1297 // Source target specified 1298 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1299 // Figure out which DBUS interface and property to use 1300 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1301 bootModeStr)) 1302 { 1303 BMCWEB_LOG_DEBUG 1304 << "Invalid property value for BootSourceOverrideTarget: " 1305 << *bootSource; 1306 messages::propertyValueNotInList(aResp->res, *bootSource, 1307 "BootSourceTargetOverride"); 1308 return; 1309 } 1310 } 1311 1312 // Act on validated parameters 1313 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1314 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1315 const char* bootObj = 1316 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1317 : "/xyz/openbmc_project/control/host0/boot"; 1318 1319 crow::connections::systemBus->async_method_call( 1320 [aResp](const boost::system::error_code ec) { 1321 if (ec) 1322 { 1323 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1324 messages::internalError(aResp->res); 1325 return; 1326 } 1327 BMCWEB_LOG_DEBUG << "Boot source update done."; 1328 }, 1329 "xyz.openbmc_project.Settings", bootObj, 1330 "org.freedesktop.DBus.Properties", "Set", 1331 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1332 std::variant<std::string>(bootSourceStr)); 1333 1334 crow::connections::systemBus->async_method_call( 1335 [aResp](const boost::system::error_code ec) { 1336 if (ec) 1337 { 1338 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1339 messages::internalError(aResp->res); 1340 return; 1341 } 1342 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1343 }, 1344 "xyz.openbmc_project.Settings", bootObj, 1345 "org.freedesktop.DBus.Properties", "Set", 1346 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1347 std::variant<std::string>(bootModeStr)); 1348 1349 crow::connections::systemBus->async_method_call( 1350 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1351 if (ec) 1352 { 1353 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1354 messages::internalError(aResp->res); 1355 return; 1356 } 1357 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1358 }, 1359 "xyz.openbmc_project.Settings", 1360 "/xyz/openbmc_project/control/host0/boot/one_time", 1361 "org.freedesktop.DBus.Properties", "Set", 1362 "xyz.openbmc_project.Object.Enable", "Enabled", 1363 std::variant<bool>(oneTimeSetting)); 1364 } 1365 1366 /** 1367 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1368 * set boot source/boot mode properties. 1369 * 1370 * @param[in] aResp Shared pointer for generating response message. 1371 * @param[in] bootSource The boot source from incoming RF request. 1372 * @param[in] bootEnable The boot override enable from incoming RF request. 1373 * 1374 * @return Integer error code. 1375 */ 1376 inline void setBootSourceProperties(const std::shared_ptr<AsyncResp>& aResp, 1377 std::optional<std::string> bootSource, 1378 std::optional<std::string> bootEnable) 1379 { 1380 BMCWEB_LOG_DEBUG << "Set boot information."; 1381 1382 crow::connections::systemBus->async_method_call( 1383 [aResp, bootSource{std::move(bootSource)}, 1384 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1385 const std::variant<bool>& oneTime) { 1386 if (ec) 1387 { 1388 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1389 messages::internalError(aResp->res); 1390 return; 1391 } 1392 1393 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1394 1395 if (!oneTimePtr) 1396 { 1397 messages::internalError(aResp->res); 1398 return; 1399 } 1400 1401 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1402 1403 setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable); 1404 }, 1405 "xyz.openbmc_project.Settings", 1406 "/xyz/openbmc_project/control/host0/boot/one_time", 1407 "org.freedesktop.DBus.Properties", "Get", 1408 "xyz.openbmc_project.Object.Enable", "Enabled"); 1409 } 1410 1411 /** 1412 * @brief Sets AssetTag 1413 * 1414 * @param[in] aResp Shared pointer for generating response message. 1415 * @param[in] assetTag "AssetTag" from request. 1416 * 1417 * @return None. 1418 */ 1419 inline void setAssetTag(const std::shared_ptr<AsyncResp>& aResp, 1420 const std::string& assetTag) 1421 { 1422 crow::connections::systemBus->async_method_call( 1423 [aResp, assetTag]( 1424 const boost::system::error_code ec, 1425 const std::vector<std::pair< 1426 std::string, 1427 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1428 subtree) { 1429 if (ec) 1430 { 1431 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1432 messages::internalError(aResp->res); 1433 return; 1434 } 1435 if (subtree.size() == 0) 1436 { 1437 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1438 messages::internalError(aResp->res); 1439 return; 1440 } 1441 // Assume only 1 system D-Bus object 1442 // Throw an error if there is more than 1 1443 if (subtree.size() > 1) 1444 { 1445 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1446 messages::internalError(aResp->res); 1447 return; 1448 } 1449 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1450 { 1451 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1452 messages::internalError(aResp->res); 1453 return; 1454 } 1455 1456 const std::string& path = subtree[0].first; 1457 const std::string& service = subtree[0].second.begin()->first; 1458 1459 if (service.empty()) 1460 { 1461 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1462 messages::internalError(aResp->res); 1463 return; 1464 } 1465 1466 crow::connections::systemBus->async_method_call( 1467 [aResp](const boost::system::error_code ec2) { 1468 if (ec2) 1469 { 1470 BMCWEB_LOG_DEBUG 1471 << "D-Bus response error on AssetTag Set " << ec2; 1472 messages::internalError(aResp->res); 1473 return; 1474 } 1475 }, 1476 service, path, "org.freedesktop.DBus.Properties", "Set", 1477 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1478 std::variant<std::string>(assetTag)); 1479 }, 1480 "xyz.openbmc_project.ObjectMapper", 1481 "/xyz/openbmc_project/object_mapper", 1482 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1483 "/xyz/openbmc_project/inventory", int32_t(0), 1484 std::array<const char*, 1>{ 1485 "xyz.openbmc_project.Inventory.Item.System"}); 1486 } 1487 1488 /** 1489 * @brief Sets automaticRetry (Auto Reboot) 1490 * 1491 * @param[in] aResp Shared pointer for generating response message. 1492 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1493 * 1494 * @return None. 1495 */ 1496 inline void setAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp, 1497 const std::string& automaticRetryConfig) 1498 { 1499 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1500 1501 // OpenBMC only supports "Disabled" and "RetryAttempts". 1502 bool autoRebootEnabled; 1503 1504 if (automaticRetryConfig == "Disabled") 1505 { 1506 autoRebootEnabled = false; 1507 } 1508 else if (automaticRetryConfig == "RetryAttempts") 1509 { 1510 autoRebootEnabled = true; 1511 } 1512 else 1513 { 1514 BMCWEB_LOG_DEBUG << "Invalid property value for " 1515 "AutomaticRetryConfig: " 1516 << automaticRetryConfig; 1517 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1518 "AutomaticRetryConfig"); 1519 return; 1520 } 1521 1522 crow::connections::systemBus->async_method_call( 1523 [aResp](const boost::system::error_code ec) { 1524 if (ec) 1525 { 1526 messages::internalError(aResp->res); 1527 return; 1528 } 1529 }, 1530 "xyz.openbmc_project.Settings", 1531 "/xyz/openbmc_project/control/host0/auto_reboot", 1532 "org.freedesktop.DBus.Properties", "Set", 1533 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1534 std::variant<bool>(autoRebootEnabled)); 1535 } 1536 1537 /** 1538 * @brief Sets power restore policy properties. 1539 * 1540 * @param[in] aResp Shared pointer for generating response message. 1541 * @param[in] policy power restore policy properties from request. 1542 * 1543 * @return None. 1544 */ 1545 inline void setPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp, 1546 const std::string& policy) 1547 { 1548 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1549 1550 const boost::container::flat_map<std::string, std::string> policyMaps = { 1551 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1552 "AlwaysOn"}, 1553 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1554 "AlwaysOff"}, 1555 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1556 "Restore"}}; 1557 1558 std::string powerRestorPolicy; 1559 1560 auto policyMapsIt = policyMaps.find(policy); 1561 if (policyMapsIt == policyMaps.end()) 1562 { 1563 messages::propertyValueNotInList(aResp->res, policy, 1564 "PowerRestorePolicy"); 1565 return; 1566 } 1567 1568 powerRestorPolicy = policyMapsIt->second; 1569 1570 crow::connections::systemBus->async_method_call( 1571 [aResp](const boost::system::error_code ec) { 1572 if (ec) 1573 { 1574 messages::internalError(aResp->res); 1575 return; 1576 } 1577 }, 1578 "xyz.openbmc_project.Settings", 1579 "/xyz/openbmc_project/control/host0/power_restore_policy", 1580 "org.freedesktop.DBus.Properties", "Set", 1581 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1582 std::variant<std::string>(powerRestorPolicy)); 1583 } 1584 1585 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1586 /** 1587 * @brief Retrieves provisioning status 1588 * 1589 * @param[in] aResp Shared pointer for completing asynchronous calls. 1590 * 1591 * @return None. 1592 */ 1593 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1594 { 1595 BMCWEB_LOG_DEBUG << "Get OEM information."; 1596 crow::connections::systemBus->async_method_call( 1597 [aResp](const boost::system::error_code ec, 1598 const std::vector<std::pair<std::string, VariantType>>& 1599 propertiesList) { 1600 nlohmann::json& oemPFR = 1601 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1602 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1603 "#OemComputerSystem.OpenBmc"; 1604 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1605 1606 if (ec) 1607 { 1608 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1609 // not an error, don't have to have the interface 1610 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1611 return; 1612 } 1613 1614 const bool* provState = nullptr; 1615 const bool* lockState = nullptr; 1616 for (const std::pair<std::string, VariantType>& property : 1617 propertiesList) 1618 { 1619 if (property.first == "UfmProvisioned") 1620 { 1621 provState = std::get_if<bool>(&property.second); 1622 } 1623 else if (property.first == "UfmLocked") 1624 { 1625 lockState = std::get_if<bool>(&property.second); 1626 } 1627 } 1628 1629 if ((provState == nullptr) || (lockState == nullptr)) 1630 { 1631 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1632 messages::internalError(aResp->res); 1633 return; 1634 } 1635 1636 if (*provState == true) 1637 { 1638 if (*lockState == true) 1639 { 1640 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1641 } 1642 else 1643 { 1644 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1645 } 1646 } 1647 else 1648 { 1649 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1650 } 1651 }, 1652 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1653 "org.freedesktop.DBus.Properties", "GetAll", 1654 "xyz.openbmc_project.PFR.Attributes"); 1655 } 1656 #endif 1657 1658 /** 1659 * @brief Translates watchdog timeout action DBUS property value to redfish. 1660 * 1661 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1662 * 1663 * @return Returns as a string, the timeout action in Redfish terms. If 1664 * translation cannot be done, returns an empty string. 1665 */ 1666 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 1667 { 1668 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1669 { 1670 return "None"; 1671 } 1672 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1673 { 1674 return "ResetSystem"; 1675 } 1676 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1677 { 1678 return "PowerDown"; 1679 } 1680 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1681 { 1682 return "PowerCycle"; 1683 } 1684 1685 return ""; 1686 } 1687 1688 /** 1689 *@brief Translates timeout action from Redfish to DBUS property value. 1690 * 1691 *@param[in] rfAction The timeout action in Redfish. 1692 * 1693 *@return Returns as a string, the time_out action as expected by DBUS. 1694 *If translation cannot be done, returns an empty string. 1695 */ 1696 1697 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 1698 { 1699 if (rfAction == "None") 1700 { 1701 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1702 } 1703 if (rfAction == "PowerCycle") 1704 { 1705 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1706 } 1707 if (rfAction == "PowerDown") 1708 { 1709 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1710 } 1711 if (rfAction == "ResetSystem") 1712 { 1713 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1714 } 1715 1716 return ""; 1717 } 1718 1719 /** 1720 * @brief Retrieves host watchdog timer properties over DBUS 1721 * 1722 * @param[in] aResp Shared pointer for completing asynchronous calls. 1723 * 1724 * @return None. 1725 */ 1726 inline void getHostWatchdogTimer(const std::shared_ptr<AsyncResp>& aResp) 1727 { 1728 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1729 crow::connections::systemBus->async_method_call( 1730 [aResp](const boost::system::error_code ec, 1731 PropertiesType& properties) { 1732 if (ec) 1733 { 1734 // watchdog service is stopped 1735 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1736 return; 1737 } 1738 1739 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1740 1741 nlohmann::json& hostWatchdogTimer = 1742 aResp->res.jsonValue["HostWatchdogTimer"]; 1743 1744 // watchdog service is running/enabled 1745 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1746 1747 for (const auto& property : properties) 1748 { 1749 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1750 if (property.first == "Enabled") 1751 { 1752 const bool* state = std::get_if<bool>(&property.second); 1753 1754 if (!state) 1755 { 1756 messages::internalError(aResp->res); 1757 continue; 1758 } 1759 1760 hostWatchdogTimer["FunctionEnabled"] = *state; 1761 } 1762 else if (property.first == "ExpireAction") 1763 { 1764 const std::string* s = 1765 std::get_if<std::string>(&property.second); 1766 if (!s) 1767 { 1768 messages::internalError(aResp->res); 1769 continue; 1770 } 1771 1772 std::string action = dbusToRfWatchdogAction(*s); 1773 if (action.empty()) 1774 { 1775 messages::internalError(aResp->res); 1776 continue; 1777 } 1778 hostWatchdogTimer["TimeoutAction"] = action; 1779 } 1780 } 1781 }, 1782 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1783 "org.freedesktop.DBus.Properties", "GetAll", 1784 "xyz.openbmc_project.State.Watchdog"); 1785 } 1786 1787 /** 1788 * @brief Sets Host WatchDog Timer properties. 1789 * 1790 * @param[in] aResp Shared pointer for generating response message. 1791 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1792 * RF request. 1793 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1794 * 1795 * @return None. 1796 */ 1797 inline void setWDTProperties(const std::shared_ptr<AsyncResp>& aResp, 1798 const std::optional<bool> wdtEnable, 1799 const std::optional<std::string>& wdtTimeOutAction) 1800 { 1801 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1802 1803 if (wdtTimeOutAction) 1804 { 1805 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1806 // check if TimeOut Action is Valid 1807 if (wdtTimeOutActStr.empty()) 1808 { 1809 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1810 << *wdtTimeOutAction; 1811 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1812 "TimeoutAction"); 1813 return; 1814 } 1815 1816 crow::connections::systemBus->async_method_call( 1817 [aResp](const boost::system::error_code ec) { 1818 if (ec) 1819 { 1820 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1821 messages::internalError(aResp->res); 1822 return; 1823 } 1824 }, 1825 "xyz.openbmc_project.Watchdog", 1826 "/xyz/openbmc_project/watchdog/host0", 1827 "org.freedesktop.DBus.Properties", "Set", 1828 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1829 std::variant<std::string>(wdtTimeOutActStr)); 1830 } 1831 1832 if (wdtEnable) 1833 { 1834 crow::connections::systemBus->async_method_call( 1835 [aResp](const boost::system::error_code ec) { 1836 if (ec) 1837 { 1838 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1839 messages::internalError(aResp->res); 1840 return; 1841 } 1842 }, 1843 "xyz.openbmc_project.Watchdog", 1844 "/xyz/openbmc_project/watchdog/host0", 1845 "org.freedesktop.DBus.Properties", "Set", 1846 "xyz.openbmc_project.State.Watchdog", "Enabled", 1847 std::variant<bool>(*wdtEnable)); 1848 } 1849 } 1850 1851 /** 1852 * SystemsCollection derived class for delivering ComputerSystems Collection 1853 * Schema 1854 */ 1855 class SystemsCollection : public Node 1856 { 1857 public: 1858 SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/") 1859 { 1860 entityPrivileges = { 1861 {boost::beast::http::verb::get, {{"Login"}}}, 1862 {boost::beast::http::verb::head, {{"Login"}}}, 1863 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1864 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1865 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1866 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1867 } 1868 1869 private: 1870 void doGet(crow::Response& res, const crow::Request&, 1871 const std::vector<std::string>&) override 1872 { 1873 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1874 res.jsonValue["@odata.type"] = 1875 "#ComputerSystemCollection.ComputerSystemCollection"; 1876 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1877 res.jsonValue["Name"] = "Computer System Collection"; 1878 1879 crow::connections::systemBus->async_method_call( 1880 [asyncResp](const boost::system::error_code ec, 1881 const std::variant<std::string>& /*hostName*/) { 1882 nlohmann::json& ifaceArray = 1883 asyncResp->res.jsonValue["Members"]; 1884 ifaceArray = nlohmann::json::array(); 1885 auto& count = asyncResp->res.jsonValue["Members@odata.count"]; 1886 ifaceArray.push_back( 1887 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1888 count = ifaceArray.size(); 1889 if (!ec) 1890 { 1891 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1892 ifaceArray.push_back( 1893 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1894 count = ifaceArray.size(); 1895 return; 1896 } 1897 }, 1898 "xyz.openbmc_project.Settings", 1899 "/xyz/openbmc_project/network/hypervisor", 1900 "org.freedesktop.DBus.Properties", "Get", 1901 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1902 } 1903 }; 1904 1905 /** 1906 * SystemActionsReset class supports handle POST method for Reset action. 1907 * The class retrieves and sends data directly to D-Bus. 1908 */ 1909 class SystemActionsReset : public Node 1910 { 1911 public: 1912 SystemActionsReset(App& app) : 1913 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1914 { 1915 entityPrivileges = { 1916 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1917 } 1918 1919 private: 1920 /** 1921 * Function handles POST method request. 1922 * Analyzes POST body message before sends Reset request data to D-Bus. 1923 */ 1924 void doPost(crow::Response& res, const crow::Request& req, 1925 const std::vector<std::string>&) override 1926 { 1927 auto asyncResp = std::make_shared<AsyncResp>(res); 1928 1929 std::string resetType; 1930 if (!json_util::readJson(req, res, "ResetType", resetType)) 1931 { 1932 return; 1933 } 1934 1935 // Get the command and host vs. chassis 1936 std::string command; 1937 bool hostCommand; 1938 if ((resetType == "On") || (resetType == "ForceOn")) 1939 { 1940 command = "xyz.openbmc_project.State.Host.Transition.On"; 1941 hostCommand = true; 1942 } 1943 else if (resetType == "ForceOff") 1944 { 1945 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1946 hostCommand = false; 1947 } 1948 else if (resetType == "ForceRestart") 1949 { 1950 command = 1951 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1952 hostCommand = true; 1953 } 1954 else if (resetType == "GracefulShutdown") 1955 { 1956 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1957 hostCommand = true; 1958 } 1959 else if (resetType == "GracefulRestart") 1960 { 1961 command = 1962 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1963 hostCommand = true; 1964 } 1965 else if (resetType == "PowerCycle") 1966 { 1967 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1968 hostCommand = true; 1969 } 1970 else if (resetType == "Nmi") 1971 { 1972 doNMI(asyncResp); 1973 return; 1974 } 1975 else 1976 { 1977 messages::actionParameterUnknown(res, "Reset", resetType); 1978 return; 1979 } 1980 1981 if (hostCommand) 1982 { 1983 crow::connections::systemBus->async_method_call( 1984 [asyncResp, resetType](const boost::system::error_code ec) { 1985 if (ec) 1986 { 1987 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1988 if (ec.value() == boost::asio::error::invalid_argument) 1989 { 1990 messages::actionParameterNotSupported( 1991 asyncResp->res, resetType, "Reset"); 1992 } 1993 else 1994 { 1995 messages::internalError(asyncResp->res); 1996 } 1997 return; 1998 } 1999 messages::success(asyncResp->res); 2000 }, 2001 "xyz.openbmc_project.State.Host", 2002 "/xyz/openbmc_project/state/host0", 2003 "org.freedesktop.DBus.Properties", "Set", 2004 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2005 std::variant<std::string>{command}); 2006 } 2007 else 2008 { 2009 crow::connections::systemBus->async_method_call( 2010 [asyncResp, resetType](const boost::system::error_code ec) { 2011 if (ec) 2012 { 2013 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2014 if (ec.value() == boost::asio::error::invalid_argument) 2015 { 2016 messages::actionParameterNotSupported( 2017 asyncResp->res, resetType, "Reset"); 2018 } 2019 else 2020 { 2021 messages::internalError(asyncResp->res); 2022 } 2023 return; 2024 } 2025 messages::success(asyncResp->res); 2026 }, 2027 "xyz.openbmc_project.State.Chassis", 2028 "/xyz/openbmc_project/state/chassis0", 2029 "org.freedesktop.DBus.Properties", "Set", 2030 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 2031 std::variant<std::string>{command}); 2032 } 2033 } 2034 /** 2035 * Function transceives data with dbus directly. 2036 */ 2037 void doNMI(const std::shared_ptr<AsyncResp>& asyncResp) 2038 { 2039 constexpr char const* serviceName = 2040 "xyz.openbmc_project.Control.Host.NMI"; 2041 constexpr char const* objectPath = 2042 "/xyz/openbmc_project/control/host0/nmi"; 2043 constexpr char const* interfaceName = 2044 "xyz.openbmc_project.Control.Host.NMI"; 2045 constexpr char const* method = "NMI"; 2046 2047 crow::connections::systemBus->async_method_call( 2048 [asyncResp](const boost::system::error_code ec) { 2049 if (ec) 2050 { 2051 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2052 messages::internalError(asyncResp->res); 2053 return; 2054 } 2055 messages::success(asyncResp->res); 2056 }, 2057 serviceName, objectPath, interfaceName, method); 2058 } 2059 }; 2060 2061 /** 2062 * Systems derived class for delivering Computer Systems Schema. 2063 */ 2064 class Systems : public Node 2065 { 2066 public: 2067 /* 2068 * Default Constructor 2069 */ 2070 Systems(App& app) : Node(app, "/redfish/v1/Systems/system/") 2071 { 2072 entityPrivileges = { 2073 {boost::beast::http::verb::get, {{"Login"}}}, 2074 {boost::beast::http::verb::head, {{"Login"}}}, 2075 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2076 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2077 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2078 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2079 } 2080 2081 private: 2082 /** 2083 * Functions triggers appropriate requests on DBus 2084 */ 2085 void doGet(crow::Response& res, const crow::Request&, 2086 const std::vector<std::string>&) override 2087 { 2088 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_13_0.ComputerSystem"; 2089 res.jsonValue["Name"] = "system"; 2090 res.jsonValue["Id"] = "system"; 2091 res.jsonValue["SystemType"] = "Physical"; 2092 res.jsonValue["Description"] = "Computer System"; 2093 res.jsonValue["ProcessorSummary"]["Count"] = 0; 2094 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 2095 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 2096 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 2097 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 2098 2099 res.jsonValue["Processors"] = { 2100 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2101 res.jsonValue["Memory"] = { 2102 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2103 res.jsonValue["Storage"] = { 2104 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2105 2106 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2107 {"target", 2108 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2109 {"@Redfish.ActionInfo", 2110 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2111 2112 res.jsonValue["LogServices"] = { 2113 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2114 2115 res.jsonValue["Bios"] = { 2116 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2117 2118 res.jsonValue["Links"]["ManagedBy"] = { 2119 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2120 2121 res.jsonValue["Status"] = { 2122 {"Health", "OK"}, 2123 {"State", "Enabled"}, 2124 }; 2125 auto asyncResp = std::make_shared<AsyncResp>(res); 2126 2127 constexpr const std::array<const char*, 4> inventoryForSystems = { 2128 "xyz.openbmc_project.Inventory.Item.Dimm", 2129 "xyz.openbmc_project.Inventory.Item.Cpu", 2130 "xyz.openbmc_project.Inventory.Item.Drive", 2131 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2132 2133 auto health = std::make_shared<HealthPopulate>(asyncResp); 2134 crow::connections::systemBus->async_method_call( 2135 [health](const boost::system::error_code ec, 2136 std::vector<std::string>& resp) { 2137 if (ec) 2138 { 2139 // no inventory 2140 return; 2141 } 2142 2143 health->inventory = std::move(resp); 2144 }, 2145 "xyz.openbmc_project.ObjectMapper", 2146 "/xyz/openbmc_project/object_mapper", 2147 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2148 int32_t(0), inventoryForSystems); 2149 2150 health->populate(); 2151 2152 getMainChassisId(asyncResp, [](const std::string& chassisId, 2153 const std::shared_ptr<AsyncResp>& aRsp) { 2154 aRsp->res.jsonValue["Links"]["Chassis"] = { 2155 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2156 }); 2157 2158 getLocationIndicatorActive(asyncResp); 2159 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2160 getIndicatorLedState(asyncResp); 2161 getComputerSystem(asyncResp, health); 2162 getHostState(asyncResp); 2163 getBootProperties(asyncResp); 2164 getBootProgress(asyncResp); 2165 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2166 getHostWatchdogTimer(asyncResp); 2167 getPowerRestorePolicy(asyncResp); 2168 getAutomaticRetry(asyncResp); 2169 getLastResetTime(asyncResp); 2170 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2171 getProvisioningStatus(asyncResp); 2172 #endif 2173 } 2174 2175 void doPatch(crow::Response& res, const crow::Request& req, 2176 const std::vector<std::string>&) override 2177 { 2178 std::optional<bool> locationIndicatorActive; 2179 std::optional<std::string> indicatorLed; 2180 std::optional<nlohmann::json> bootProps; 2181 std::optional<nlohmann::json> wdtTimerProps; 2182 std::optional<std::string> assetTag; 2183 std::optional<std::string> powerRestorePolicy; 2184 auto asyncResp = std::make_shared<AsyncResp>(res); 2185 2186 if (!json_util::readJson( 2187 req, res, "IndicatorLED", indicatorLed, 2188 "LocationIndicatorActive", locationIndicatorActive, "Boot", 2189 bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy", 2190 powerRestorePolicy, "AssetTag", assetTag)) 2191 { 2192 return; 2193 } 2194 2195 res.result(boost::beast::http::status::no_content); 2196 2197 if (assetTag) 2198 { 2199 setAssetTag(asyncResp, *assetTag); 2200 } 2201 2202 if (wdtTimerProps) 2203 { 2204 std::optional<bool> wdtEnable; 2205 std::optional<std::string> wdtTimeOutAction; 2206 2207 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2208 "FunctionEnabled", wdtEnable, 2209 "TimeoutAction", wdtTimeOutAction)) 2210 { 2211 return; 2212 } 2213 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2214 } 2215 2216 if (bootProps) 2217 { 2218 std::optional<std::string> bootSource; 2219 std::optional<std::string> bootEnable; 2220 std::optional<std::string> automaticRetryConfig; 2221 2222 if (!json_util::readJson( 2223 *bootProps, asyncResp->res, "BootSourceOverrideTarget", 2224 bootSource, "BootSourceOverrideEnabled", bootEnable, 2225 "AutomaticRetryConfig", automaticRetryConfig)) 2226 { 2227 return; 2228 } 2229 if (bootSource || bootEnable) 2230 { 2231 setBootSourceProperties(asyncResp, std::move(bootSource), 2232 std::move(bootEnable)); 2233 } 2234 if (automaticRetryConfig) 2235 { 2236 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2237 } 2238 } 2239 2240 if (locationIndicatorActive) 2241 { 2242 setLocationIndicatorActive(asyncResp, *locationIndicatorActive); 2243 } 2244 2245 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2246 if (indicatorLed) 2247 { 2248 setIndicatorLedState(asyncResp, *indicatorLed); 2249 res.addHeader(boost::beast::http::field::warning, 2250 "299 - \"IndicatorLED is deprecated. Use " 2251 "LocationIndicatorActive instead.\""); 2252 } 2253 2254 if (powerRestorePolicy) 2255 { 2256 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2257 } 2258 } 2259 }; 2260 2261 /** 2262 * SystemResetActionInfo derived class for delivering Computer Systems 2263 * ResetType AllowableValues using ResetInfo schema. 2264 */ 2265 class SystemResetActionInfo : public Node 2266 { 2267 public: 2268 /* 2269 * Default Constructor 2270 */ 2271 SystemResetActionInfo(App& app) : 2272 Node(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2273 { 2274 entityPrivileges = { 2275 {boost::beast::http::verb::get, {{"Login"}}}, 2276 {boost::beast::http::verb::head, {{"Login"}}}, 2277 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2278 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2279 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2280 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2281 } 2282 2283 private: 2284 /** 2285 * Functions triggers appropriate requests on DBus 2286 */ 2287 void doGet(crow::Response& res, const crow::Request&, 2288 const std::vector<std::string>&) override 2289 { 2290 res.jsonValue = { 2291 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2292 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2293 {"Name", "Reset Action Info"}, 2294 {"Id", "ResetActionInfo"}, 2295 {"Parameters", 2296 {{{"Name", "ResetType"}, 2297 {"Required", true}, 2298 {"DataType", "String"}, 2299 {"AllowableValues", 2300 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 2301 "GracefulShutdown", "PowerCycle", "Nmi"}}}}}}; 2302 res.end(); 2303 } 2304 }; 2305 } // namespace redfish 2306