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