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