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