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