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 at least 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 at least 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 Translates 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 Translates 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 Translates 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 the Last Reset Time 923 * 924 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 925 * and power off. Even though this is the "system" Redfish object look at the 926 * chassis D-Bus interface for the LastStateChangeTime since this has the 927 * last power operation time. 928 * 929 * @param[in] aResp Shared pointer for generating response message. 930 * 931 * @return None. 932 */ 933 void getLastResetTime(std::shared_ptr<AsyncResp> aResp) 934 { 935 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 936 937 crow::connections::systemBus->async_method_call( 938 [aResp](const boost::system::error_code ec, 939 std::variant<uint64_t>& lastResetTime) { 940 if (ec) 941 { 942 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 943 return; 944 } 945 946 const uint64_t* lastResetTimePtr = 947 std::get_if<uint64_t>(&lastResetTime); 948 949 if (!lastResetTimePtr) 950 { 951 messages::internalError(aResp->res); 952 return; 953 } 954 // LastStateChangeTime is epoch time, in milliseconds 955 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 956 time_t lastResetTimeStamp = 957 static_cast<time_t>(*lastResetTimePtr / 1000); 958 959 // Convert to ISO 8601 standard 960 aResp->res.jsonValue["LastResetTime"] = 961 crow::utility::getDateTime(lastResetTimeStamp); 962 }, 963 "xyz.openbmc_project.State.Chassis", 964 "/xyz/openbmc_project/state/chassis0", 965 "org.freedesktop.DBus.Properties", "Get", 966 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 967 } 968 969 /** 970 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 971 * 972 * @param[in] aResp Shared pointer for generating response message. 973 * 974 * @return None. 975 */ 976 void getAutomaticRetry(std::shared_ptr<AsyncResp> aResp) 977 { 978 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 979 980 crow::connections::systemBus->async_method_call( 981 [aResp](const boost::system::error_code ec, 982 std::variant<bool>& autoRebootEnabled) { 983 if (ec) 984 { 985 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 986 return; 987 } 988 989 const bool* autoRebootEnabledPtr = 990 std::get_if<bool>(&autoRebootEnabled); 991 992 if (!autoRebootEnabledPtr) 993 { 994 messages::internalError(aResp->res); 995 return; 996 } 997 998 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 999 if (*autoRebootEnabledPtr == true) 1000 { 1001 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1002 "RetryAttempts"; 1003 // If AutomaticRetry (AutoReboot) is enabled see how many 1004 // attempts are left 1005 crow::connections::systemBus->async_method_call( 1006 [aResp](const boost::system::error_code ec, 1007 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1008 if (ec) 1009 { 1010 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1011 return; 1012 } 1013 1014 const uint32_t* autoRebootAttemptsLeftPtr = 1015 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1016 1017 if (!autoRebootAttemptsLeftPtr) 1018 { 1019 messages::internalError(aResp->res); 1020 return; 1021 } 1022 1023 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1024 << *autoRebootAttemptsLeftPtr; 1025 1026 aResp->res 1027 .jsonValue["Boot"] 1028 ["RemainingAutomaticRetryAttempts"] = 1029 *autoRebootAttemptsLeftPtr; 1030 }, 1031 "xyz.openbmc_project.State.Host", 1032 "/xyz/openbmc_project/state/host0", 1033 "org.freedesktop.DBus.Properties", "Get", 1034 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1035 "AttemptsLeft"); 1036 } 1037 else 1038 { 1039 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1040 "Disabled"; 1041 } 1042 1043 // Not on D-Bus. Hardcoded here: 1044 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1045 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1046 1047 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1048 // and RetryAttempts. OpenBMC only supports Disabled and 1049 // RetryAttempts. 1050 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1051 "AllowableValues"] = {"Disabled", 1052 "RetryAttempts"}; 1053 }, 1054 "xyz.openbmc_project.Settings", 1055 "/xyz/openbmc_project/control/host0/auto_reboot", 1056 "org.freedesktop.DBus.Properties", "Get", 1057 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1058 } 1059 1060 /** 1061 * @brief Retrieves power restore policy over DBUS. 1062 * 1063 * @param[in] aResp Shared pointer for generating response message. 1064 * 1065 * @return None. 1066 */ 1067 void getPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp) 1068 { 1069 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1070 1071 crow::connections::systemBus->async_method_call( 1072 [aResp](const boost::system::error_code ec, 1073 std::variant<std::string>& policy) { 1074 if (ec) 1075 { 1076 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1077 return; 1078 } 1079 1080 const boost::container::flat_map<std::string, std::string> 1081 policyMaps = { 1082 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1083 "AlwaysOn", 1084 "AlwaysOn"}, 1085 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1086 "AlwaysOff", 1087 "AlwaysOff"}, 1088 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1089 "LastState", 1090 "LastState"}}; 1091 1092 const std::string* policyPtr = std::get_if<std::string>(&policy); 1093 1094 if (!policyPtr) 1095 { 1096 messages::internalError(aResp->res); 1097 return; 1098 } 1099 1100 auto policyMapsIt = policyMaps.find(*policyPtr); 1101 if (policyMapsIt == policyMaps.end()) 1102 { 1103 messages::internalError(aResp->res); 1104 return; 1105 } 1106 1107 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1108 }, 1109 "xyz.openbmc_project.Settings", 1110 "/xyz/openbmc_project/control/host0/power_restore_policy", 1111 "org.freedesktop.DBus.Properties", "Get", 1112 "xyz.openbmc_project.Control.Power.RestorePolicy", 1113 "PowerRestorePolicy"); 1114 } 1115 1116 /** 1117 * @brief Sets boot properties into DBUS object(s). 1118 * 1119 * @param[in] aResp Shared pointer for generating response message. 1120 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 1121 * @param[in] bootSource The boot source to set. 1122 * @param[in] bootEnable The source override "enable" to set. 1123 * 1124 * @return Integer error code. 1125 */ 1126 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 1127 bool oneTimeEnabled, 1128 std::optional<std::string> bootSource, 1129 std::optional<std::string> bootEnable) 1130 { 1131 std::string bootSourceStr = 1132 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1133 std::string bootModeStr = 1134 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1135 bool oneTimeSetting = oneTimeEnabled; 1136 bool useBootSource = true; 1137 1138 // Validate incoming parameters 1139 if (bootEnable) 1140 { 1141 if (*bootEnable == "Once") 1142 { 1143 oneTimeSetting = true; 1144 } 1145 else if (*bootEnable == "Continuous") 1146 { 1147 oneTimeSetting = false; 1148 } 1149 else if (*bootEnable == "Disabled") 1150 { 1151 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1152 oneTimeSetting = false; 1153 useBootSource = false; 1154 } 1155 else 1156 { 1157 BMCWEB_LOG_DEBUG << "Unsupported value for " 1158 "BootSourceOverrideEnabled: " 1159 << *bootEnable; 1160 messages::propertyValueNotInList(aResp->res, *bootEnable, 1161 "BootSourceOverrideEnabled"); 1162 return; 1163 } 1164 } 1165 1166 if (bootSource && useBootSource) 1167 { 1168 // Source target specified 1169 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1170 // Figure out which DBUS interface and property to use 1171 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1172 bootModeStr)) 1173 { 1174 BMCWEB_LOG_DEBUG 1175 << "Invalid property value for BootSourceOverrideTarget: " 1176 << *bootSource; 1177 messages::propertyValueNotInList(aResp->res, *bootSource, 1178 "BootSourceTargetOverride"); 1179 return; 1180 } 1181 } 1182 1183 // Act on validated parameters 1184 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1185 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1186 const char* bootObj = 1187 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1188 : "/xyz/openbmc_project/control/host0/boot"; 1189 1190 crow::connections::systemBus->async_method_call( 1191 [aResp](const boost::system::error_code ec) { 1192 if (ec) 1193 { 1194 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1195 messages::internalError(aResp->res); 1196 return; 1197 } 1198 BMCWEB_LOG_DEBUG << "Boot source update done."; 1199 }, 1200 "xyz.openbmc_project.Settings", bootObj, 1201 "org.freedesktop.DBus.Properties", "Set", 1202 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1203 std::variant<std::string>(bootSourceStr)); 1204 1205 crow::connections::systemBus->async_method_call( 1206 [aResp](const boost::system::error_code ec) { 1207 if (ec) 1208 { 1209 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1210 messages::internalError(aResp->res); 1211 return; 1212 } 1213 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1214 }, 1215 "xyz.openbmc_project.Settings", bootObj, 1216 "org.freedesktop.DBus.Properties", "Set", 1217 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1218 std::variant<std::string>(bootModeStr)); 1219 1220 crow::connections::systemBus->async_method_call( 1221 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1222 if (ec) 1223 { 1224 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1225 messages::internalError(aResp->res); 1226 return; 1227 } 1228 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1229 }, 1230 "xyz.openbmc_project.Settings", 1231 "/xyz/openbmc_project/control/host0/boot/one_time", 1232 "org.freedesktop.DBus.Properties", "Set", 1233 "xyz.openbmc_project.Object.Enable", "Enabled", 1234 std::variant<bool>(oneTimeSetting)); 1235 } 1236 1237 /** 1238 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1239 * set boot source/boot mode properties. 1240 * 1241 * @param[in] aResp Shared pointer for generating response message. 1242 * @param[in] bootSource The boot source from incoming RF request. 1243 * @param[in] bootEnable The boot override enable from incoming RF request. 1244 * 1245 * @return Integer error code. 1246 */ 1247 static void setBootSourceProperties(std::shared_ptr<AsyncResp> aResp, 1248 std::optional<std::string> bootSource, 1249 std::optional<std::string> bootEnable) 1250 { 1251 BMCWEB_LOG_DEBUG << "Set boot information."; 1252 1253 crow::connections::systemBus->async_method_call( 1254 [aResp, bootSource{std::move(bootSource)}, 1255 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1256 const std::variant<bool>& oneTime) { 1257 if (ec) 1258 { 1259 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1260 messages::internalError(aResp->res); 1261 return; 1262 } 1263 1264 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1265 1266 if (!oneTimePtr) 1267 { 1268 messages::internalError(aResp->res); 1269 return; 1270 } 1271 1272 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1273 1274 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 1275 std::move(bootEnable)); 1276 }, 1277 "xyz.openbmc_project.Settings", 1278 "/xyz/openbmc_project/control/host0/boot/one_time", 1279 "org.freedesktop.DBus.Properties", "Get", 1280 "xyz.openbmc_project.Object.Enable", "Enabled"); 1281 } 1282 1283 /** 1284 * @brief Sets automaticRetry (Auto Reboot) 1285 * 1286 * @param[in] aResp Shared pointer for generating response message. 1287 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1288 * 1289 * @return None. 1290 */ 1291 static void setAutomaticRetry(std::shared_ptr<AsyncResp> aResp, 1292 const std::string&& automaticRetryConfig) 1293 { 1294 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1295 1296 // OpenBMC only supports "Disabled" and "RetryAttempts". 1297 bool autoRebootEnabled; 1298 1299 if (automaticRetryConfig == "Disabled") 1300 { 1301 autoRebootEnabled = false; 1302 } 1303 else if (automaticRetryConfig == "RetryAttempts") 1304 { 1305 autoRebootEnabled = true; 1306 } 1307 else 1308 { 1309 BMCWEB_LOG_DEBUG << "Invalid property value for " 1310 "AutomaticRetryConfig: " 1311 << automaticRetryConfig; 1312 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1313 "AutomaticRetryConfig"); 1314 return; 1315 } 1316 1317 crow::connections::systemBus->async_method_call( 1318 [aResp](const boost::system::error_code ec) { 1319 if (ec) 1320 { 1321 messages::internalError(aResp->res); 1322 return; 1323 } 1324 }, 1325 "xyz.openbmc_project.Settings", 1326 "/xyz/openbmc_project/control/host0/auto_reboot", 1327 "org.freedesktop.DBus.Properties", "Set", 1328 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1329 std::variant<bool>(autoRebootEnabled)); 1330 } 1331 1332 /** 1333 * @brief Sets power restore policy properties. 1334 * 1335 * @param[in] aResp Shared pointer for generating response message. 1336 * @param[in] policy power restore policy properties from request. 1337 * 1338 * @return None. 1339 */ 1340 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp, 1341 std::optional<std::string> policy) 1342 { 1343 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1344 1345 const boost::container::flat_map<std::string, std::string> policyMaps = { 1346 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1347 "AlwaysOn"}, 1348 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1349 "AlwaysOff"}, 1350 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1351 "LastState"}}; 1352 1353 std::string powerRestorPolicy; 1354 1355 auto policyMapsIt = policyMaps.find(*policy); 1356 if (policyMapsIt == policyMaps.end()) 1357 { 1358 messages::internalError(aResp->res); 1359 return; 1360 } 1361 1362 powerRestorPolicy = policyMapsIt->second; 1363 1364 crow::connections::systemBus->async_method_call( 1365 [aResp](const boost::system::error_code ec) { 1366 if (ec) 1367 { 1368 messages::internalError(aResp->res); 1369 return; 1370 } 1371 }, 1372 "xyz.openbmc_project.Settings", 1373 "/xyz/openbmc_project/control/host0/power_restore_policy", 1374 "org.freedesktop.DBus.Properties", "Set", 1375 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1376 std::variant<std::string>(powerRestorPolicy)); 1377 } 1378 1379 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1380 /** 1381 * @brief Retrieves provisioning status 1382 * 1383 * @param[in] aResp Shared pointer for completing asynchronous calls. 1384 * 1385 * @return None. 1386 */ 1387 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp) 1388 { 1389 BMCWEB_LOG_DEBUG << "Get OEM information."; 1390 crow::connections::systemBus->async_method_call( 1391 [aResp](const boost::system::error_code ec, 1392 const std::vector<std::pair<std::string, VariantType>>& 1393 propertiesList) { 1394 nlohmann::json& oemPFR = 1395 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1396 if (ec) 1397 { 1398 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1399 // not an error, don't have to have the interface 1400 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1401 return; 1402 } 1403 1404 const bool* provState = nullptr; 1405 const bool* lockState = nullptr; 1406 for (const std::pair<std::string, VariantType>& property : 1407 propertiesList) 1408 { 1409 if (property.first == "UfmProvisioned") 1410 { 1411 provState = std::get_if<bool>(&property.second); 1412 } 1413 else if (property.first == "UfmLocked") 1414 { 1415 lockState = std::get_if<bool>(&property.second); 1416 } 1417 } 1418 1419 if ((provState == nullptr) || (lockState == nullptr)) 1420 { 1421 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1422 messages::internalError(aResp->res); 1423 return; 1424 } 1425 1426 if (*provState == true) 1427 { 1428 if (*lockState == true) 1429 { 1430 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1431 } 1432 else 1433 { 1434 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1435 } 1436 } 1437 else 1438 { 1439 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1440 } 1441 }, 1442 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1443 "org.freedesktop.DBus.Properties", "GetAll", 1444 "xyz.openbmc_project.PFR.Attributes"); 1445 } 1446 #endif 1447 1448 /** 1449 * @brief Translates watchdog timeout action DBUS property value to redfish. 1450 * 1451 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1452 * 1453 * @return Returns as a string, the timeout action in Redfish terms. If 1454 * translation cannot be done, returns an empty string. 1455 */ 1456 static std::string dbusToRfWatchdogAction(const std::string& dbusAction) 1457 { 1458 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1459 { 1460 return "None"; 1461 } 1462 else if (dbusAction == 1463 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1464 { 1465 return "ResetSystem"; 1466 } 1467 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1468 { 1469 return "PowerDown"; 1470 } 1471 else if (dbusAction == 1472 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1473 { 1474 return "PowerCycle"; 1475 } 1476 1477 return ""; 1478 } 1479 1480 /** 1481 *@brief Translates timeout action from Redfish to DBUS property value. 1482 * 1483 *@param[in] rfAction The timeout action in Redfish. 1484 * 1485 *@return Returns as a string, the time_out action as expected by DBUS. 1486 *If translation cannot be done, returns an empty string. 1487 */ 1488 1489 static std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 1490 { 1491 if (rfAction == "None") 1492 { 1493 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1494 } 1495 else if (rfAction == "PowerCycle") 1496 { 1497 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1498 } 1499 else if (rfAction == "PowerDown") 1500 { 1501 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1502 } 1503 else if (rfAction == "ResetSystem") 1504 { 1505 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1506 } 1507 1508 return ""; 1509 } 1510 1511 /** 1512 * @brief Retrieves host watchdog timer properties over DBUS 1513 * 1514 * @param[in] aResp Shared pointer for completing asynchronous calls. 1515 * 1516 * @return None. 1517 */ 1518 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1519 { 1520 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1521 crow::connections::systemBus->async_method_call( 1522 [aResp](const boost::system::error_code ec, 1523 PropertiesType& properties) { 1524 if (ec) 1525 { 1526 // watchdog service is stopped 1527 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1528 return; 1529 } 1530 1531 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1532 1533 nlohmann::json& hostWatchdogTimer = 1534 aResp->res.jsonValue["HostWatchdogTimer"]; 1535 1536 // watchdog service is running/enabled 1537 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1538 1539 for (const auto& property : properties) 1540 { 1541 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1542 if (property.first == "Enabled") 1543 { 1544 const bool* state = std::get_if<bool>(&property.second); 1545 1546 if (!state) 1547 { 1548 messages::internalError(aResp->res); 1549 continue; 1550 } 1551 1552 hostWatchdogTimer["FunctionEnabled"] = *state; 1553 } 1554 else if (property.first == "ExpireAction") 1555 { 1556 const std::string* s = 1557 std::get_if<std::string>(&property.second); 1558 if (!s) 1559 { 1560 messages::internalError(aResp->res); 1561 continue; 1562 } 1563 1564 std::string action = dbusToRfWatchdogAction(*s); 1565 if (action.empty()) 1566 { 1567 messages::internalError(aResp->res); 1568 continue; 1569 } 1570 hostWatchdogTimer["TimeoutAction"] = action; 1571 } 1572 } 1573 }, 1574 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1575 "org.freedesktop.DBus.Properties", "GetAll", 1576 "xyz.openbmc_project.State.Watchdog"); 1577 } 1578 1579 /** 1580 * @brief Sets Host WatchDog Timer properties. 1581 * 1582 * @param[in] aResp Shared pointer for generating response message. 1583 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1584 * RF request. 1585 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1586 * 1587 * @return None. 1588 */ 1589 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1590 const std::optional<bool> wdtEnable, 1591 const std::optional<std::string>& wdtTimeOutAction) 1592 { 1593 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1594 1595 if (wdtTimeOutAction) 1596 { 1597 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1598 // check if TimeOut Action is Valid 1599 if (wdtTimeOutActStr.empty()) 1600 { 1601 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1602 << *wdtTimeOutAction; 1603 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1604 "TimeoutAction"); 1605 return; 1606 } 1607 1608 crow::connections::systemBus->async_method_call( 1609 [aResp](const boost::system::error_code ec) { 1610 if (ec) 1611 { 1612 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1613 messages::internalError(aResp->res); 1614 return; 1615 } 1616 }, 1617 "xyz.openbmc_project.Watchdog", 1618 "/xyz/openbmc_project/watchdog/host0", 1619 "org.freedesktop.DBus.Properties", "Set", 1620 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1621 std::variant<std::string>(wdtTimeOutActStr)); 1622 } 1623 1624 if (wdtEnable) 1625 { 1626 crow::connections::systemBus->async_method_call( 1627 [aResp](const boost::system::error_code ec) { 1628 if (ec) 1629 { 1630 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1631 messages::internalError(aResp->res); 1632 return; 1633 } 1634 }, 1635 "xyz.openbmc_project.Watchdog", 1636 "/xyz/openbmc_project/watchdog/host0", 1637 "org.freedesktop.DBus.Properties", "Set", 1638 "xyz.openbmc_project.State.Watchdog", "Enabled", 1639 std::variant<bool>(*wdtEnable)); 1640 } 1641 } 1642 1643 /** 1644 * SystemsCollection derived class for delivering ComputerSystems Collection 1645 * Schema 1646 */ 1647 class SystemsCollection : public Node 1648 { 1649 public: 1650 SystemsCollection(CrowApp& app) : Node(app, "/redfish/v1/Systems/") 1651 { 1652 entityPrivileges = { 1653 {boost::beast::http::verb::get, {{"Login"}}}, 1654 {boost::beast::http::verb::head, {{"Login"}}}, 1655 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1656 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1657 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1658 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1659 } 1660 1661 private: 1662 void doGet(crow::Response& res, const crow::Request& req, 1663 const std::vector<std::string>& params) override 1664 { 1665 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1666 res.jsonValue["@odata.type"] = 1667 "#ComputerSystemCollection.ComputerSystemCollection"; 1668 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1669 res.jsonValue["Name"] = "Computer System Collection"; 1670 1671 crow::connections::systemBus->async_method_call( 1672 [asyncResp](const boost::system::error_code ec, 1673 const std::variant<std::string>& hostName) { 1674 nlohmann::json& iface_array = 1675 asyncResp->res.jsonValue["Members"]; 1676 iface_array = nlohmann::json::array(); 1677 auto& count = asyncResp->res.jsonValue["Members@odata.count"]; 1678 count = 0; 1679 if (ec) 1680 { 1681 iface_array.push_back( 1682 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1683 count = iface_array.size(); 1684 return; 1685 } 1686 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1687 iface_array.push_back( 1688 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1689 iface_array.push_back( 1690 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1691 count = iface_array.size(); 1692 }, 1693 "xyz.openbmc_project.Settings", 1694 "/xyz/openbmc_project/network/hypervisor", 1695 "org.freedesktop.DBus.Properties", "Get", 1696 "xyz.openbmc_project.Network.SystemConfiguration", "HostName"); 1697 } 1698 }; 1699 1700 /** 1701 * SystemActionsReset class supports handle POST method for Reset action. 1702 * The class retrieves and sends data directly to D-Bus. 1703 */ 1704 class SystemActionsReset : public Node 1705 { 1706 public: 1707 SystemActionsReset(CrowApp& app) : 1708 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1709 { 1710 entityPrivileges = { 1711 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1712 } 1713 1714 private: 1715 /** 1716 * Function handles POST method request. 1717 * Analyzes POST body message before sends Reset request data to D-Bus. 1718 */ 1719 void doPost(crow::Response& res, const crow::Request& req, 1720 const std::vector<std::string>& params) override 1721 { 1722 auto asyncResp = std::make_shared<AsyncResp>(res); 1723 1724 std::string resetType; 1725 if (!json_util::readJson(req, res, "ResetType", resetType)) 1726 { 1727 return; 1728 } 1729 1730 // Get the command and host vs. chassis 1731 std::string command; 1732 bool hostCommand; 1733 if (resetType == "On") 1734 { 1735 command = "xyz.openbmc_project.State.Host.Transition.On"; 1736 hostCommand = true; 1737 } 1738 else if (resetType == "ForceOff") 1739 { 1740 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1741 hostCommand = false; 1742 } 1743 else if (resetType == "ForceOn") 1744 { 1745 command = "xyz.openbmc_project.State.Host.Transition.On"; 1746 hostCommand = true; 1747 } 1748 else if (resetType == "ForceRestart") 1749 { 1750 command = 1751 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 1752 hostCommand = true; 1753 } 1754 else if (resetType == "GracefulShutdown") 1755 { 1756 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1757 hostCommand = true; 1758 } 1759 else if (resetType == "GracefulRestart") 1760 { 1761 command = 1762 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot"; 1763 hostCommand = true; 1764 } 1765 else if (resetType == "PowerCycle") 1766 { 1767 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1768 hostCommand = true; 1769 } 1770 else if (resetType == "Nmi") 1771 { 1772 doNMI(asyncResp); 1773 return; 1774 } 1775 else 1776 { 1777 messages::actionParameterUnknown(res, "Reset", resetType); 1778 return; 1779 } 1780 1781 if (hostCommand) 1782 { 1783 crow::connections::systemBus->async_method_call( 1784 [asyncResp, resetType](const boost::system::error_code ec) { 1785 if (ec) 1786 { 1787 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1788 if (ec.value() == boost::asio::error::invalid_argument) 1789 { 1790 messages::actionParameterNotSupported( 1791 asyncResp->res, resetType, "Reset"); 1792 } 1793 else 1794 { 1795 messages::internalError(asyncResp->res); 1796 } 1797 return; 1798 } 1799 messages::success(asyncResp->res); 1800 }, 1801 "xyz.openbmc_project.State.Host", 1802 "/xyz/openbmc_project/state/host0", 1803 "org.freedesktop.DBus.Properties", "Set", 1804 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1805 std::variant<std::string>{command}); 1806 } 1807 else 1808 { 1809 crow::connections::systemBus->async_method_call( 1810 [asyncResp, resetType](const boost::system::error_code ec) { 1811 if (ec) 1812 { 1813 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1814 if (ec.value() == boost::asio::error::invalid_argument) 1815 { 1816 messages::actionParameterNotSupported( 1817 asyncResp->res, resetType, "Reset"); 1818 } 1819 else 1820 { 1821 messages::internalError(asyncResp->res); 1822 } 1823 return; 1824 } 1825 messages::success(asyncResp->res); 1826 }, 1827 "xyz.openbmc_project.State.Chassis", 1828 "/xyz/openbmc_project/state/chassis0", 1829 "org.freedesktop.DBus.Properties", "Set", 1830 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1831 std::variant<std::string>{command}); 1832 } 1833 } 1834 /** 1835 * Function transceives data with dbus directly. 1836 */ 1837 void doNMI(const std::shared_ptr<AsyncResp>& asyncResp) 1838 { 1839 constexpr char const* serviceName = 1840 "xyz.openbmc_project.Control.Host.NMI"; 1841 constexpr char const* objectPath = 1842 "/xyz/openbmc_project/control/host0/nmi"; 1843 constexpr char const* interfaceName = 1844 "xyz.openbmc_project.Control.Host.NMI"; 1845 constexpr char const* method = "NMI"; 1846 1847 crow::connections::systemBus->async_method_call( 1848 [asyncResp](const boost::system::error_code ec) { 1849 if (ec) 1850 { 1851 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 1852 messages::internalError(asyncResp->res); 1853 return; 1854 } 1855 messages::success(asyncResp->res); 1856 }, 1857 serviceName, objectPath, interfaceName, method); 1858 } 1859 }; 1860 1861 /** 1862 * Systems derived class for delivering Computer Systems Schema. 1863 */ 1864 class Systems : public Node 1865 { 1866 public: 1867 /* 1868 * Default Constructor 1869 */ 1870 Systems(CrowApp& app) : Node(app, "/redfish/v1/Systems/system/") 1871 { 1872 entityPrivileges = { 1873 {boost::beast::http::verb::get, {{"Login"}}}, 1874 {boost::beast::http::verb::head, {{"Login"}}}, 1875 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1876 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1877 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1878 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1879 } 1880 1881 private: 1882 /** 1883 * Functions triggers appropriate requests on DBus 1884 */ 1885 void doGet(crow::Response& res, const crow::Request& req, 1886 const std::vector<std::string>& params) override 1887 { 1888 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_12_0.ComputerSystem"; 1889 res.jsonValue["Name"] = "system"; 1890 res.jsonValue["Id"] = "system"; 1891 res.jsonValue["SystemType"] = "Physical"; 1892 res.jsonValue["Description"] = "Computer System"; 1893 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1894 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1895 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0); 1896 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1897 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1898 1899 res.jsonValue["Processors"] = { 1900 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1901 res.jsonValue["Memory"] = { 1902 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1903 res.jsonValue["Storage"] = { 1904 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 1905 1906 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1907 {"target", 1908 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1909 {"ResetType@Redfish.AllowableValues", 1910 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1911 "GracefulShutdown", "PowerCycle", "Nmi"}}}; 1912 1913 res.jsonValue["LogServices"] = { 1914 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1915 1916 res.jsonValue["Bios"] = { 1917 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1918 1919 res.jsonValue["Links"]["ManagedBy"] = { 1920 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1921 1922 res.jsonValue["Status"] = { 1923 {"Health", "OK"}, 1924 {"State", "Enabled"}, 1925 }; 1926 auto asyncResp = std::make_shared<AsyncResp>(res); 1927 1928 constexpr const std::array<const char*, 4> inventoryForSystems = { 1929 "xyz.openbmc_project.Inventory.Item.Dimm", 1930 "xyz.openbmc_project.Inventory.Item.Cpu", 1931 "xyz.openbmc_project.Inventory.Item.Drive", 1932 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1933 1934 auto health = std::make_shared<HealthPopulate>(asyncResp); 1935 crow::connections::systemBus->async_method_call( 1936 [health](const boost::system::error_code ec, 1937 std::vector<std::string>& resp) { 1938 if (ec) 1939 { 1940 // no inventory 1941 return; 1942 } 1943 1944 health->inventory = std::move(resp); 1945 }, 1946 "xyz.openbmc_project.ObjectMapper", 1947 "/xyz/openbmc_project/object_mapper", 1948 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1949 int32_t(0), inventoryForSystems); 1950 1951 health->populate(); 1952 1953 getMainChassisId(asyncResp, [](const std::string& chassisId, 1954 std::shared_ptr<AsyncResp> aRsp) { 1955 aRsp->res.jsonValue["Links"]["Chassis"] = { 1956 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1957 }); 1958 1959 getIndicatorLedState(asyncResp); 1960 getComputerSystem(asyncResp, health); 1961 getHostState(asyncResp); 1962 getBootProperties(asyncResp); 1963 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1964 getHostWatchdogTimer(asyncResp); 1965 getPowerRestorePolicy(asyncResp); 1966 getAutomaticRetry(asyncResp); 1967 getLastResetTime(asyncResp); 1968 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1969 getProvisioningStatus(asyncResp); 1970 #endif 1971 } 1972 1973 void doPatch(crow::Response& res, const crow::Request& req, 1974 const std::vector<std::string>& params) override 1975 { 1976 std::optional<std::string> indicatorLed; 1977 std::optional<nlohmann::json> bootProps; 1978 std::optional<nlohmann::json> wdtTimerProps; 1979 std::optional<std::string> powerRestorePolicy; 1980 auto asyncResp = std::make_shared<AsyncResp>(res); 1981 1982 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1983 bootProps, "WatchdogTimer", wdtTimerProps, 1984 "PowerRestorePolicy", powerRestorePolicy)) 1985 { 1986 return; 1987 } 1988 1989 res.result(boost::beast::http::status::no_content); 1990 1991 if (wdtTimerProps) 1992 { 1993 std::optional<bool> wdtEnable; 1994 std::optional<std::string> wdtTimeOutAction; 1995 1996 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1997 "FunctionEnabled", wdtEnable, 1998 "TimeoutAction", wdtTimeOutAction)) 1999 { 2000 return; 2001 } 2002 setWDTProperties(asyncResp, std::move(wdtEnable), 2003 std::move(wdtTimeOutAction)); 2004 } 2005 2006 if (bootProps) 2007 { 2008 std::optional<std::string> bootSource; 2009 std::optional<std::string> bootEnable; 2010 std::optional<std::string> automaticRetryConfig; 2011 2012 if (!json_util::readJson( 2013 *bootProps, asyncResp->res, "BootSourceOverrideTarget", 2014 bootSource, "BootSourceOverrideEnabled", bootEnable, 2015 "AutomaticRetryConfig", automaticRetryConfig)) 2016 { 2017 return; 2018 } 2019 if (bootSource || bootEnable) 2020 { 2021 setBootSourceProperties(asyncResp, std::move(bootSource), 2022 std::move(bootEnable)); 2023 } 2024 if (automaticRetryConfig) 2025 { 2026 setAutomaticRetry(asyncResp, std::move(*automaticRetryConfig)); 2027 } 2028 } 2029 2030 if (indicatorLed) 2031 { 2032 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 2033 } 2034 2035 if (powerRestorePolicy) 2036 { 2037 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 2038 } 2039 } 2040 }; 2041 } // namespace redfish 2042