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