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