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