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