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