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 "Quiesced") 620 { 621 aResp->res.jsonValue["PowerState"] = "On"; 622 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 623 } 624 else if (*s == "xyz.openbmc_project.State.Host.HostState." 625 "DiagnosticMode") 626 { 627 aResp->res.jsonValue["PowerState"] = "On"; 628 aResp->res.jsonValue["Status"]["State"] = "InTest"; 629 } 630 else 631 { 632 aResp->res.jsonValue["PowerState"] = "Off"; 633 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 634 } 635 } 636 }, 637 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 638 "org.freedesktop.DBus.Properties", "Get", 639 "xyz.openbmc_project.State.Host", "CurrentHostState"); 640 } 641 642 /** 643 * @brief Traslates boot source DBUS property value to redfish. 644 * 645 * @param[in] dbusSource The boot source in DBUS speak. 646 * 647 * @return Returns as a string, the boot source in Redfish terms. If translation 648 * cannot be done, returns an empty string. 649 */ 650 static std::string dbusToRfBootSource(const std::string &dbusSource) 651 { 652 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 653 { 654 return "None"; 655 } 656 else if (dbusSource == 657 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 658 { 659 return "Hdd"; 660 } 661 else if (dbusSource == 662 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 663 { 664 return "Cd"; 665 } 666 else if (dbusSource == 667 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 668 { 669 return "Pxe"; 670 } 671 else if (dbusSource == 672 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 673 { 674 return "Usb"; 675 } 676 else 677 { 678 return ""; 679 } 680 } 681 682 /** 683 * @brief Traslates boot mode DBUS property value to redfish. 684 * 685 * @param[in] dbusMode The boot mode in DBUS speak. 686 * 687 * @return Returns as a string, the boot mode in Redfish terms. If translation 688 * cannot be done, returns an empty string. 689 */ 690 static std::string dbusToRfBootMode(const std::string &dbusMode) 691 { 692 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 693 { 694 return "None"; 695 } 696 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 697 { 698 return "Diags"; 699 } 700 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 701 { 702 return "BiosSetup"; 703 } 704 else 705 { 706 return ""; 707 } 708 } 709 710 /** 711 * @brief Traslates boot source from Redfish to the DBus boot paths. 712 * 713 * @param[in] rfSource The boot source in Redfish. 714 * @param[out] bootSource The DBus source 715 * @param[out] bootMode the DBus boot mode 716 * 717 * @return Integer error code. 718 */ 719 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp, 720 const std::string &rfSource, 721 std::string &bootSource, std::string &bootMode) 722 { 723 // The caller has initialized the bootSource and bootMode to: 724 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 725 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 726 // Only modify the bootSource/bootMode variable needed to achieve the 727 // desired boot action. 728 729 if (rfSource == "None") 730 { 731 return 0; 732 } 733 else if (rfSource == "Pxe") 734 { 735 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 736 } 737 else if (rfSource == "Hdd") 738 { 739 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 740 } 741 else if (rfSource == "Diags") 742 { 743 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 744 } 745 else if (rfSource == "Cd") 746 { 747 bootSource = 748 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 749 } 750 else if (rfSource == "BiosSetup") 751 { 752 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 753 } 754 else if (rfSource == "Usb") 755 { 756 bootSource = 757 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 758 } 759 else 760 { 761 BMCWEB_LOG_DEBUG << "Invalid property value for " 762 "BootSourceOverrideTarget: " 763 << bootSource; 764 messages::propertyValueNotInList(aResp->res, rfSource, 765 "BootSourceTargetOverride"); 766 return -1; 767 } 768 return 0; 769 } 770 771 /** 772 * @brief Retrieves boot mode over DBUS and fills out the response 773 * 774 * @param[in] aResp Shared pointer for generating response message. 775 * @param[in] bootDbusObj The dbus object to query for boot properties. 776 * 777 * @return None. 778 */ 779 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 780 std::string bootDbusObj) 781 { 782 crow::connections::systemBus->async_method_call( 783 [aResp](const boost::system::error_code ec, 784 const std::variant<std::string> &bootMode) { 785 if (ec) 786 { 787 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 788 messages::internalError(aResp->res); 789 return; 790 } 791 792 const std::string *bootModeStr = 793 std::get_if<std::string>(&bootMode); 794 795 if (!bootModeStr) 796 { 797 messages::internalError(aResp->res); 798 return; 799 } 800 801 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 802 803 // TODO (Santosh): Do we need to support override mode? 804 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 805 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 806 "AllowableValues"] = { 807 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 808 809 if (*bootModeStr != 810 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 811 { 812 auto rfMode = dbusToRfBootMode(*bootModeStr); 813 if (!rfMode.empty()) 814 { 815 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 816 rfMode; 817 } 818 } 819 820 // If the BootSourceOverrideTarget is still "None" at the end, 821 // reset the BootSourceOverrideEnabled to indicate that 822 // overrides are disabled 823 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 824 "None") 825 { 826 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 827 "Disabled"; 828 } 829 }, 830 "xyz.openbmc_project.Settings", bootDbusObj, 831 "org.freedesktop.DBus.Properties", "Get", 832 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 833 } 834 835 /** 836 * @brief Retrieves boot source over DBUS 837 * 838 * @param[in] aResp Shared pointer for generating response message. 839 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 840 * 841 * @return None. 842 */ 843 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 844 { 845 std::string bootDbusObj = 846 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 847 : "/xyz/openbmc_project/control/host0/boot"; 848 849 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 850 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 851 (oneTimeEnabled) ? "Once" : "Continuous"; 852 853 crow::connections::systemBus->async_method_call( 854 [aResp, bootDbusObj](const boost::system::error_code ec, 855 const std::variant<std::string> &bootSource) { 856 if (ec) 857 { 858 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 859 messages::internalError(aResp->res); 860 return; 861 } 862 863 const std::string *bootSourceStr = 864 std::get_if<std::string>(&bootSource); 865 866 if (!bootSourceStr) 867 { 868 messages::internalError(aResp->res); 869 return; 870 } 871 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 872 873 auto rfSource = dbusToRfBootSource(*bootSourceStr); 874 if (!rfSource.empty()) 875 { 876 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 877 rfSource; 878 } 879 }, 880 "xyz.openbmc_project.Settings", bootDbusObj, 881 "org.freedesktop.DBus.Properties", "Get", 882 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 883 getBootMode(std::move(aResp), std::move(bootDbusObj)); 884 } 885 886 /** 887 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 888 * get boot source and boot mode. 889 * 890 * @param[in] aResp Shared pointer for generating response message. 891 * 892 * @return None. 893 */ 894 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 895 { 896 BMCWEB_LOG_DEBUG << "Get boot information."; 897 898 crow::connections::systemBus->async_method_call( 899 [aResp](const boost::system::error_code ec, 900 const sdbusplus::message::variant<bool> &oneTime) { 901 if (ec) 902 { 903 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 904 // not an error, don't have to have the interface 905 return; 906 } 907 908 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 909 910 if (!oneTimePtr) 911 { 912 messages::internalError(aResp->res); 913 return; 914 } 915 getBootSource(aResp, *oneTimePtr); 916 }, 917 "xyz.openbmc_project.Settings", 918 "/xyz/openbmc_project/control/host0/boot/one_time", 919 "org.freedesktop.DBus.Properties", "Get", 920 "xyz.openbmc_project.Object.Enable", "Enabled"); 921 } 922 923 /** 924 * @brief Retrieves power restore policy over DBUS. 925 * 926 * @param[in] aResp Shared pointer for generating response message. 927 * 928 * @return None. 929 */ 930 void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp) 931 { 932 BMCWEB_LOG_DEBUG << "Get power restore policy"; 933 934 crow::connections::systemBus->async_method_call( 935 [aResp](const boost::system::error_code ec, 936 sdbusplus::message::variant<std::string> &policy) { 937 if (ec) 938 { 939 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 940 return; 941 } 942 943 const boost::container::flat_map<std::string, std::string> 944 policyMaps = { 945 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 946 "AlwaysOn", 947 "AlwaysOn"}, 948 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 949 "AlwaysOff", 950 "AlwaysOff"}, 951 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 952 "LastState", 953 "LastState"}}; 954 955 const std::string *policyPtr = std::get_if<std::string>(&policy); 956 957 if (!policyPtr) 958 { 959 messages::internalError(aResp->res); 960 return; 961 } 962 963 auto policyMapsIt = policyMaps.find(*policyPtr); 964 if (policyMapsIt == policyMaps.end()) 965 { 966 messages::internalError(aResp->res); 967 return; 968 } 969 970 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 971 }, 972 "xyz.openbmc_project.Settings", 973 "/xyz/openbmc_project/control/host0/power_restore_policy", 974 "org.freedesktop.DBus.Properties", "Get", 975 "xyz.openbmc_project.Control.Power.RestorePolicy", 976 "PowerRestorePolicy"); 977 } 978 979 /** 980 * @brief Sets boot properties into DBUS object(s). 981 * 982 * @param[in] aResp Shared pointer for generating response message. 983 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 984 * @param[in] bootSource The boot source to set. 985 * @param[in] bootEnable The source override "enable" to set. 986 * 987 * @return Integer error code. 988 */ 989 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 990 bool oneTimeEnabled, 991 std::optional<std::string> bootSource, 992 std::optional<std::string> bootEnable) 993 { 994 std::string bootSourceStr = 995 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 996 std::string bootModeStr = 997 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 998 bool oneTimeSetting = oneTimeEnabled; 999 bool useBootSource = true; 1000 1001 // Validate incoming parameters 1002 if (bootEnable) 1003 { 1004 if (*bootEnable == "Once") 1005 { 1006 oneTimeSetting = true; 1007 } 1008 else if (*bootEnable == "Continuous") 1009 { 1010 oneTimeSetting = false; 1011 } 1012 else if (*bootEnable == "Disabled") 1013 { 1014 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1015 oneTimeSetting = false; 1016 useBootSource = false; 1017 } 1018 else 1019 { 1020 BMCWEB_LOG_DEBUG << "Unsupported value for " 1021 "BootSourceOverrideEnabled: " 1022 << *bootEnable; 1023 messages::propertyValueNotInList(aResp->res, *bootEnable, 1024 "BootSourceOverrideEnabled"); 1025 return; 1026 } 1027 } 1028 1029 if (bootSource && useBootSource) 1030 { 1031 // Source target specified 1032 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1033 // Figure out which DBUS interface and property to use 1034 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1035 bootModeStr)) 1036 { 1037 BMCWEB_LOG_DEBUG 1038 << "Invalid property value for BootSourceOverrideTarget: " 1039 << *bootSource; 1040 messages::propertyValueNotInList(aResp->res, *bootSource, 1041 "BootSourceTargetOverride"); 1042 return; 1043 } 1044 } 1045 1046 // Act on validated parameters 1047 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1048 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1049 const char *bootObj = 1050 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1051 : "/xyz/openbmc_project/control/host0/boot"; 1052 1053 crow::connections::systemBus->async_method_call( 1054 [aResp](const boost::system::error_code ec) { 1055 if (ec) 1056 { 1057 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1058 messages::internalError(aResp->res); 1059 return; 1060 } 1061 BMCWEB_LOG_DEBUG << "Boot source update done."; 1062 }, 1063 "xyz.openbmc_project.Settings", bootObj, 1064 "org.freedesktop.DBus.Properties", "Set", 1065 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1066 std::variant<std::string>(bootSourceStr)); 1067 1068 crow::connections::systemBus->async_method_call( 1069 [aResp](const boost::system::error_code ec) { 1070 if (ec) 1071 { 1072 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1073 messages::internalError(aResp->res); 1074 return; 1075 } 1076 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1077 }, 1078 "xyz.openbmc_project.Settings", bootObj, 1079 "org.freedesktop.DBus.Properties", "Set", 1080 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1081 std::variant<std::string>(bootModeStr)); 1082 1083 crow::connections::systemBus->async_method_call( 1084 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1085 if (ec) 1086 { 1087 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1088 messages::internalError(aResp->res); 1089 return; 1090 } 1091 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1092 }, 1093 "xyz.openbmc_project.Settings", 1094 "/xyz/openbmc_project/control/host0/boot/one_time", 1095 "org.freedesktop.DBus.Properties", "Set", 1096 "xyz.openbmc_project.Object.Enable", "Enabled", 1097 std::variant<bool>(oneTimeSetting)); 1098 } 1099 1100 /** 1101 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1102 * set boot source/boot mode properties. 1103 * 1104 * @param[in] aResp Shared pointer for generating response message. 1105 * @param[in] bootSource The boot source from incoming RF request. 1106 * @param[in] bootEnable The boot override enable from incoming RF request. 1107 * 1108 * @return Integer error code. 1109 */ 1110 static void setBootProperties(std::shared_ptr<AsyncResp> aResp, 1111 std::optional<std::string> bootSource, 1112 std::optional<std::string> bootEnable) 1113 { 1114 BMCWEB_LOG_DEBUG << "Set boot information."; 1115 1116 crow::connections::systemBus->async_method_call( 1117 [aResp, bootSource{std::move(bootSource)}, 1118 bootEnable{std::move(bootEnable)}]( 1119 const boost::system::error_code ec, 1120 const sdbusplus::message::variant<bool> &oneTime) { 1121 if (ec) 1122 { 1123 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1124 messages::internalError(aResp->res); 1125 return; 1126 } 1127 1128 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 1129 1130 if (!oneTimePtr) 1131 { 1132 messages::internalError(aResp->res); 1133 return; 1134 } 1135 1136 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1137 1138 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 1139 std::move(bootEnable)); 1140 }, 1141 "xyz.openbmc_project.Settings", 1142 "/xyz/openbmc_project/control/host0/boot/one_time", 1143 "org.freedesktop.DBus.Properties", "Get", 1144 "xyz.openbmc_project.Object.Enable", "Enabled"); 1145 } 1146 1147 /** 1148 * @brief Sets power restore policy properties. 1149 * 1150 * @param[in] aResp Shared pointer for generating response message. 1151 * @param[in] policy power restore policy properties from request. 1152 * 1153 * @return None. 1154 */ 1155 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp, 1156 std::optional<std::string> policy) 1157 { 1158 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1159 1160 const boost::container::flat_map<std::string, std::string> policyMaps = { 1161 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1162 "AlwaysOn"}, 1163 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1164 "AlwaysOff"}, 1165 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1166 "LastState"}}; 1167 1168 std::string powerRestorPolicy; 1169 1170 auto policyMapsIt = policyMaps.find(*policy); 1171 if (policyMapsIt == policyMaps.end()) 1172 { 1173 messages::internalError(aResp->res); 1174 return; 1175 } 1176 1177 powerRestorPolicy = policyMapsIt->second; 1178 1179 crow::connections::systemBus->async_method_call( 1180 [aResp](const boost::system::error_code ec) { 1181 if (ec) 1182 { 1183 messages::internalError(aResp->res); 1184 return; 1185 } 1186 }, 1187 "xyz.openbmc_project.Settings", 1188 "/xyz/openbmc_project/control/host0/power_restore_policy", 1189 "org.freedesktop.DBus.Properties", "Set", 1190 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1191 std::variant<std::string>(powerRestorPolicy)); 1192 } 1193 1194 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1195 /** 1196 * @brief Retrieves provisioning status 1197 * 1198 * @param[in] aResp Shared pointer for completing asynchronous calls. 1199 * 1200 * @return None. 1201 */ 1202 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1203 { 1204 BMCWEB_LOG_DEBUG << "Get OEM information."; 1205 crow::connections::systemBus->async_method_call( 1206 [aResp](const boost::system::error_code ec, 1207 const std::vector<std::pair<std::string, VariantType>> 1208 &propertiesList) { 1209 if (ec) 1210 { 1211 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1212 messages::internalError(aResp->res); 1213 return; 1214 } 1215 1216 const bool *provState = nullptr; 1217 const bool *lockState = nullptr; 1218 for (const std::pair<std::string, VariantType> &property : 1219 propertiesList) 1220 { 1221 if (property.first == "UfmProvisioned") 1222 { 1223 provState = std::get_if<bool>(&property.second); 1224 } 1225 else if (property.first == "UfmLocked") 1226 { 1227 lockState = std::get_if<bool>(&property.second); 1228 } 1229 } 1230 1231 if ((provState == nullptr) || (lockState == nullptr)) 1232 { 1233 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1234 messages::internalError(aResp->res); 1235 return; 1236 } 1237 1238 nlohmann::json &oemPFR = 1239 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1240 if (*provState == true) 1241 { 1242 if (*lockState == true) 1243 { 1244 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1245 } 1246 else 1247 { 1248 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1249 } 1250 } 1251 else 1252 { 1253 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1254 } 1255 }, 1256 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1257 "org.freedesktop.DBus.Properties", "GetAll", 1258 "xyz.openbmc_project.PFR.Attributes"); 1259 } 1260 #endif 1261 1262 /** 1263 * @brief Translates watchdog timeout action DBUS property value to redfish. 1264 * 1265 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1266 * 1267 * @return Returns as a string, the timeout action in Redfish terms. If 1268 * translation cannot be done, returns an empty string. 1269 */ 1270 static std::string dbusToRfWatchdogAction(const std::string &dbusAction) 1271 { 1272 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1273 { 1274 return "None"; 1275 } 1276 else if (dbusAction == 1277 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1278 { 1279 return "ResetSystem"; 1280 } 1281 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1282 { 1283 return "PowerDown"; 1284 } 1285 else if (dbusAction == 1286 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1287 { 1288 return "PowerCycle"; 1289 } 1290 1291 return ""; 1292 } 1293 1294 /** 1295 *@brief Translates timeout action from Redfish to DBUS property value. 1296 * 1297 *@param[in] rfAction The timeout action in Redfish. 1298 * 1299 *@return Returns as a string, the time_out action as expected by DBUS. 1300 *If translation cannot be done, returns an empty string. 1301 */ 1302 1303 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction) 1304 { 1305 if (rfAction == "None") 1306 { 1307 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1308 } 1309 else if (rfAction == "PowerCycle") 1310 { 1311 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1312 } 1313 else if (rfAction == "PowerDown") 1314 { 1315 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1316 } 1317 else if (rfAction == "ResetSystem") 1318 { 1319 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1320 } 1321 1322 return ""; 1323 } 1324 1325 /** 1326 * @brief Retrieves host watchdog timer properties over DBUS 1327 * 1328 * @param[in] aResp Shared pointer for completing asynchronous calls. 1329 * 1330 * @return None. 1331 */ 1332 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1333 { 1334 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1335 crow::connections::systemBus->async_method_call( 1336 [aResp](const boost::system::error_code ec, 1337 PropertiesType &properties) { 1338 if (ec) 1339 { 1340 // watchdog service is stopped 1341 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1342 return; 1343 } 1344 1345 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1346 1347 nlohmann::json &hostWatchdogTimer = 1348 aResp->res.jsonValue["HostWatchdogTimer"]; 1349 1350 // watchdog service is running/enabled 1351 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1352 1353 for (const auto &property : properties) 1354 { 1355 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1356 if (property.first == "Enabled") 1357 { 1358 const bool *state = std::get_if<bool>(&property.second); 1359 1360 if (!state) 1361 { 1362 messages::internalError(aResp->res); 1363 continue; 1364 } 1365 1366 hostWatchdogTimer["FunctionEnabled"] = *state; 1367 } 1368 else if (property.first == "ExpireAction") 1369 { 1370 const std::string *s = 1371 std::get_if<std::string>(&property.second); 1372 if (!s) 1373 { 1374 messages::internalError(aResp->res); 1375 continue; 1376 } 1377 1378 std::string action = dbusToRfWatchdogAction(*s); 1379 if (action.empty()) 1380 { 1381 messages::internalError(aResp->res); 1382 continue; 1383 } 1384 hostWatchdogTimer["TimeoutAction"] = action; 1385 } 1386 } 1387 }, 1388 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1389 "org.freedesktop.DBus.Properties", "GetAll", 1390 "xyz.openbmc_project.State.Watchdog"); 1391 } 1392 1393 /** 1394 * @brief Sets Host WatchDog Timer properties. 1395 * 1396 * @param[in] aResp Shared pointer for generating response message. 1397 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1398 * RF request. 1399 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1400 * 1401 * @return None. 1402 */ 1403 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1404 const std::optional<bool> wdtEnable, 1405 const std::optional<std::string> &wdtTimeOutAction) 1406 { 1407 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1408 1409 if (wdtTimeOutAction) 1410 { 1411 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1412 // check if TimeOut Action is Valid 1413 if (wdtTimeOutActStr.empty()) 1414 { 1415 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1416 << *wdtTimeOutAction; 1417 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1418 "TimeoutAction"); 1419 return; 1420 } 1421 1422 crow::connections::systemBus->async_method_call( 1423 [aResp](const boost::system::error_code ec) { 1424 if (ec) 1425 { 1426 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1427 messages::internalError(aResp->res); 1428 return; 1429 } 1430 }, 1431 "xyz.openbmc_project.Watchdog", 1432 "/xyz/openbmc_project/watchdog/host0", 1433 "org.freedesktop.DBus.Properties", "Set", 1434 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1435 std::variant<std::string>(wdtTimeOutActStr)); 1436 } 1437 1438 if (wdtEnable) 1439 { 1440 crow::connections::systemBus->async_method_call( 1441 [aResp](const boost::system::error_code ec) { 1442 if (ec) 1443 { 1444 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1445 messages::internalError(aResp->res); 1446 return; 1447 } 1448 }, 1449 "xyz.openbmc_project.Watchdog", 1450 "/xyz/openbmc_project/watchdog/host0", 1451 "org.freedesktop.DBus.Properties", "Set", 1452 "xyz.openbmc_project.State.Watchdog", "Enabled", 1453 std::variant<bool>(*wdtEnable)); 1454 } 1455 } 1456 1457 /** 1458 * SystemsCollection derived class for delivering ComputerSystems Collection 1459 * Schema 1460 */ 1461 class SystemsCollection : public Node 1462 { 1463 public: 1464 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 1465 { 1466 entityPrivileges = { 1467 {boost::beast::http::verb::get, {{"Login"}}}, 1468 {boost::beast::http::verb::head, {{"Login"}}}, 1469 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1470 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1471 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1472 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1473 } 1474 1475 private: 1476 void doGet(crow::Response &res, const crow::Request &req, 1477 const std::vector<std::string> ¶ms) override 1478 { 1479 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1480 res.jsonValue["@odata.type"] = 1481 "#ComputerSystemCollection.ComputerSystemCollection"; 1482 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1483 res.jsonValue["Name"] = "Computer System Collection"; 1484 1485 crow::connections::systemBus->async_method_call( 1486 [asyncResp](const boost::system::error_code ec, 1487 const std::variant<std::string> &hostName) { 1488 nlohmann::json &iface_array = 1489 asyncResp->res.jsonValue["Members"]; 1490 iface_array = nlohmann::json::array(); 1491 auto &count = asyncResp->res.jsonValue["Members@odata.count"]; 1492 count = 0; 1493 if (ec) 1494 { 1495 iface_array.push_back( 1496 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1497 count = iface_array.size(); 1498 return; 1499 } 1500 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1501 iface_array.push_back( 1502 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1503 iface_array.push_back( 1504 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1505 count = iface_array.size(); 1506 }, 1507 "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi", 1508 "org.freedesktop.DBus.Properties", "Get", 1509 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1510 } 1511 }; 1512 1513 /** 1514 * SystemActionsReset class supports handle POST method for Reset action. 1515 * The class retrieves and sends data directly to D-Bus. 1516 */ 1517 class SystemActionsReset : public Node 1518 { 1519 public: 1520 SystemActionsReset(CrowApp &app) : 1521 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1522 { 1523 entityPrivileges = { 1524 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1525 } 1526 1527 private: 1528 /** 1529 * Function handles POST method request. 1530 * Analyzes POST body message before sends Reset request data to D-Bus. 1531 */ 1532 void doPost(crow::Response &res, const crow::Request &req, 1533 const std::vector<std::string> ¶ms) override 1534 { 1535 auto asyncResp = std::make_shared<AsyncResp>(res); 1536 1537 std::string resetType; 1538 if (!json_util::readJson(req, res, "ResetType", resetType)) 1539 { 1540 return; 1541 } 1542 1543 // Get the command and host vs. chassis 1544 std::string command; 1545 bool hostCommand; 1546 if (resetType == "On") 1547 { 1548 command = "xyz.openbmc_project.State.Host.Transition.On"; 1549 hostCommand = true; 1550 } 1551 else if (resetType == "ForceOff") 1552 { 1553 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1554 hostCommand = false; 1555 } 1556 else if (resetType == "ForceOn") 1557 { 1558 command = "xyz.openbmc_project.State.Host.Transition.On"; 1559 hostCommand = true; 1560 } 1561 else if (resetType == "ForceRestart") 1562 { 1563 command = 1564 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1565 hostCommand = true; 1566 } 1567 else if (resetType == "GracefulShutdown") 1568 { 1569 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1570 hostCommand = true; 1571 } 1572 else if (resetType == "GracefulRestart") 1573 { 1574 command = 1575 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1576 hostCommand = true; 1577 } 1578 else if (resetType == "PowerCycle") 1579 { 1580 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1581 hostCommand = true; 1582 } 1583 else if (resetType == "Nmi") 1584 { 1585 doNMI(asyncResp); 1586 return; 1587 } 1588 else 1589 { 1590 messages::actionParameterUnknown(res, "Reset", resetType); 1591 return; 1592 } 1593 1594 if (hostCommand) 1595 { 1596 crow::connections::systemBus->async_method_call( 1597 [asyncResp, resetType](const boost::system::error_code ec) { 1598 if (ec) 1599 { 1600 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1601 if (ec.value() == boost::asio::error::invalid_argument) 1602 { 1603 messages::actionParameterNotSupported( 1604 asyncResp->res, resetType, "Reset"); 1605 } 1606 else 1607 { 1608 messages::internalError(asyncResp->res); 1609 } 1610 return; 1611 } 1612 messages::success(asyncResp->res); 1613 }, 1614 "xyz.openbmc_project.State.Host", 1615 "/xyz/openbmc_project/state/host0", 1616 "org.freedesktop.DBus.Properties", "Set", 1617 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1618 std::variant<std::string>{command}); 1619 } 1620 else 1621 { 1622 crow::connections::systemBus->async_method_call( 1623 [asyncResp, resetType](const boost::system::error_code ec) { 1624 if (ec) 1625 { 1626 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1627 if (ec.value() == boost::asio::error::invalid_argument) 1628 { 1629 messages::actionParameterNotSupported( 1630 asyncResp->res, resetType, "Reset"); 1631 } 1632 else 1633 { 1634 messages::internalError(asyncResp->res); 1635 } 1636 return; 1637 } 1638 messages::success(asyncResp->res); 1639 }, 1640 "xyz.openbmc_project.State.Chassis", 1641 "/xyz/openbmc_project/state/chassis0", 1642 "org.freedesktop.DBus.Properties", "Set", 1643 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1644 std::variant<std::string>{command}); 1645 } 1646 } 1647 /** 1648 * Function transceives data with dbus directly. 1649 */ 1650 void doNMI(const std::shared_ptr<AsyncResp> &asyncResp) 1651 { 1652 constexpr char const *serviceName = 1653 "xyz.openbmc_project.Control.Host.NMI"; 1654 constexpr char const *objectPath = 1655 "/xyz/openbmc_project/control/host0/nmi"; 1656 constexpr char const *interfaceName = 1657 "xyz.openbmc_project.Control.Host.NMI"; 1658 constexpr char const *method = "NMI"; 1659 1660 crow::connections::systemBus->async_method_call( 1661 [asyncResp](const boost::system::error_code ec) { 1662 if (ec) 1663 { 1664 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 1665 messages::internalError(asyncResp->res); 1666 return; 1667 } 1668 messages::success(asyncResp->res); 1669 }, 1670 serviceName, objectPath, interfaceName, method); 1671 } 1672 }; 1673 1674 /** 1675 * Systems derived class for delivering Computer Systems Schema. 1676 */ 1677 class Systems : public Node 1678 { 1679 public: 1680 /* 1681 * Default Constructor 1682 */ 1683 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1684 { 1685 entityPrivileges = { 1686 {boost::beast::http::verb::get, {{"Login"}}}, 1687 {boost::beast::http::verb::head, {{"Login"}}}, 1688 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1689 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1690 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1691 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1692 } 1693 1694 private: 1695 /** 1696 * Functions triggers appropriate requests on DBus 1697 */ 1698 void doGet(crow::Response &res, const crow::Request &req, 1699 const std::vector<std::string> ¶ms) override 1700 { 1701 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1702 res.jsonValue["Name"] = "system"; 1703 res.jsonValue["Id"] = "system"; 1704 res.jsonValue["SystemType"] = "Physical"; 1705 res.jsonValue["Description"] = "Computer System"; 1706 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1707 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1708 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 1709 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1710 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1711 1712 res.jsonValue["Processors"] = { 1713 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1714 res.jsonValue["Memory"] = { 1715 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1716 res.jsonValue["Storage"] = { 1717 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 1718 1719 // TODO Need to support ForceRestart. 1720 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1721 {"target", 1722 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1723 {"ResetType@Redfish.AllowableValues", 1724 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1725 "GracefulShutdown", "PowerCycle", "Nmi"}}}; 1726 1727 res.jsonValue["LogServices"] = { 1728 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1729 1730 res.jsonValue["Bios"] = { 1731 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1732 1733 res.jsonValue["Links"]["ManagedBy"] = { 1734 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1735 1736 res.jsonValue["Status"] = { 1737 {"Health", "OK"}, 1738 {"State", "Enabled"}, 1739 }; 1740 auto asyncResp = std::make_shared<AsyncResp>(res); 1741 1742 constexpr const std::array<const char *, 4> inventoryForSystems = { 1743 "xyz.openbmc_project.Inventory.Item.Dimm", 1744 "xyz.openbmc_project.Inventory.Item.Cpu", 1745 "xyz.openbmc_project.Inventory.Item.Drive", 1746 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1747 1748 auto health = std::make_shared<HealthPopulate>(asyncResp); 1749 crow::connections::systemBus->async_method_call( 1750 [health](const boost::system::error_code ec, 1751 std::vector<std::string> &resp) { 1752 if (ec) 1753 { 1754 // no inventory 1755 return; 1756 } 1757 1758 health->inventory = std::move(resp); 1759 }, 1760 "xyz.openbmc_project.ObjectMapper", 1761 "/xyz/openbmc_project/object_mapper", 1762 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1763 int32_t(0), inventoryForSystems); 1764 1765 health->populate(); 1766 1767 getMainChassisId(asyncResp, [](const std::string &chassisId, 1768 std::shared_ptr<AsyncResp> aRsp) { 1769 aRsp->res.jsonValue["Links"]["Chassis"] = { 1770 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1771 }); 1772 1773 getIndicatorLedState(asyncResp); 1774 getComputerSystem(asyncResp, health); 1775 getHostState(asyncResp); 1776 getBootProperties(asyncResp); 1777 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1778 getHostWatchdogTimer(asyncResp); 1779 getPowerRestorePolicy(asyncResp); 1780 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1781 getProvisioningStatus(asyncResp); 1782 #endif 1783 } 1784 1785 void doPatch(crow::Response &res, const crow::Request &req, 1786 const std::vector<std::string> ¶ms) override 1787 { 1788 std::optional<std::string> indicatorLed; 1789 std::optional<nlohmann::json> bootProps; 1790 std::optional<nlohmann::json> wdtTimerProps; 1791 std::optional<std::string> powerRestorePolicy; 1792 auto asyncResp = std::make_shared<AsyncResp>(res); 1793 1794 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1795 bootProps, "WatchdogTimer", wdtTimerProps, 1796 "PowerRestorePolicy", powerRestorePolicy)) 1797 { 1798 return; 1799 } 1800 1801 res.result(boost::beast::http::status::no_content); 1802 1803 if (wdtTimerProps) 1804 { 1805 std::optional<bool> wdtEnable; 1806 std::optional<std::string> wdtTimeOutAction; 1807 1808 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1809 "FunctionEnabled", wdtEnable, 1810 "TimeoutAction", wdtTimeOutAction)) 1811 { 1812 return; 1813 } 1814 setWDTProperties(asyncResp, std::move(wdtEnable), 1815 std::move(wdtTimeOutAction)); 1816 } 1817 1818 if (bootProps) 1819 { 1820 std::optional<std::string> bootSource; 1821 std::optional<std::string> bootEnable; 1822 1823 if (!json_util::readJson(*bootProps, asyncResp->res, 1824 "BootSourceOverrideTarget", bootSource, 1825 "BootSourceOverrideEnabled", bootEnable)) 1826 { 1827 return; 1828 } 1829 setBootProperties(asyncResp, std::move(bootSource), 1830 std::move(bootEnable)); 1831 } 1832 1833 if (indicatorLed) 1834 { 1835 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 1836 } 1837 1838 if (powerRestorePolicy) 1839 { 1840 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 1841 } 1842 } 1843 }; 1844 } // namespace redfish 1845