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 #include <variant> 28 29 namespace redfish 30 { 31 32 /** 33 * @brief Updates the Functional State of DIMMs 34 * 35 * @param[in] aResp Shared pointer for completing asynchronous calls 36 * @param[in] dimmState Dimm's Functional state, true/false 37 * 38 * @return None. 39 */ 40 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp, 41 const std::variant<bool> &dimmState) 42 { 43 const bool *isDimmFunctional = std::get_if<bool>(&dimmState); 44 if (isDimmFunctional == nullptr) 45 { 46 messages::internalError(aResp->res); 47 return; 48 } 49 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 50 51 // Set it as Enabled if atleast one DIMM is functional 52 // Update STATE only if previous State was DISABLED and current Dimm is 53 // ENABLED. 54 nlohmann::json &prevMemSummary = 55 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 56 if (prevMemSummary == "Disabled") 57 { 58 if (*isDimmFunctional == true) 59 { 60 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 61 "Enabled"; 62 } 63 } 64 } 65 66 /* 67 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 68 * 69 * @param[in] aResp Shared pointer for completing asynchronous calls 70 * @param[in] cpuPresenceState CPU present or not 71 * 72 * @return None. 73 */ 74 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp, 75 const std::variant<bool> &cpuPresenceState) 76 { 77 const bool *isCpuPresent = std::get_if<bool>(&cpuPresenceState); 78 79 if (isCpuPresent == nullptr) 80 { 81 messages::internalError(aResp->res); 82 return; 83 } 84 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 85 86 if (*isCpuPresent == true) 87 { 88 nlohmann::json &procCount = 89 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 90 auto procCountPtr = 91 procCount.get_ptr<nlohmann::json::number_integer_t *>(); 92 if (procCountPtr != nullptr) 93 { 94 // shouldn't be possible to be nullptr 95 *procCountPtr += 1; 96 } 97 } 98 } 99 100 /* 101 * @brief Update "ProcessorSummary" "Status" "State" based on 102 * CPU Functional State 103 * 104 * @param[in] aResp Shared pointer for completing asynchronous calls 105 * @param[in] cpuFunctionalState is CPU functional true/false 106 * 107 * @return None. 108 */ 109 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp, 110 const std::variant<bool> &cpuFunctionalState) 111 { 112 const bool *isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 113 114 if (isCpuFunctional == nullptr) 115 { 116 messages::internalError(aResp->res); 117 return; 118 } 119 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 120 121 nlohmann::json &prevProcState = 122 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 123 124 // Set it as Enabled if atleast one CPU is functional 125 // Update STATE only if previous State was Non_Functional and current CPU is 126 // Functional. 127 if (prevProcState == "Disabled") 128 { 129 if (*isCpuFunctional == true) 130 { 131 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 132 "Enabled"; 133 } 134 } 135 } 136 137 /* 138 * @brief Retrieves computer system properties over dbus 139 * 140 * @param[in] aResp Shared pointer for completing asynchronous calls 141 * @param[in] name Computer system name from request 142 * 143 * @return None. 144 */ 145 void getComputerSystem(std::shared_ptr<AsyncResp> aResp, 146 std::shared_ptr<HealthPopulate> systemHealth) 147 { 148 BMCWEB_LOG_DEBUG << "Get available system components."; 149 150 crow::connections::systemBus->async_method_call( 151 [aResp, systemHealth]( 152 const boost::system::error_code ec, 153 const std::vector<std::pair< 154 std::string, 155 std::vector<std::pair<std::string, std::vector<std::string>>>>> 156 &subtree) { 157 if (ec) 158 { 159 BMCWEB_LOG_DEBUG << "DBUS response error"; 160 messages::internalError(aResp->res); 161 return; 162 } 163 // Iterate over all retrieved ObjectPaths. 164 for (const std::pair<std::string, 165 std::vector<std::pair< 166 std::string, std::vector<std::string>>>> 167 &object : subtree) 168 { 169 const std::string &path = object.first; 170 BMCWEB_LOG_DEBUG << "Got path: " << path; 171 const std::vector< 172 std::pair<std::string, std::vector<std::string>>> 173 &connectionNames = object.second; 174 if (connectionNames.size() < 1) 175 { 176 continue; 177 } 178 179 auto memoryHealth = std::make_shared<HealthPopulate>( 180 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 181 182 auto cpuHealth = std::make_shared<HealthPopulate>( 183 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 184 185 systemHealth->children.emplace_back(memoryHealth); 186 systemHealth->children.emplace_back(cpuHealth); 187 188 // This is not system, so check if it's cpu, dimm, UUID or 189 // BiosVer 190 for (const auto &connection : connectionNames) 191 { 192 for (const auto &interfaceName : connection.second) 193 { 194 if (interfaceName == 195 "xyz.openbmc_project.Inventory.Item.Dimm") 196 { 197 BMCWEB_LOG_DEBUG 198 << "Found Dimm, now get its properties."; 199 200 crow::connections::systemBus->async_method_call( 201 [aResp, service{connection.first}, 202 path(std::move(path))]( 203 const boost::system::error_code ec, 204 const std::vector< 205 std::pair<std::string, VariantType>> 206 &properties) { 207 if (ec) 208 { 209 BMCWEB_LOG_ERROR 210 << "DBUS response error " << ec; 211 messages::internalError(aResp->res); 212 return; 213 } 214 BMCWEB_LOG_DEBUG << "Got " 215 << properties.size() 216 << " Dimm properties."; 217 218 if (properties.size() > 0) 219 { 220 for (const std::pair<std::string, 221 VariantType> 222 &property : properties) 223 { 224 if (property.first != 225 "MemorySizeInKB") 226 { 227 continue; 228 } 229 const uint32_t *value = 230 sdbusplus::message::variant_ns:: 231 get_if<uint32_t>( 232 &property.second); 233 if (value == nullptr) 234 { 235 BMCWEB_LOG_DEBUG 236 << "Find incorrect type of " 237 "MemorySize"; 238 continue; 239 } 240 nlohmann::json &totalMemory = 241 aResp->res 242 .jsonValue["MemorySummar" 243 "y"] 244 ["TotalSystemMe" 245 "moryGiB"]; 246 uint64_t *preValue = 247 totalMemory 248 .get_ptr<uint64_t *>(); 249 if (preValue == nullptr) 250 { 251 continue; 252 } 253 aResp->res 254 .jsonValue["MemorySummary"] 255 ["TotalSystemMemoryGi" 256 "B"] = 257 *value / (1024 * 1024) + 258 *preValue; 259 aResp->res 260 .jsonValue["MemorySummary"] 261 ["Status"]["State"] = 262 "Enabled"; 263 } 264 } 265 else 266 { 267 auto getDimmProperties = 268 [aResp]( 269 const boost::system::error_code 270 ec, 271 const std::variant<bool> 272 &dimmState) { 273 if (ec) 274 { 275 BMCWEB_LOG_ERROR 276 << "DBUS response " 277 "error " 278 << ec; 279 return; 280 } 281 updateDimmProperties(aResp, 282 dimmState); 283 }; 284 crow::connections::systemBus 285 ->async_method_call( 286 std::move(getDimmProperties), 287 service, path, 288 "org.freedesktop.DBus." 289 "Properties", 290 "Get", 291 "xyz.openbmc_project.State." 292 "Decorator.OperationalStatus", 293 "Functional"); 294 } 295 }, 296 connection.first, path, 297 "org.freedesktop.DBus.Properties", "GetAll", 298 "xyz.openbmc_project.Inventory.Item.Dimm"); 299 300 memoryHealth->inventory.emplace_back(path); 301 } 302 else if (interfaceName == 303 "xyz.openbmc_project.Inventory.Item.Cpu") 304 { 305 BMCWEB_LOG_DEBUG 306 << "Found Cpu, now get its properties."; 307 308 crow::connections::systemBus->async_method_call( 309 [aResp, service{connection.first}, 310 path(std::move(path))]( 311 const boost::system::error_code ec, 312 const std::vector< 313 std::pair<std::string, VariantType>> 314 &properties) { 315 if (ec) 316 { 317 BMCWEB_LOG_ERROR 318 << "DBUS response error " << ec; 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 for (const auto &property : properties) 329 { 330 if (property.first == 331 "ProcessorFamily") 332 { 333 const std::string *value = 334 sdbusplus::message:: 335 variant_ns::get_if< 336 std::string>( 337 &property.second); 338 if (value != nullptr) 339 { 340 nlohmann::json 341 &procSummary = 342 aResp->res.jsonValue 343 ["ProcessorSumm" 344 "ary"]; 345 nlohmann::json &procCount = 346 procSummary["Count"]; 347 348 auto procCountPtr = 349 procCount.get_ptr< 350 nlohmann::json:: 351 number_integer_t 352 *>(); 353 if (procCountPtr != nullptr) 354 { 355 // shouldn't be possible 356 // to be nullptr 357 *procCountPtr += 1; 358 } 359 procSummary["Status"] 360 ["State"] = 361 "Enabled"; 362 procSummary["Model"] = 363 *value; 364 } 365 } 366 } 367 } 368 else 369 { 370 auto getCpuPresenceState = 371 [aResp]( 372 const boost::system::error_code 373 ec, 374 const std::variant<bool> 375 &cpuPresenceCheck) { 376 if (ec) 377 { 378 BMCWEB_LOG_ERROR 379 << "DBUS response " 380 "error " 381 << ec; 382 return; 383 } 384 modifyCpuPresenceState( 385 aResp, cpuPresenceCheck); 386 }; 387 388 auto getCpuFunctionalState = 389 [aResp]( 390 const boost::system::error_code 391 ec, 392 const std::variant<bool> 393 &cpuFunctionalCheck) { 394 if (ec) 395 { 396 BMCWEB_LOG_ERROR 397 << "DBUS response " 398 "error " 399 << ec; 400 return; 401 } 402 modifyCpuFunctionalState( 403 aResp, cpuFunctionalCheck); 404 }; 405 // Get the Presence of CPU 406 crow::connections::systemBus 407 ->async_method_call( 408 std::move(getCpuPresenceState), 409 service, path, 410 "org.freedesktop.DBus." 411 "Properties", 412 "Get", 413 "xyz.openbmc_project.Inventory." 414 "Item", 415 "Present"); 416 417 // Get the Functional State 418 crow::connections::systemBus 419 ->async_method_call( 420 std::move( 421 getCpuFunctionalState), 422 service, path, 423 "org.freedesktop.DBus." 424 "Properties", 425 "Get", 426 "xyz.openbmc_project.State." 427 "Decorator." 428 "OperationalStatus", 429 "Functional"); 430 431 // Get the MODEL from 432 // xyz.openbmc_project.Inventory.Decorator.Asset 433 // support it later as Model is Empty 434 // currently. 435 } 436 }, 437 connection.first, path, 438 "org.freedesktop.DBus.Properties", "GetAll", 439 "xyz.openbmc_project.Inventory.Item.Cpu"); 440 441 cpuHealth->inventory.emplace_back(path); 442 } 443 else if (interfaceName == 444 "xyz.openbmc_project.Common.UUID") 445 { 446 BMCWEB_LOG_DEBUG 447 << "Found UUID, now get its properties."; 448 crow::connections::systemBus->async_method_call( 449 [aResp](const boost::system::error_code ec, 450 const std::vector< 451 std::pair<std::string, VariantType>> 452 &properties) { 453 if (ec) 454 { 455 BMCWEB_LOG_DEBUG 456 << "DBUS response error " << ec; 457 messages::internalError(aResp->res); 458 return; 459 } 460 BMCWEB_LOG_DEBUG << "Got " 461 << properties.size() 462 << " UUID properties."; 463 for (const std::pair<std::string, 464 VariantType> 465 &property : properties) 466 { 467 if (property.first == "UUID") 468 { 469 const std::string *value = 470 sdbusplus::message::variant_ns:: 471 get_if<std::string>( 472 &property.second); 473 474 if (value != nullptr) 475 { 476 std::string valueStr = *value; 477 if (valueStr.size() == 32) 478 { 479 valueStr.insert(8, 1, '-'); 480 valueStr.insert(13, 1, '-'); 481 valueStr.insert(18, 1, '-'); 482 valueStr.insert(23, 1, '-'); 483 } 484 BMCWEB_LOG_DEBUG << "UUID = " 485 << valueStr; 486 aResp->res.jsonValue["UUID"] = 487 valueStr; 488 } 489 } 490 } 491 }, 492 connection.first, path, 493 "org.freedesktop.DBus.Properties", "GetAll", 494 "xyz.openbmc_project.Common.UUID"); 495 } 496 else if (interfaceName == 497 "xyz.openbmc_project.Inventory.Item.System") 498 { 499 crow::connections::systemBus->async_method_call( 500 [aResp](const boost::system::error_code ec, 501 const std::vector< 502 std::pair<std::string, VariantType>> 503 &propertiesList) { 504 if (ec) 505 { 506 // doesn't have to include this 507 // interface 508 return; 509 } 510 BMCWEB_LOG_DEBUG 511 << "Got " << propertiesList.size() 512 << " properties for system"; 513 for (const std::pair<std::string, 514 VariantType> 515 &property : propertiesList) 516 { 517 const std::string &propertyName = 518 property.first; 519 if ((propertyName == "PartNumber") || 520 (propertyName == "SerialNumber") || 521 (propertyName == "Manufacturer") || 522 (propertyName == "Model")) 523 { 524 const std::string *value = 525 std::get_if<std::string>( 526 &property.second); 527 if (value != nullptr) 528 { 529 aResp->res 530 .jsonValue[propertyName] = 531 *value; 532 } 533 } 534 } 535 536 // Grab the bios version 537 fw_util::getActiveFwVersion( 538 aResp, fw_util::biosPurpose, 539 "BiosVersion"); 540 }, 541 connection.first, path, 542 "org.freedesktop.DBus.Properties", "GetAll", 543 "xyz.openbmc_project.Inventory.Decorator." 544 "Asset"); 545 546 crow::connections::systemBus->async_method_call( 547 [aResp]( 548 const boost::system::error_code ec, 549 const std::variant<std::string> &property) { 550 if (ec) 551 { 552 // doesn't have to include this 553 // interface 554 return; 555 } 556 557 const std::string *value = 558 std::get_if<std::string>(&property); 559 if (value != nullptr) 560 { 561 aResp->res.jsonValue["AssetTag"] = 562 *value; 563 } 564 }, 565 connection.first, path, 566 "org.freedesktop.DBus.Properties", "Get", 567 "xyz.openbmc_project.Inventory.Decorator." 568 "AssetTag", 569 "AssetTag"); 570 } 571 } 572 } 573 } 574 }, 575 "xyz.openbmc_project.ObjectMapper", 576 "/xyz/openbmc_project/object_mapper", 577 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 578 "/xyz/openbmc_project/inventory", int32_t(0), 579 std::array<const char *, 5>{ 580 "xyz.openbmc_project.Inventory.Decorator.Asset", 581 "xyz.openbmc_project.Inventory.Item.Cpu", 582 "xyz.openbmc_project.Inventory.Item.Dimm", 583 "xyz.openbmc_project.Inventory.Item.System", 584 "xyz.openbmc_project.Common.UUID", 585 }); 586 } 587 588 /** 589 * @brief Retrieves host state properties over dbus 590 * 591 * @param[in] aResp Shared pointer for completing asynchronous calls. 592 * 593 * @return None. 594 */ 595 void getHostState(std::shared_ptr<AsyncResp> aResp) 596 { 597 BMCWEB_LOG_DEBUG << "Get host information."; 598 crow::connections::systemBus->async_method_call( 599 [aResp](const boost::system::error_code ec, 600 const std::variant<std::string> &hostState) { 601 if (ec) 602 { 603 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 604 messages::internalError(aResp->res); 605 return; 606 } 607 608 const std::string *s = std::get_if<std::string>(&hostState); 609 BMCWEB_LOG_DEBUG << "Host state: " << *s; 610 if (s != nullptr) 611 { 612 // Verify Host State 613 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 614 { 615 aResp->res.jsonValue["PowerState"] = "On"; 616 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 617 } 618 else if (*s == "xyz.openbmc_project.State.Host.HostState." 619 "DiagnosticMode") 620 { 621 aResp->res.jsonValue["PowerState"] = "On"; 622 aResp->res.jsonValue["Status"]["State"] = "InTest"; 623 } 624 else 625 { 626 aResp->res.jsonValue["PowerState"] = "Off"; 627 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 628 } 629 } 630 }, 631 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 632 "org.freedesktop.DBus.Properties", "Get", 633 "xyz.openbmc_project.State.Host", "CurrentHostState"); 634 } 635 636 /** 637 * @brief Traslates boot source DBUS property value to redfish. 638 * 639 * @param[in] dbusSource The boot source in DBUS speak. 640 * 641 * @return Returns as a string, the boot source in Redfish terms. If translation 642 * cannot be done, returns an empty string. 643 */ 644 static std::string dbusToRfBootSource(const std::string &dbusSource) 645 { 646 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 647 { 648 return "None"; 649 } 650 else if (dbusSource == 651 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 652 { 653 return "Hdd"; 654 } 655 else if (dbusSource == 656 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 657 { 658 return "Cd"; 659 } 660 else if (dbusSource == 661 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 662 { 663 return "Pxe"; 664 } 665 else if (dbusSource == 666 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 667 { 668 return "Usb"; 669 } 670 else 671 { 672 return ""; 673 } 674 } 675 676 /** 677 * @brief Traslates boot mode DBUS property value to redfish. 678 * 679 * @param[in] dbusMode The boot mode in DBUS speak. 680 * 681 * @return Returns as a string, the boot mode in Redfish terms. If translation 682 * cannot be done, returns an empty string. 683 */ 684 static std::string dbusToRfBootMode(const std::string &dbusMode) 685 { 686 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 687 { 688 return "None"; 689 } 690 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 691 { 692 return "Diags"; 693 } 694 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 695 { 696 return "BiosSetup"; 697 } 698 else 699 { 700 return ""; 701 } 702 } 703 704 /** 705 * @brief Traslates boot source from Redfish to the DBus boot paths. 706 * 707 * @param[in] rfSource The boot source in Redfish. 708 * @param[out] bootSource The DBus source 709 * @param[out] bootMode the DBus boot mode 710 * 711 * @return Integer error code. 712 */ 713 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp, 714 const std::string &rfSource, 715 std::string &bootSource, std::string &bootMode) 716 { 717 // The caller has initialized the bootSource and bootMode to: 718 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 719 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 720 // Only modify the bootSource/bootMode variable needed to achieve the 721 // desired boot action. 722 723 if (rfSource == "None") 724 { 725 return 0; 726 } 727 else if (rfSource == "Pxe") 728 { 729 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 730 } 731 else if (rfSource == "Hdd") 732 { 733 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 734 } 735 else if (rfSource == "Diags") 736 { 737 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 738 } 739 else if (rfSource == "Cd") 740 { 741 bootSource = 742 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 743 } 744 else if (rfSource == "BiosSetup") 745 { 746 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 747 } 748 else if (rfSource == "Usb") 749 { 750 bootSource = 751 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 752 } 753 else 754 { 755 BMCWEB_LOG_DEBUG << "Invalid property value for " 756 "BootSourceOverrideTarget: " 757 << bootSource; 758 messages::propertyValueNotInList(aResp->res, rfSource, 759 "BootSourceTargetOverride"); 760 return -1; 761 } 762 return 0; 763 } 764 765 /** 766 * @brief Retrieves boot mode over DBUS and fills out the response 767 * 768 * @param[in] aResp Shared pointer for generating response message. 769 * @param[in] bootDbusObj The dbus object to query for boot properties. 770 * 771 * @return None. 772 */ 773 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 774 std::string bootDbusObj) 775 { 776 crow::connections::systemBus->async_method_call( 777 [aResp](const boost::system::error_code ec, 778 const std::variant<std::string> &bootMode) { 779 if (ec) 780 { 781 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 782 messages::internalError(aResp->res); 783 return; 784 } 785 786 const std::string *bootModeStr = 787 std::get_if<std::string>(&bootMode); 788 789 if (!bootModeStr) 790 { 791 messages::internalError(aResp->res); 792 return; 793 } 794 795 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 796 797 // TODO (Santosh): Do we need to support override mode? 798 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 799 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 800 "AllowableValues"] = { 801 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 802 803 if (*bootModeStr != 804 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 805 { 806 auto rfMode = dbusToRfBootMode(*bootModeStr); 807 if (!rfMode.empty()) 808 { 809 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 810 rfMode; 811 } 812 } 813 814 // If the BootSourceOverrideTarget is still "None" at the end, 815 // reset the BootSourceOverrideEnabled to indicate that 816 // overrides are disabled 817 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 818 "None") 819 { 820 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 821 "Disabled"; 822 } 823 }, 824 "xyz.openbmc_project.Settings", bootDbusObj, 825 "org.freedesktop.DBus.Properties", "Get", 826 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 827 } 828 829 /** 830 * @brief Retrieves boot source over DBUS 831 * 832 * @param[in] aResp Shared pointer for generating response message. 833 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 834 * 835 * @return None. 836 */ 837 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 838 { 839 std::string bootDbusObj = 840 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 841 : "/xyz/openbmc_project/control/host0/boot"; 842 843 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 844 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 845 (oneTimeEnabled) ? "Once" : "Continuous"; 846 847 crow::connections::systemBus->async_method_call( 848 [aResp, bootDbusObj](const boost::system::error_code ec, 849 const std::variant<std::string> &bootSource) { 850 if (ec) 851 { 852 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 853 messages::internalError(aResp->res); 854 return; 855 } 856 857 const std::string *bootSourceStr = 858 std::get_if<std::string>(&bootSource); 859 860 if (!bootSourceStr) 861 { 862 messages::internalError(aResp->res); 863 return; 864 } 865 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 866 867 auto rfSource = dbusToRfBootSource(*bootSourceStr); 868 if (!rfSource.empty()) 869 { 870 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 871 rfSource; 872 } 873 }, 874 "xyz.openbmc_project.Settings", bootDbusObj, 875 "org.freedesktop.DBus.Properties", "Get", 876 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 877 getBootMode(std::move(aResp), std::move(bootDbusObj)); 878 } 879 880 /** 881 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 882 * get boot source and boot mode. 883 * 884 * @param[in] aResp Shared pointer for generating response message. 885 * 886 * @return None. 887 */ 888 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 889 { 890 BMCWEB_LOG_DEBUG << "Get boot information."; 891 892 crow::connections::systemBus->async_method_call( 893 [aResp](const boost::system::error_code ec, 894 const sdbusplus::message::variant<bool> &oneTime) { 895 if (ec) 896 { 897 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 898 // not an error, don't have to have the interface 899 return; 900 } 901 902 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 903 904 if (!oneTimePtr) 905 { 906 messages::internalError(aResp->res); 907 return; 908 } 909 getBootSource(aResp, *oneTimePtr); 910 }, 911 "xyz.openbmc_project.Settings", 912 "/xyz/openbmc_project/control/host0/boot/one_time", 913 "org.freedesktop.DBus.Properties", "Get", 914 "xyz.openbmc_project.Object.Enable", "Enabled"); 915 } 916 917 /** 918 * @brief Retrieves power restore policy over DBUS. 919 * 920 * @param[in] aResp Shared pointer for generating response message. 921 * 922 * @return None. 923 */ 924 void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp) 925 { 926 BMCWEB_LOG_DEBUG << "Get power restore policy"; 927 928 crow::connections::systemBus->async_method_call( 929 [aResp](const boost::system::error_code ec, 930 sdbusplus::message::variant<std::string> &policy) { 931 if (ec) 932 { 933 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 934 return; 935 } 936 937 const boost::container::flat_map<std::string, std::string> 938 policyMaps = { 939 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 940 "AlwaysOn", 941 "AlwaysOn"}, 942 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 943 "AlwaysOff", 944 "AlwaysOff"}, 945 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 946 "LastState", 947 "LastState"}}; 948 949 const std::string *policyPtr = std::get_if<std::string>(&policy); 950 951 if (!policyPtr) 952 { 953 messages::internalError(aResp->res); 954 return; 955 } 956 957 auto policyMapsIt = policyMaps.find(*policyPtr); 958 if (policyMapsIt == policyMaps.end()) 959 { 960 messages::internalError(aResp->res); 961 return; 962 } 963 964 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 965 }, 966 "xyz.openbmc_project.Settings", 967 "/xyz/openbmc_project/control/host0/power_restore_policy", 968 "org.freedesktop.DBus.Properties", "Get", 969 "xyz.openbmc_project.Control.Power.RestorePolicy", 970 "PowerRestorePolicy"); 971 } 972 973 /** 974 * @brief Sets boot properties into DBUS object(s). 975 * 976 * @param[in] aResp Shared pointer for generating response message. 977 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 978 * @param[in] bootSource The boot source to set. 979 * @param[in] bootEnable The source override "enable" to set. 980 * 981 * @return Integer error code. 982 */ 983 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 984 bool oneTimeEnabled, 985 std::optional<std::string> bootSource, 986 std::optional<std::string> bootEnable) 987 { 988 std::string bootSourceStr = 989 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 990 std::string bootModeStr = 991 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 992 bool oneTimeSetting = oneTimeEnabled; 993 bool useBootSource = true; 994 995 // Validate incoming parameters 996 if (bootEnable) 997 { 998 if (*bootEnable == "Once") 999 { 1000 oneTimeSetting = true; 1001 } 1002 else if (*bootEnable == "Continuous") 1003 { 1004 oneTimeSetting = false; 1005 } 1006 else if (*bootEnable == "Disabled") 1007 { 1008 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1009 oneTimeSetting = false; 1010 useBootSource = false; 1011 } 1012 else 1013 { 1014 BMCWEB_LOG_DEBUG << "Unsupported value for " 1015 "BootSourceOverrideEnabled: " 1016 << *bootEnable; 1017 messages::propertyValueNotInList(aResp->res, *bootEnable, 1018 "BootSourceOverrideEnabled"); 1019 return; 1020 } 1021 } 1022 1023 if (bootSource && useBootSource) 1024 { 1025 // Source target specified 1026 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1027 // Figure out which DBUS interface and property to use 1028 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1029 bootModeStr)) 1030 { 1031 BMCWEB_LOG_DEBUG 1032 << "Invalid property value for BootSourceOverrideTarget: " 1033 << *bootSource; 1034 messages::propertyValueNotInList(aResp->res, *bootSource, 1035 "BootSourceTargetOverride"); 1036 return; 1037 } 1038 } 1039 1040 // Act on validated parameters 1041 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1042 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1043 const char *bootObj = 1044 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1045 : "/xyz/openbmc_project/control/host0/boot"; 1046 1047 crow::connections::systemBus->async_method_call( 1048 [aResp](const boost::system::error_code ec) { 1049 if (ec) 1050 { 1051 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1052 messages::internalError(aResp->res); 1053 return; 1054 } 1055 BMCWEB_LOG_DEBUG << "Boot source update done."; 1056 }, 1057 "xyz.openbmc_project.Settings", bootObj, 1058 "org.freedesktop.DBus.Properties", "Set", 1059 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1060 std::variant<std::string>(bootSourceStr)); 1061 1062 crow::connections::systemBus->async_method_call( 1063 [aResp](const boost::system::error_code ec) { 1064 if (ec) 1065 { 1066 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1067 messages::internalError(aResp->res); 1068 return; 1069 } 1070 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1071 }, 1072 "xyz.openbmc_project.Settings", bootObj, 1073 "org.freedesktop.DBus.Properties", "Set", 1074 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1075 std::variant<std::string>(bootModeStr)); 1076 1077 crow::connections::systemBus->async_method_call( 1078 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1079 if (ec) 1080 { 1081 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1082 messages::internalError(aResp->res); 1083 return; 1084 } 1085 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1086 }, 1087 "xyz.openbmc_project.Settings", 1088 "/xyz/openbmc_project/control/host0/boot/one_time", 1089 "org.freedesktop.DBus.Properties", "Set", 1090 "xyz.openbmc_project.Object.Enable", "Enabled", 1091 std::variant<bool>(oneTimeSetting)); 1092 } 1093 1094 /** 1095 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1096 * set boot source/boot mode properties. 1097 * 1098 * @param[in] aResp Shared pointer for generating response message. 1099 * @param[in] bootSource The boot source from incoming RF request. 1100 * @param[in] bootEnable The boot override enable from incoming RF request. 1101 * 1102 * @return Integer error code. 1103 */ 1104 static void setBootProperties(std::shared_ptr<AsyncResp> aResp, 1105 std::optional<std::string> bootSource, 1106 std::optional<std::string> bootEnable) 1107 { 1108 BMCWEB_LOG_DEBUG << "Set boot information."; 1109 1110 crow::connections::systemBus->async_method_call( 1111 [aResp, bootSource{std::move(bootSource)}, 1112 bootEnable{std::move(bootEnable)}]( 1113 const boost::system::error_code ec, 1114 const sdbusplus::message::variant<bool> &oneTime) { 1115 if (ec) 1116 { 1117 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1118 messages::internalError(aResp->res); 1119 return; 1120 } 1121 1122 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 1123 1124 if (!oneTimePtr) 1125 { 1126 messages::internalError(aResp->res); 1127 return; 1128 } 1129 1130 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1131 1132 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 1133 std::move(bootEnable)); 1134 }, 1135 "xyz.openbmc_project.Settings", 1136 "/xyz/openbmc_project/control/host0/boot/one_time", 1137 "org.freedesktop.DBus.Properties", "Get", 1138 "xyz.openbmc_project.Object.Enable", "Enabled"); 1139 } 1140 1141 /** 1142 * @brief Sets power restore policy properties. 1143 * 1144 * @param[in] aResp Shared pointer for generating response message. 1145 * @param[in] policy power restore policy properties from request. 1146 * 1147 * @return None. 1148 */ 1149 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp, 1150 std::optional<std::string> policy) 1151 { 1152 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1153 1154 const boost::container::flat_map<std::string, std::string> policyMaps = { 1155 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1156 "AlwaysOn"}, 1157 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1158 "AlwaysOff"}, 1159 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1160 "LastState"}}; 1161 1162 std::string powerRestorPolicy; 1163 1164 auto policyMapsIt = policyMaps.find(*policy); 1165 if (policyMapsIt == policyMaps.end()) 1166 { 1167 messages::internalError(aResp->res); 1168 return; 1169 } 1170 1171 powerRestorPolicy = policyMapsIt->second; 1172 1173 crow::connections::systemBus->async_method_call( 1174 [aResp](const boost::system::error_code ec) { 1175 if (ec) 1176 { 1177 messages::internalError(aResp->res); 1178 return; 1179 } 1180 }, 1181 "xyz.openbmc_project.Settings", 1182 "/xyz/openbmc_project/control/host0/power_restore_policy", 1183 "org.freedesktop.DBus.Properties", "Set", 1184 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1185 std::variant<std::string>(powerRestorPolicy)); 1186 } 1187 1188 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1189 /** 1190 * @brief Retrieves provisioning status 1191 * 1192 * @param[in] aResp Shared pointer for completing asynchronous calls. 1193 * 1194 * @return None. 1195 */ 1196 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1197 { 1198 BMCWEB_LOG_DEBUG << "Get OEM information."; 1199 crow::connections::systemBus->async_method_call( 1200 [aResp](const boost::system::error_code ec, 1201 const std::vector<std::pair<std::string, VariantType>> 1202 &propertiesList) { 1203 if (ec) 1204 { 1205 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1206 messages::internalError(aResp->res); 1207 return; 1208 } 1209 1210 const bool *provState = nullptr; 1211 const bool *lockState = nullptr; 1212 for (const std::pair<std::string, VariantType> &property : 1213 propertiesList) 1214 { 1215 if (property.first == "UfmProvisioned") 1216 { 1217 provState = std::get_if<bool>(&property.second); 1218 } 1219 else if (property.first == "UfmLocked") 1220 { 1221 lockState = std::get_if<bool>(&property.second); 1222 } 1223 } 1224 1225 if ((provState == nullptr) || (lockState == nullptr)) 1226 { 1227 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1228 messages::internalError(aResp->res); 1229 return; 1230 } 1231 1232 nlohmann::json &oemPFR = 1233 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1234 if (*provState == true) 1235 { 1236 if (*lockState == true) 1237 { 1238 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1239 } 1240 else 1241 { 1242 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1243 } 1244 } 1245 else 1246 { 1247 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1248 } 1249 }, 1250 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1251 "org.freedesktop.DBus.Properties", "GetAll", 1252 "xyz.openbmc_project.PFR.Attributes"); 1253 } 1254 #endif 1255 1256 /** 1257 * @brief Translates watchdog timeout action DBUS property value to redfish. 1258 * 1259 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1260 * 1261 * @return Returns as a string, the timeout action in Redfish terms. If 1262 * translation cannot be done, returns an empty string. 1263 */ 1264 static std::string dbusToRfWatchdogAction(const std::string &dbusAction) 1265 { 1266 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1267 { 1268 return "None"; 1269 } 1270 else if (dbusAction == 1271 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1272 { 1273 return "ResetSystem"; 1274 } 1275 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1276 { 1277 return "PowerDown"; 1278 } 1279 else if (dbusAction == 1280 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1281 { 1282 return "PowerCycle"; 1283 } 1284 1285 return ""; 1286 } 1287 1288 /** 1289 *@brief Translates timeout action from Redfish to DBUS property value. 1290 * 1291 *@param[in] rfAction The timeout action in Redfish. 1292 * 1293 *@return Returns as a string, the time_out action as expected by DBUS. 1294 *If translation cannot be done, returns an empty string. 1295 */ 1296 1297 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction) 1298 { 1299 if (rfAction == "None") 1300 { 1301 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1302 } 1303 else if (rfAction == "PowerCycle") 1304 { 1305 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1306 } 1307 else if (rfAction == "PowerDown") 1308 { 1309 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1310 } 1311 else if (rfAction == "ResetSystem") 1312 { 1313 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1314 } 1315 1316 return ""; 1317 } 1318 1319 /** 1320 * @brief Retrieves host watchdog timer properties over DBUS 1321 * 1322 * @param[in] aResp Shared pointer for completing asynchronous calls. 1323 * 1324 * @return None. 1325 */ 1326 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1327 { 1328 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1329 crow::connections::systemBus->async_method_call( 1330 [aResp](const boost::system::error_code ec, 1331 PropertiesType &properties) { 1332 if (ec) 1333 { 1334 // watchdog service is stopped 1335 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1336 return; 1337 } 1338 1339 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1340 1341 nlohmann::json &hostWatchdogTimer = 1342 aResp->res.jsonValue["HostWatchdogTimer"]; 1343 1344 // watchdog service is running/enabled 1345 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1346 1347 for (const auto &property : properties) 1348 { 1349 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1350 if (property.first == "Enabled") 1351 { 1352 const bool *state = std::get_if<bool>(&property.second); 1353 1354 if (!state) 1355 { 1356 messages::internalError(aResp->res); 1357 continue; 1358 } 1359 1360 hostWatchdogTimer["FunctionEnabled"] = *state; 1361 } 1362 else if (property.first == "ExpireAction") 1363 { 1364 const std::string *s = 1365 std::get_if<std::string>(&property.second); 1366 if (!s) 1367 { 1368 messages::internalError(aResp->res); 1369 continue; 1370 } 1371 1372 std::string action = dbusToRfWatchdogAction(*s); 1373 if (action.empty()) 1374 { 1375 messages::internalError(aResp->res); 1376 continue; 1377 } 1378 hostWatchdogTimer["TimeoutAction"] = action; 1379 } 1380 } 1381 }, 1382 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1383 "org.freedesktop.DBus.Properties", "GetAll", 1384 "xyz.openbmc_project.State.Watchdog"); 1385 } 1386 1387 /** 1388 * @brief Sets Host WatchDog Timer properties. 1389 * 1390 * @param[in] aResp Shared pointer for generating response message. 1391 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1392 * RF request. 1393 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1394 * 1395 * @return None. 1396 */ 1397 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1398 const std::optional<bool> wdtEnable, 1399 const std::optional<std::string> &wdtTimeOutAction) 1400 { 1401 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1402 1403 if (wdtTimeOutAction) 1404 { 1405 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1406 // check if TimeOut Action is Valid 1407 if (wdtTimeOutActStr.empty()) 1408 { 1409 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1410 << *wdtTimeOutAction; 1411 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1412 "TimeoutAction"); 1413 return; 1414 } 1415 1416 crow::connections::systemBus->async_method_call( 1417 [aResp](const boost::system::error_code ec) { 1418 if (ec) 1419 { 1420 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1421 messages::internalError(aResp->res); 1422 return; 1423 } 1424 }, 1425 "xyz.openbmc_project.Watchdog", 1426 "/xyz/openbmc_project/watchdog/host0", 1427 "org.freedesktop.DBus.Properties", "Set", 1428 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1429 std::variant<std::string>(wdtTimeOutActStr)); 1430 } 1431 1432 if (wdtEnable) 1433 { 1434 crow::connections::systemBus->async_method_call( 1435 [aResp](const boost::system::error_code ec) { 1436 if (ec) 1437 { 1438 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1439 messages::internalError(aResp->res); 1440 return; 1441 } 1442 }, 1443 "xyz.openbmc_project.Watchdog", 1444 "/xyz/openbmc_project/watchdog/host0", 1445 "org.freedesktop.DBus.Properties", "Set", 1446 "xyz.openbmc_project.State.Watchdog", "Enabled", 1447 std::variant<bool>(*wdtEnable)); 1448 } 1449 } 1450 1451 /** 1452 * SystemsCollection derived class for delivering ComputerSystems Collection 1453 * Schema 1454 */ 1455 class SystemsCollection : public Node 1456 { 1457 public: 1458 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 1459 { 1460 entityPrivileges = { 1461 {boost::beast::http::verb::get, {{"Login"}}}, 1462 {boost::beast::http::verb::head, {{"Login"}}}, 1463 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1464 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1465 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1466 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1467 } 1468 1469 private: 1470 void doGet(crow::Response &res, const crow::Request &req, 1471 const std::vector<std::string> ¶ms) override 1472 { 1473 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1474 res.jsonValue["@odata.type"] = 1475 "#ComputerSystemCollection.ComputerSystemCollection"; 1476 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1477 res.jsonValue["Name"] = "Computer System Collection"; 1478 1479 crow::connections::systemBus->async_method_call( 1480 [asyncResp](const boost::system::error_code ec, 1481 const std::variant<std::string> &hostName) { 1482 nlohmann::json &iface_array = 1483 asyncResp->res.jsonValue["Members"]; 1484 iface_array = nlohmann::json::array(); 1485 auto &count = asyncResp->res.jsonValue["Members@odata.count"]; 1486 count = 0; 1487 if (ec) 1488 { 1489 iface_array.push_back( 1490 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1491 count = iface_array.size(); 1492 return; 1493 } 1494 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1495 iface_array.push_back( 1496 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1497 iface_array.push_back( 1498 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1499 count = iface_array.size(); 1500 }, 1501 "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi", 1502 "org.freedesktop.DBus.Properties", "Get", 1503 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1504 } 1505 }; 1506 1507 /** 1508 * SystemActionsReset class supports handle POST method for Reset action. 1509 * The class retrieves and sends data directly to D-Bus. 1510 */ 1511 class SystemActionsReset : public Node 1512 { 1513 public: 1514 SystemActionsReset(CrowApp &app) : 1515 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1516 { 1517 entityPrivileges = { 1518 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1519 } 1520 1521 private: 1522 /** 1523 * Function handles POST method request. 1524 * Analyzes POST body message before sends Reset request data to D-Bus. 1525 */ 1526 void doPost(crow::Response &res, const crow::Request &req, 1527 const std::vector<std::string> ¶ms) override 1528 { 1529 auto asyncResp = std::make_shared<AsyncResp>(res); 1530 1531 std::string resetType; 1532 if (!json_util::readJson(req, res, "ResetType", resetType)) 1533 { 1534 return; 1535 } 1536 1537 // Get the command and host vs. chassis 1538 std::string command; 1539 bool hostCommand; 1540 if (resetType == "On") 1541 { 1542 command = "xyz.openbmc_project.State.Host.Transition.On"; 1543 hostCommand = true; 1544 } 1545 else if (resetType == "ForceOff") 1546 { 1547 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1548 hostCommand = false; 1549 } 1550 else if (resetType == "ForceOn") 1551 { 1552 command = "xyz.openbmc_project.State.Host.Transition.On"; 1553 hostCommand = true; 1554 } 1555 else if (resetType == "ForceRestart") 1556 { 1557 command = 1558 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1559 hostCommand = true; 1560 } 1561 else if (resetType == "GracefulShutdown") 1562 { 1563 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1564 hostCommand = true; 1565 } 1566 else if (resetType == "GracefulRestart") 1567 { 1568 command = 1569 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1570 hostCommand = true; 1571 } 1572 else if (resetType == "PowerCycle") 1573 { 1574 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1575 hostCommand = true; 1576 } 1577 else if (resetType == "Nmi") 1578 { 1579 doNMI(asyncResp); 1580 return; 1581 } 1582 else 1583 { 1584 messages::actionParameterUnknown(res, "Reset", resetType); 1585 return; 1586 } 1587 1588 if (hostCommand) 1589 { 1590 crow::connections::systemBus->async_method_call( 1591 [asyncResp, resetType](const boost::system::error_code ec) { 1592 if (ec) 1593 { 1594 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1595 if (ec.value() == boost::asio::error::invalid_argument) 1596 { 1597 messages::actionParameterNotSupported( 1598 asyncResp->res, resetType, "Reset"); 1599 } 1600 else 1601 { 1602 messages::internalError(asyncResp->res); 1603 } 1604 return; 1605 } 1606 messages::success(asyncResp->res); 1607 }, 1608 "xyz.openbmc_project.State.Host", 1609 "/xyz/openbmc_project/state/host0", 1610 "org.freedesktop.DBus.Properties", "Set", 1611 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1612 std::variant<std::string>{command}); 1613 } 1614 else 1615 { 1616 crow::connections::systemBus->async_method_call( 1617 [asyncResp, resetType](const boost::system::error_code ec) { 1618 if (ec) 1619 { 1620 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1621 if (ec.value() == boost::asio::error::invalid_argument) 1622 { 1623 messages::actionParameterNotSupported( 1624 asyncResp->res, resetType, "Reset"); 1625 } 1626 else 1627 { 1628 messages::internalError(asyncResp->res); 1629 } 1630 return; 1631 } 1632 messages::success(asyncResp->res); 1633 }, 1634 "xyz.openbmc_project.State.Chassis", 1635 "/xyz/openbmc_project/state/chassis0", 1636 "org.freedesktop.DBus.Properties", "Set", 1637 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1638 std::variant<std::string>{command}); 1639 } 1640 } 1641 /** 1642 * Function transceives data with dbus directly. 1643 */ 1644 void doNMI(const std::shared_ptr<AsyncResp> &asyncResp) 1645 { 1646 constexpr char const *serviceName = 1647 "xyz.openbmc_project.Control.Host.NMI"; 1648 constexpr char const *objectPath = 1649 "/xyz/openbmc_project/control/host0/nmi"; 1650 constexpr char const *interfaceName = 1651 "xyz.openbmc_project.Control.Host.NMI"; 1652 constexpr char const *method = "NMI"; 1653 1654 crow::connections::systemBus->async_method_call( 1655 [asyncResp](const boost::system::error_code ec) { 1656 if (ec) 1657 { 1658 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 1659 messages::internalError(asyncResp->res); 1660 return; 1661 } 1662 messages::success(asyncResp->res); 1663 }, 1664 serviceName, objectPath, interfaceName, method); 1665 } 1666 }; 1667 1668 /** 1669 * Systems derived class for delivering Computer Systems Schema. 1670 */ 1671 class Systems : public Node 1672 { 1673 public: 1674 /* 1675 * Default Constructor 1676 */ 1677 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1678 { 1679 entityPrivileges = { 1680 {boost::beast::http::verb::get, {{"Login"}}}, 1681 {boost::beast::http::verb::head, {{"Login"}}}, 1682 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1683 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1684 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1685 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1686 } 1687 1688 private: 1689 /** 1690 * Functions triggers appropriate requests on DBus 1691 */ 1692 void doGet(crow::Response &res, const crow::Request &req, 1693 const std::vector<std::string> ¶ms) override 1694 { 1695 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1696 res.jsonValue["Name"] = "system"; 1697 res.jsonValue["Id"] = "system"; 1698 res.jsonValue["SystemType"] = "Physical"; 1699 res.jsonValue["Description"] = "Computer System"; 1700 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1701 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1702 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 1703 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1704 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1705 1706 res.jsonValue["Processors"] = { 1707 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1708 res.jsonValue["Memory"] = { 1709 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1710 res.jsonValue["Storage"] = { 1711 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 1712 1713 // TODO Need to support ForceRestart. 1714 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1715 {"target", 1716 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1717 {"ResetType@Redfish.AllowableValues", 1718 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1719 "GracefulShutdown", "PowerCycle", "Nmi"}}}; 1720 1721 res.jsonValue["LogServices"] = { 1722 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1723 1724 res.jsonValue["Bios"] = { 1725 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1726 1727 res.jsonValue["Links"]["ManagedBy"] = { 1728 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1729 1730 res.jsonValue["Status"] = { 1731 {"Health", "OK"}, 1732 {"State", "Enabled"}, 1733 }; 1734 auto asyncResp = std::make_shared<AsyncResp>(res); 1735 1736 constexpr const std::array<const char *, 4> inventoryForSystems = { 1737 "xyz.openbmc_project.Inventory.Item.Dimm", 1738 "xyz.openbmc_project.Inventory.Item.Cpu", 1739 "xyz.openbmc_project.Inventory.Item.Drive", 1740 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1741 1742 auto health = std::make_shared<HealthPopulate>(asyncResp); 1743 crow::connections::systemBus->async_method_call( 1744 [health](const boost::system::error_code ec, 1745 std::vector<std::string> &resp) { 1746 if (ec) 1747 { 1748 // no inventory 1749 return; 1750 } 1751 1752 health->inventory = std::move(resp); 1753 }, 1754 "xyz.openbmc_project.ObjectMapper", 1755 "/xyz/openbmc_project/object_mapper", 1756 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1757 int32_t(0), inventoryForSystems); 1758 1759 health->populate(); 1760 1761 getMainChassisId(asyncResp, [](const std::string &chassisId, 1762 std::shared_ptr<AsyncResp> aRsp) { 1763 aRsp->res.jsonValue["Links"]["Chassis"] = { 1764 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1765 }); 1766 1767 getIndicatorLedState(asyncResp); 1768 getComputerSystem(asyncResp, health); 1769 getHostState(asyncResp); 1770 getBootProperties(asyncResp); 1771 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1772 getHostWatchdogTimer(asyncResp); 1773 getPowerRestorePolicy(asyncResp); 1774 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1775 getProvisioningStatus(asyncResp); 1776 #endif 1777 } 1778 1779 void doPatch(crow::Response &res, const crow::Request &req, 1780 const std::vector<std::string> ¶ms) override 1781 { 1782 std::optional<std::string> indicatorLed; 1783 std::optional<nlohmann::json> bootProps; 1784 std::optional<nlohmann::json> wdtTimerProps; 1785 std::optional<std::string> powerRestorePolicy; 1786 auto asyncResp = std::make_shared<AsyncResp>(res); 1787 1788 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1789 bootProps, "WatchdogTimer", wdtTimerProps, 1790 "PowerRestorePolicy", powerRestorePolicy)) 1791 { 1792 return; 1793 } 1794 1795 res.result(boost::beast::http::status::no_content); 1796 1797 if (wdtTimerProps) 1798 { 1799 std::optional<bool> wdtEnable; 1800 std::optional<std::string> wdtTimeOutAction; 1801 1802 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1803 "FunctionEnabled", wdtEnable, 1804 "TimeoutAction", wdtTimeOutAction)) 1805 { 1806 return; 1807 } 1808 setWDTProperties(asyncResp, std::move(wdtEnable), 1809 std::move(wdtTimeOutAction)); 1810 } 1811 1812 if (bootProps) 1813 { 1814 std::optional<std::string> bootSource; 1815 std::optional<std::string> bootEnable; 1816 1817 if (!json_util::readJson(*bootProps, asyncResp->res, 1818 "BootSourceOverrideTarget", bootSource, 1819 "BootSourceOverrideEnabled", bootEnable)) 1820 { 1821 return; 1822 } 1823 setBootProperties(asyncResp, std::move(bootSource), 1824 std::move(bootEnable)); 1825 } 1826 1827 if (indicatorLed) 1828 { 1829 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 1830 } 1831 1832 if (powerRestorePolicy) 1833 { 1834 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 1835 } 1836 } 1837 }; 1838 } // namespace redfish 1839