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