1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include "health.hpp" 19 #include "led.hpp" 20 #include "pcie.hpp" 21 #include "redfish_util.hpp" 22 23 #include <boost/container/flat_map.hpp> 24 #include <node.hpp> 25 #include <utils/fw_utils.hpp> 26 #include <utils/json_utils.hpp> 27 28 #include <variant> 29 30 namespace redfish 31 { 32 33 /** 34 * @brief Updates the Functional State of DIMMs 35 * 36 * @param[in] aResp Shared pointer for completing asynchronous calls 37 * @param[in] dimmState Dimm's Functional state, true/false 38 * 39 * @return None. 40 */ 41 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp, 42 const std::variant<bool>& dimmState) 43 { 44 const bool* isDimmFunctional = std::get_if<bool>(&dimmState); 45 if (isDimmFunctional == nullptr) 46 { 47 messages::internalError(aResp->res); 48 return; 49 } 50 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 51 52 // Set it as Enabled if atleast one DIMM is functional 53 // Update STATE only if previous State was DISABLED and current Dimm is 54 // ENABLED. 55 nlohmann::json& prevMemSummary = 56 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 57 if (prevMemSummary == "Disabled") 58 { 59 if (*isDimmFunctional == true) 60 { 61 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 62 "Enabled"; 63 } 64 } 65 } 66 67 /* 68 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 69 * 70 * @param[in] aResp Shared pointer for completing asynchronous calls 71 * @param[in] cpuPresenceState CPU present or not 72 * 73 * @return None. 74 */ 75 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp, 76 const std::variant<bool>& cpuPresenceState) 77 { 78 const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState); 79 80 if (isCpuPresent == nullptr) 81 { 82 messages::internalError(aResp->res); 83 return; 84 } 85 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 86 87 if (*isCpuPresent == true) 88 { 89 nlohmann::json& procCount = 90 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 91 auto procCountPtr = 92 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 93 if (procCountPtr != nullptr) 94 { 95 // shouldn't be possible to be nullptr 96 *procCountPtr += 1; 97 } 98 } 99 } 100 101 /* 102 * @brief Update "ProcessorSummary" "Status" "State" based on 103 * CPU Functional State 104 * 105 * @param[in] aResp Shared pointer for completing asynchronous calls 106 * @param[in] cpuFunctionalState is CPU functional true/false 107 * 108 * @return None. 109 */ 110 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp, 111 const std::variant<bool>& cpuFunctionalState) 112 { 113 const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 114 115 if (isCpuFunctional == nullptr) 116 { 117 messages::internalError(aResp->res); 118 return; 119 } 120 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 121 122 nlohmann::json& prevProcState = 123 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 124 125 // Set it as Enabled if atleast one CPU is functional 126 // Update STATE only if previous State was Non_Functional and current CPU is 127 // Functional. 128 if (prevProcState == "Disabled") 129 { 130 if (*isCpuFunctional == true) 131 { 132 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 133 "Enabled"; 134 } 135 } 136 } 137 138 /* 139 * @brief Retrieves computer system properties over dbus 140 * 141 * @param[in] aResp Shared pointer for completing asynchronous calls 142 * @param[in] name Computer system name from request 143 * 144 * @return None. 145 */ 146 void getComputerSystem(std::shared_ptr<AsyncResp> aResp, 147 std::shared_ptr<HealthPopulate> systemHealth) 148 { 149 BMCWEB_LOG_DEBUG << "Get available system components."; 150 151 crow::connections::systemBus->async_method_call( 152 [aResp, systemHealth]( 153 const boost::system::error_code ec, 154 const std::vector<std::pair< 155 std::string, 156 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 157 subtree) { 158 if (ec) 159 { 160 BMCWEB_LOG_DEBUG << "DBUS response error"; 161 messages::internalError(aResp->res); 162 return; 163 } 164 // Iterate over all retrieved ObjectPaths. 165 for (const std::pair<std::string, 166 std::vector<std::pair< 167 std::string, std::vector<std::string>>>>& 168 object : subtree) 169 { 170 const std::string& path = object.first; 171 BMCWEB_LOG_DEBUG << "Got path: " << path; 172 const std::vector< 173 std::pair<std::string, std::vector<std::string>>>& 174 connectionNames = object.second; 175 if (connectionNames.size() < 1) 176 { 177 continue; 178 } 179 180 auto memoryHealth = std::make_shared<HealthPopulate>( 181 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 182 183 auto cpuHealth = std::make_shared<HealthPopulate>( 184 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 185 186 systemHealth->children.emplace_back(memoryHealth); 187 systemHealth->children.emplace_back(cpuHealth); 188 189 // This is not system, so check if it's cpu, dimm, UUID or 190 // BiosVer 191 for (const auto& connection : connectionNames) 192 { 193 for (const auto& interfaceName : connection.second) 194 { 195 if (interfaceName == 196 "xyz.openbmc_project.Inventory.Item.Dimm") 197 { 198 BMCWEB_LOG_DEBUG 199 << "Found Dimm, now get its properties."; 200 201 crow::connections::systemBus->async_method_call( 202 [aResp, service{connection.first}, 203 path(std::move(path))]( 204 const boost::system::error_code ec, 205 const std::vector< 206 std::pair<std::string, VariantType>>& 207 properties) { 208 if (ec) 209 { 210 BMCWEB_LOG_ERROR 211 << "DBUS response error " << ec; 212 messages::internalError(aResp->res); 213 return; 214 } 215 BMCWEB_LOG_DEBUG << "Got " 216 << properties.size() 217 << " Dimm properties."; 218 219 if (properties.size() > 0) 220 { 221 for (const std::pair<std::string, 222 VariantType>& 223 property : properties) 224 { 225 if (property.first != 226 "MemorySizeInKB") 227 { 228 continue; 229 } 230 const uint32_t* value = 231 std::get_if<uint32_t>( 232 &property.second); 233 if (value == nullptr) 234 { 235 BMCWEB_LOG_DEBUG 236 << "Find incorrect type of " 237 "MemorySize"; 238 continue; 239 } 240 nlohmann::json& totalMemory = 241 aResp->res 242 .jsonValue["MemorySummar" 243 "y"] 244 ["TotalSystemMe" 245 "moryGiB"]; 246 uint64_t* preValue = 247 totalMemory 248 .get_ptr<uint64_t*>(); 249 if (preValue == nullptr) 250 { 251 continue; 252 } 253 aResp->res 254 .jsonValue["MemorySummary"] 255 ["TotalSystemMemoryGi" 256 "B"] = 257 *value / (1024 * 1024) + 258 *preValue; 259 aResp->res 260 .jsonValue["MemorySummary"] 261 ["Status"]["State"] = 262 "Enabled"; 263 } 264 } 265 else 266 { 267 auto getDimmProperties = 268 [aResp]( 269 const boost::system::error_code 270 ec, 271 const std::variant<bool>& 272 dimmState) { 273 if (ec) 274 { 275 BMCWEB_LOG_ERROR 276 << "DBUS response " 277 "error " 278 << ec; 279 return; 280 } 281 updateDimmProperties(aResp, 282 dimmState); 283 }; 284 crow::connections::systemBus 285 ->async_method_call( 286 std::move(getDimmProperties), 287 service, path, 288 "org.freedesktop.DBus." 289 "Properties", 290 "Get", 291 "xyz.openbmc_project.State." 292 "Decorator.OperationalStatus", 293 "Functional"); 294 } 295 }, 296 connection.first, path, 297 "org.freedesktop.DBus.Properties", "GetAll", 298 "xyz.openbmc_project.Inventory.Item.Dimm"); 299 300 memoryHealth->inventory.emplace_back(path); 301 } 302 else if (interfaceName == 303 "xyz.openbmc_project.Inventory.Item.Cpu") 304 { 305 BMCWEB_LOG_DEBUG 306 << "Found Cpu, now get its properties."; 307 308 crow::connections::systemBus->async_method_call( 309 [aResp, service{connection.first}, 310 path(std::move(path))]( 311 const boost::system::error_code ec, 312 const std::vector< 313 std::pair<std::string, VariantType>>& 314 properties) { 315 if (ec) 316 { 317 BMCWEB_LOG_ERROR 318 << "DBUS response error " << ec; 319 messages::internalError(aResp->res); 320 return; 321 } 322 BMCWEB_LOG_DEBUG << "Got " 323 << properties.size() 324 << " Cpu properties."; 325 326 if (properties.size() > 0) 327 { 328 for (const auto& property : properties) 329 { 330 if (property.first == 331 "ProcessorFamily") 332 { 333 const std::string* value = 334 std::get_if<std::string>( 335 &property.second); 336 if (value != nullptr) 337 { 338 nlohmann::json& 339 procSummary = 340 aResp->res.jsonValue 341 ["ProcessorSumm" 342 "ary"]; 343 nlohmann::json& procCount = 344 procSummary["Count"]; 345 346 auto procCountPtr = 347 procCount.get_ptr< 348 nlohmann::json:: 349 number_integer_t*>(); 350 if (procCountPtr != nullptr) 351 { 352 // shouldn't be possible 353 // to be nullptr 354 *procCountPtr += 1; 355 } 356 procSummary["Status"] 357 ["State"] = 358 "Enabled"; 359 procSummary["Model"] = 360 *value; 361 } 362 } 363 } 364 } 365 else 366 { 367 auto getCpuPresenceState = 368 [aResp]( 369 const boost::system::error_code 370 ec, 371 const std::variant<bool>& 372 cpuPresenceCheck) { 373 if (ec) 374 { 375 BMCWEB_LOG_ERROR 376 << "DBUS response " 377 "error " 378 << ec; 379 return; 380 } 381 modifyCpuPresenceState( 382 aResp, cpuPresenceCheck); 383 }; 384 385 auto getCpuFunctionalState = 386 [aResp]( 387 const boost::system::error_code 388 ec, 389 const std::variant<bool>& 390 cpuFunctionalCheck) { 391 if (ec) 392 { 393 BMCWEB_LOG_ERROR 394 << "DBUS response " 395 "error " 396 << ec; 397 return; 398 } 399 modifyCpuFunctionalState( 400 aResp, cpuFunctionalCheck); 401 }; 402 // Get the Presence of CPU 403 crow::connections::systemBus 404 ->async_method_call( 405 std::move(getCpuPresenceState), 406 service, path, 407 "org.freedesktop.DBus." 408 "Properties", 409 "Get", 410 "xyz.openbmc_project.Inventory." 411 "Item", 412 "Present"); 413 414 // Get the Functional State 415 crow::connections::systemBus 416 ->async_method_call( 417 std::move( 418 getCpuFunctionalState), 419 service, path, 420 "org.freedesktop.DBus." 421 "Properties", 422 "Get", 423 "xyz.openbmc_project.State." 424 "Decorator." 425 "OperationalStatus", 426 "Functional"); 427 428 // Get the MODEL from 429 // xyz.openbmc_project.Inventory.Decorator.Asset 430 // support it later as Model is Empty 431 // currently. 432 } 433 }, 434 connection.first, path, 435 "org.freedesktop.DBus.Properties", "GetAll", 436 "xyz.openbmc_project.Inventory.Item.Cpu"); 437 438 cpuHealth->inventory.emplace_back(path); 439 } 440 else if (interfaceName == 441 "xyz.openbmc_project.Common.UUID") 442 { 443 BMCWEB_LOG_DEBUG 444 << "Found UUID, now get its properties."; 445 crow::connections::systemBus->async_method_call( 446 [aResp]( 447 const boost::system::error_code ec, 448 const std::vector< 449 std::pair<std::string, VariantType>>& 450 properties) { 451 if (ec) 452 { 453 BMCWEB_LOG_DEBUG 454 << "DBUS response error " << ec; 455 messages::internalError(aResp->res); 456 return; 457 } 458 BMCWEB_LOG_DEBUG << "Got " 459 << properties.size() 460 << " UUID properties."; 461 for (const std::pair<std::string, 462 VariantType>& 463 property : properties) 464 { 465 if (property.first == "UUID") 466 { 467 const std::string* value = 468 std::get_if<std::string>( 469 &property.second); 470 471 if (value != nullptr) 472 { 473 std::string valueStr = *value; 474 if (valueStr.size() == 32) 475 { 476 valueStr.insert(8, 1, '-'); 477 valueStr.insert(13, 1, '-'); 478 valueStr.insert(18, 1, '-'); 479 valueStr.insert(23, 1, '-'); 480 } 481 BMCWEB_LOG_DEBUG << "UUID = " 482 << valueStr; 483 aResp->res.jsonValue["UUID"] = 484 valueStr; 485 } 486 } 487 } 488 }, 489 connection.first, path, 490 "org.freedesktop.DBus.Properties", "GetAll", 491 "xyz.openbmc_project.Common.UUID"); 492 } 493 else if (interfaceName == 494 "xyz.openbmc_project.Inventory.Item.System") 495 { 496 crow::connections::systemBus->async_method_call( 497 [aResp]( 498 const boost::system::error_code ec, 499 const std::vector< 500 std::pair<std::string, VariantType>>& 501 propertiesList) { 502 if (ec) 503 { 504 // doesn't have to include this 505 // interface 506 return; 507 } 508 BMCWEB_LOG_DEBUG 509 << "Got " << propertiesList.size() 510 << " properties for system"; 511 for (const std::pair<std::string, 512 VariantType>& 513 property : propertiesList) 514 { 515 const std::string& propertyName = 516 property.first; 517 if ((propertyName == "PartNumber") || 518 (propertyName == "SerialNumber") || 519 (propertyName == "Manufacturer") || 520 (propertyName == "Model")) 521 { 522 const std::string* value = 523 std::get_if<std::string>( 524 &property.second); 525 if (value != nullptr) 526 { 527 aResp->res 528 .jsonValue[propertyName] = 529 *value; 530 } 531 } 532 } 533 534 // Grab the bios version 535 fw_util::getActiveFwVersion( 536 aResp, fw_util::biosPurpose, 537 "BiosVersion"); 538 }, 539 connection.first, path, 540 "org.freedesktop.DBus.Properties", "GetAll", 541 "xyz.openbmc_project.Inventory.Decorator." 542 "Asset"); 543 544 crow::connections::systemBus->async_method_call( 545 [aResp]( 546 const boost::system::error_code ec, 547 const std::variant<std::string>& property) { 548 if (ec) 549 { 550 // doesn't have to include this 551 // interface 552 return; 553 } 554 555 const std::string* value = 556 std::get_if<std::string>(&property); 557 if (value != nullptr) 558 { 559 aResp->res.jsonValue["AssetTag"] = 560 *value; 561 } 562 }, 563 connection.first, path, 564 "org.freedesktop.DBus.Properties", "Get", 565 "xyz.openbmc_project.Inventory.Decorator." 566 "AssetTag", 567 "AssetTag"); 568 } 569 } 570 } 571 } 572 }, 573 "xyz.openbmc_project.ObjectMapper", 574 "/xyz/openbmc_project/object_mapper", 575 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 576 "/xyz/openbmc_project/inventory", int32_t(0), 577 std::array<const char*, 5>{ 578 "xyz.openbmc_project.Inventory.Decorator.Asset", 579 "xyz.openbmc_project.Inventory.Item.Cpu", 580 "xyz.openbmc_project.Inventory.Item.Dimm", 581 "xyz.openbmc_project.Inventory.Item.System", 582 "xyz.openbmc_project.Common.UUID", 583 }); 584 } 585 586 /** 587 * @brief Retrieves host state properties over dbus 588 * 589 * @param[in] aResp Shared pointer for completing asynchronous calls. 590 * 591 * @return None. 592 */ 593 void getHostState(std::shared_ptr<AsyncResp> aResp) 594 { 595 BMCWEB_LOG_DEBUG << "Get host information."; 596 crow::connections::systemBus->async_method_call( 597 [aResp](const boost::system::error_code ec, 598 const std::variant<std::string>& hostState) { 599 if (ec) 600 { 601 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 602 messages::internalError(aResp->res); 603 return; 604 } 605 606 const std::string* s = std::get_if<std::string>(&hostState); 607 BMCWEB_LOG_DEBUG << "Host state: " << *s; 608 if (s != nullptr) 609 { 610 // Verify Host State 611 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 612 { 613 aResp->res.jsonValue["PowerState"] = "On"; 614 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 615 } 616 else if (*s == "xyz.openbmc_project.State.Host.HostState." 617 "Quiesced") 618 { 619 aResp->res.jsonValue["PowerState"] = "On"; 620 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 621 } 622 else if (*s == "xyz.openbmc_project.State.Host.HostState." 623 "DiagnosticMode") 624 { 625 aResp->res.jsonValue["PowerState"] = "On"; 626 aResp->res.jsonValue["Status"]["State"] = "InTest"; 627 } 628 else 629 { 630 aResp->res.jsonValue["PowerState"] = "Off"; 631 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 632 } 633 } 634 }, 635 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 636 "org.freedesktop.DBus.Properties", "Get", 637 "xyz.openbmc_project.State.Host", "CurrentHostState"); 638 } 639 640 /** 641 * @brief Traslates boot source DBUS property value to redfish. 642 * 643 * @param[in] dbusSource The boot source in DBUS speak. 644 * 645 * @return Returns as a string, the boot source in Redfish terms. If translation 646 * cannot be done, returns an empty string. 647 */ 648 static std::string dbusToRfBootSource(const std::string& dbusSource) 649 { 650 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 651 { 652 return "None"; 653 } 654 else if (dbusSource == 655 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 656 { 657 return "Hdd"; 658 } 659 else if (dbusSource == 660 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 661 { 662 return "Cd"; 663 } 664 else if (dbusSource == 665 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 666 { 667 return "Pxe"; 668 } 669 else if (dbusSource == 670 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 671 { 672 return "Usb"; 673 } 674 else 675 { 676 return ""; 677 } 678 } 679 680 /** 681 * @brief Traslates boot mode DBUS property value to redfish. 682 * 683 * @param[in] dbusMode The boot mode in DBUS speak. 684 * 685 * @return Returns as a string, the boot mode in Redfish terms. If translation 686 * cannot be done, returns an empty string. 687 */ 688 static std::string dbusToRfBootMode(const std::string& dbusMode) 689 { 690 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 691 { 692 return "None"; 693 } 694 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 695 { 696 return "Diags"; 697 } 698 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 699 { 700 return "BiosSetup"; 701 } 702 else 703 { 704 return ""; 705 } 706 } 707 708 /** 709 * @brief Traslates boot source from Redfish to the DBus boot paths. 710 * 711 * @param[in] rfSource The boot source in Redfish. 712 * @param[out] bootSource The DBus source 713 * @param[out] bootMode the DBus boot mode 714 * 715 * @return Integer error code. 716 */ 717 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp, 718 const std::string& rfSource, 719 std::string& bootSource, std::string& bootMode) 720 { 721 // The caller has initialized the bootSource and bootMode to: 722 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 723 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 724 // Only modify the bootSource/bootMode variable needed to achieve the 725 // desired boot action. 726 727 if (rfSource == "None") 728 { 729 return 0; 730 } 731 else if (rfSource == "Pxe") 732 { 733 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 734 } 735 else if (rfSource == "Hdd") 736 { 737 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 738 } 739 else if (rfSource == "Diags") 740 { 741 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 742 } 743 else if (rfSource == "Cd") 744 { 745 bootSource = 746 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 747 } 748 else if (rfSource == "BiosSetup") 749 { 750 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 751 } 752 else if (rfSource == "Usb") 753 { 754 bootSource = 755 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 756 } 757 else 758 { 759 BMCWEB_LOG_DEBUG << "Invalid property value for " 760 "BootSourceOverrideTarget: " 761 << bootSource; 762 messages::propertyValueNotInList(aResp->res, rfSource, 763 "BootSourceTargetOverride"); 764 return -1; 765 } 766 return 0; 767 } 768 769 /** 770 * @brief Retrieves boot mode over DBUS and fills out the response 771 * 772 * @param[in] aResp Shared pointer for generating response message. 773 * @param[in] bootDbusObj The dbus object to query for boot properties. 774 * 775 * @return None. 776 */ 777 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 778 std::string bootDbusObj) 779 { 780 crow::connections::systemBus->async_method_call( 781 [aResp](const boost::system::error_code ec, 782 const std::variant<std::string>& bootMode) { 783 if (ec) 784 { 785 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 786 messages::internalError(aResp->res); 787 return; 788 } 789 790 const std::string* bootModeStr = 791 std::get_if<std::string>(&bootMode); 792 793 if (!bootModeStr) 794 { 795 messages::internalError(aResp->res); 796 return; 797 } 798 799 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 800 801 // TODO (Santosh): Do we need to support override mode? 802 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 803 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 804 "AllowableValues"] = { 805 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 806 807 if (*bootModeStr != 808 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 809 { 810 auto rfMode = dbusToRfBootMode(*bootModeStr); 811 if (!rfMode.empty()) 812 { 813 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 814 rfMode; 815 } 816 } 817 818 // If the BootSourceOverrideTarget is still "None" at the end, 819 // reset the BootSourceOverrideEnabled to indicate that 820 // overrides are disabled 821 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 822 "None") 823 { 824 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 825 "Disabled"; 826 } 827 }, 828 "xyz.openbmc_project.Settings", bootDbusObj, 829 "org.freedesktop.DBus.Properties", "Get", 830 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 831 } 832 833 /** 834 * @brief Retrieves boot source over DBUS 835 * 836 * @param[in] aResp Shared pointer for generating response message. 837 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 838 * 839 * @return None. 840 */ 841 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 842 { 843 std::string bootDbusObj = 844 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 845 : "/xyz/openbmc_project/control/host0/boot"; 846 847 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 848 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 849 (oneTimeEnabled) ? "Once" : "Continuous"; 850 851 crow::connections::systemBus->async_method_call( 852 [aResp, bootDbusObj](const boost::system::error_code ec, 853 const std::variant<std::string>& bootSource) { 854 if (ec) 855 { 856 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 857 messages::internalError(aResp->res); 858 return; 859 } 860 861 const std::string* bootSourceStr = 862 std::get_if<std::string>(&bootSource); 863 864 if (!bootSourceStr) 865 { 866 messages::internalError(aResp->res); 867 return; 868 } 869 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 870 871 auto rfSource = dbusToRfBootSource(*bootSourceStr); 872 if (!rfSource.empty()) 873 { 874 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 875 rfSource; 876 } 877 }, 878 "xyz.openbmc_project.Settings", bootDbusObj, 879 "org.freedesktop.DBus.Properties", "Get", 880 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 881 getBootMode(std::move(aResp), std::move(bootDbusObj)); 882 } 883 884 /** 885 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 886 * get boot source and boot mode. 887 * 888 * @param[in] aResp Shared pointer for generating response message. 889 * 890 * @return None. 891 */ 892 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 893 { 894 BMCWEB_LOG_DEBUG << "Get boot information."; 895 896 crow::connections::systemBus->async_method_call( 897 [aResp](const boost::system::error_code ec, 898 const std::variant<bool>& oneTime) { 899 if (ec) 900 { 901 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 902 // not an error, don't have to have the interface 903 return; 904 } 905 906 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 907 908 if (!oneTimePtr) 909 { 910 messages::internalError(aResp->res); 911 return; 912 } 913 getBootSource(aResp, *oneTimePtr); 914 }, 915 "xyz.openbmc_project.Settings", 916 "/xyz/openbmc_project/control/host0/boot/one_time", 917 "org.freedesktop.DBus.Properties", "Get", 918 "xyz.openbmc_project.Object.Enable", "Enabled"); 919 } 920 921 /** 922 * @brief Retrieves 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 if (ec) 1395 { 1396 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1397 messages::internalError(aResp->res); 1398 return; 1399 } 1400 1401 const bool* provState = nullptr; 1402 const bool* lockState = nullptr; 1403 for (const std::pair<std::string, VariantType>& property : 1404 propertiesList) 1405 { 1406 if (property.first == "UfmProvisioned") 1407 { 1408 provState = std::get_if<bool>(&property.second); 1409 } 1410 else if (property.first == "UfmLocked") 1411 { 1412 lockState = std::get_if<bool>(&property.second); 1413 } 1414 } 1415 1416 if ((provState == nullptr) || (lockState == nullptr)) 1417 { 1418 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1419 messages::internalError(aResp->res); 1420 return; 1421 } 1422 1423 nlohmann::json& oemPFR = 1424 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1425 if (*provState == true) 1426 { 1427 if (*lockState == true) 1428 { 1429 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1430 } 1431 else 1432 { 1433 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1434 } 1435 } 1436 else 1437 { 1438 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1439 } 1440 }, 1441 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1442 "org.freedesktop.DBus.Properties", "GetAll", 1443 "xyz.openbmc_project.PFR.Attributes"); 1444 } 1445 #endif 1446 1447 /** 1448 * @brief Translates watchdog timeout action DBUS property value to redfish. 1449 * 1450 * @param[in] dbusAction The watchdog timeout action in D-BUS. 1451 * 1452 * @return Returns as a string, the timeout action in Redfish terms. If 1453 * translation cannot be done, returns an empty string. 1454 */ 1455 static std::string dbusToRfWatchdogAction(const std::string& dbusAction) 1456 { 1457 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 1458 { 1459 return "None"; 1460 } 1461 else if (dbusAction == 1462 "xyz.openbmc_project.State.Watchdog.Action.HardReset") 1463 { 1464 return "ResetSystem"; 1465 } 1466 else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 1467 { 1468 return "PowerDown"; 1469 } 1470 else if (dbusAction == 1471 "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 1472 { 1473 return "PowerCycle"; 1474 } 1475 1476 return ""; 1477 } 1478 1479 /** 1480 *@brief Translates timeout action from Redfish to DBUS property value. 1481 * 1482 *@param[in] rfAction The timeout action in Redfish. 1483 * 1484 *@return Returns as a string, the time_out action as expected by DBUS. 1485 *If translation cannot be done, returns an empty string. 1486 */ 1487 1488 static std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 1489 { 1490 if (rfAction == "None") 1491 { 1492 return "xyz.openbmc_project.State.Watchdog.Action.None"; 1493 } 1494 else if (rfAction == "PowerCycle") 1495 { 1496 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 1497 } 1498 else if (rfAction == "PowerDown") 1499 { 1500 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 1501 } 1502 else if (rfAction == "ResetSystem") 1503 { 1504 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 1505 } 1506 1507 return ""; 1508 } 1509 1510 /** 1511 * @brief Retrieves host watchdog timer properties over DBUS 1512 * 1513 * @param[in] aResp Shared pointer for completing asynchronous calls. 1514 * 1515 * @return None. 1516 */ 1517 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp) 1518 { 1519 BMCWEB_LOG_DEBUG << "Get host watchodg"; 1520 crow::connections::systemBus->async_method_call( 1521 [aResp](const boost::system::error_code ec, 1522 PropertiesType& properties) { 1523 if (ec) 1524 { 1525 // watchdog service is stopped 1526 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1527 return; 1528 } 1529 1530 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 1531 1532 nlohmann::json& hostWatchdogTimer = 1533 aResp->res.jsonValue["HostWatchdogTimer"]; 1534 1535 // watchdog service is running/enabled 1536 hostWatchdogTimer["Status"]["State"] = "Enabled"; 1537 1538 for (const auto& property : properties) 1539 { 1540 BMCWEB_LOG_DEBUG << "prop=" << property.first; 1541 if (property.first == "Enabled") 1542 { 1543 const bool* state = std::get_if<bool>(&property.second); 1544 1545 if (!state) 1546 { 1547 messages::internalError(aResp->res); 1548 continue; 1549 } 1550 1551 hostWatchdogTimer["FunctionEnabled"] = *state; 1552 } 1553 else if (property.first == "ExpireAction") 1554 { 1555 const std::string* s = 1556 std::get_if<std::string>(&property.second); 1557 if (!s) 1558 { 1559 messages::internalError(aResp->res); 1560 continue; 1561 } 1562 1563 std::string action = dbusToRfWatchdogAction(*s); 1564 if (action.empty()) 1565 { 1566 messages::internalError(aResp->res); 1567 continue; 1568 } 1569 hostWatchdogTimer["TimeoutAction"] = action; 1570 } 1571 } 1572 }, 1573 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 1574 "org.freedesktop.DBus.Properties", "GetAll", 1575 "xyz.openbmc_project.State.Watchdog"); 1576 } 1577 1578 /** 1579 * @brief Sets Host WatchDog Timer properties. 1580 * 1581 * @param[in] aResp Shared pointer for generating response message. 1582 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 1583 * RF request. 1584 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 1585 * 1586 * @return None. 1587 */ 1588 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp, 1589 const std::optional<bool> wdtEnable, 1590 const std::optional<std::string>& wdtTimeOutAction) 1591 { 1592 BMCWEB_LOG_DEBUG << "Set host watchdog"; 1593 1594 if (wdtTimeOutAction) 1595 { 1596 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 1597 // check if TimeOut Action is Valid 1598 if (wdtTimeOutActStr.empty()) 1599 { 1600 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 1601 << *wdtTimeOutAction; 1602 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 1603 "TimeoutAction"); 1604 return; 1605 } 1606 1607 crow::connections::systemBus->async_method_call( 1608 [aResp](const boost::system::error_code ec) { 1609 if (ec) 1610 { 1611 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1612 messages::internalError(aResp->res); 1613 return; 1614 } 1615 }, 1616 "xyz.openbmc_project.Watchdog", 1617 "/xyz/openbmc_project/watchdog/host0", 1618 "org.freedesktop.DBus.Properties", "Set", 1619 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 1620 std::variant<std::string>(wdtTimeOutActStr)); 1621 } 1622 1623 if (wdtEnable) 1624 { 1625 crow::connections::systemBus->async_method_call( 1626 [aResp](const boost::system::error_code ec) { 1627 if (ec) 1628 { 1629 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1630 messages::internalError(aResp->res); 1631 return; 1632 } 1633 }, 1634 "xyz.openbmc_project.Watchdog", 1635 "/xyz/openbmc_project/watchdog/host0", 1636 "org.freedesktop.DBus.Properties", "Set", 1637 "xyz.openbmc_project.State.Watchdog", "Enabled", 1638 std::variant<bool>(*wdtEnable)); 1639 } 1640 } 1641 1642 /** 1643 * SystemsCollection derived class for delivering ComputerSystems Collection 1644 * Schema 1645 */ 1646 class SystemsCollection : public Node 1647 { 1648 public: 1649 SystemsCollection(CrowApp& app) : Node(app, "/redfish/v1/Systems/") 1650 { 1651 entityPrivileges = { 1652 {boost::beast::http::verb::get, {{"Login"}}}, 1653 {boost::beast::http::verb::head, {{"Login"}}}, 1654 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1655 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1656 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1657 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1658 } 1659 1660 private: 1661 void doGet(crow::Response& res, const crow::Request& req, 1662 const std::vector<std::string>& params) override 1663 { 1664 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 1665 res.jsonValue["@odata.type"] = 1666 "#ComputerSystemCollection.ComputerSystemCollection"; 1667 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 1668 res.jsonValue["Name"] = "Computer System Collection"; 1669 1670 crow::connections::systemBus->async_method_call( 1671 [asyncResp](const boost::system::error_code ec, 1672 const std::variant<std::string>& hostName) { 1673 nlohmann::json& iface_array = 1674 asyncResp->res.jsonValue["Members"]; 1675 iface_array = nlohmann::json::array(); 1676 auto& count = asyncResp->res.jsonValue["Members@odata.count"]; 1677 count = 0; 1678 if (ec) 1679 { 1680 iface_array.push_back( 1681 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1682 count = iface_array.size(); 1683 return; 1684 } 1685 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 1686 iface_array.push_back( 1687 {{"@odata.id", "/redfish/v1/Systems/system"}}); 1688 iface_array.push_back( 1689 {{"@odata.id", "/redfish/v1/Systems/hypervisor"}}); 1690 count = iface_array.size(); 1691 }, 1692 "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi", 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(CrowApp& 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>& params) 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(CrowApp& 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& req, 1884 const std::vector<std::string>& params) 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 {"ResetType@Redfish.AllowableValues", 1908 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1909 "GracefulShutdown", "PowerCycle", "Nmi"}}}; 1910 1911 res.jsonValue["LogServices"] = { 1912 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1913 1914 res.jsonValue["Bios"] = { 1915 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 1916 1917 res.jsonValue["Links"]["ManagedBy"] = { 1918 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1919 1920 res.jsonValue["Status"] = { 1921 {"Health", "OK"}, 1922 {"State", "Enabled"}, 1923 }; 1924 auto asyncResp = std::make_shared<AsyncResp>(res); 1925 1926 constexpr const std::array<const char*, 4> inventoryForSystems = { 1927 "xyz.openbmc_project.Inventory.Item.Dimm", 1928 "xyz.openbmc_project.Inventory.Item.Cpu", 1929 "xyz.openbmc_project.Inventory.Item.Drive", 1930 "xyz.openbmc_project.Inventory.Item.StorageController"}; 1931 1932 auto health = std::make_shared<HealthPopulate>(asyncResp); 1933 crow::connections::systemBus->async_method_call( 1934 [health](const boost::system::error_code ec, 1935 std::vector<std::string>& resp) { 1936 if (ec) 1937 { 1938 // no inventory 1939 return; 1940 } 1941 1942 health->inventory = std::move(resp); 1943 }, 1944 "xyz.openbmc_project.ObjectMapper", 1945 "/xyz/openbmc_project/object_mapper", 1946 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 1947 int32_t(0), inventoryForSystems); 1948 1949 health->populate(); 1950 1951 getMainChassisId(asyncResp, [](const std::string& chassisId, 1952 std::shared_ptr<AsyncResp> aRsp) { 1953 aRsp->res.jsonValue["Links"]["Chassis"] = { 1954 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1955 }); 1956 1957 getIndicatorLedState(asyncResp); 1958 getComputerSystem(asyncResp, health); 1959 getHostState(asyncResp); 1960 getBootProperties(asyncResp); 1961 getPCIeDeviceList(asyncResp, "PCIeDevices"); 1962 getHostWatchdogTimer(asyncResp); 1963 getPowerRestorePolicy(asyncResp); 1964 getAutomaticRetry(asyncResp); 1965 getLastResetTime(asyncResp); 1966 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1967 getProvisioningStatus(asyncResp); 1968 #endif 1969 } 1970 1971 void doPatch(crow::Response& res, const crow::Request& req, 1972 const std::vector<std::string>& params) override 1973 { 1974 std::optional<std::string> indicatorLed; 1975 std::optional<nlohmann::json> bootProps; 1976 std::optional<nlohmann::json> wdtTimerProps; 1977 std::optional<std::string> powerRestorePolicy; 1978 auto asyncResp = std::make_shared<AsyncResp>(res); 1979 1980 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1981 bootProps, "WatchdogTimer", wdtTimerProps, 1982 "PowerRestorePolicy", powerRestorePolicy)) 1983 { 1984 return; 1985 } 1986 1987 res.result(boost::beast::http::status::no_content); 1988 1989 if (wdtTimerProps) 1990 { 1991 std::optional<bool> wdtEnable; 1992 std::optional<std::string> wdtTimeOutAction; 1993 1994 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 1995 "FunctionEnabled", wdtEnable, 1996 "TimeoutAction", wdtTimeOutAction)) 1997 { 1998 return; 1999 } 2000 setWDTProperties(asyncResp, std::move(wdtEnable), 2001 std::move(wdtTimeOutAction)); 2002 } 2003 2004 if (bootProps) 2005 { 2006 std::optional<std::string> bootSource; 2007 std::optional<std::string> bootEnable; 2008 std::optional<std::string> automaticRetryConfig; 2009 2010 if (!json_util::readJson( 2011 *bootProps, asyncResp->res, "BootSourceOverrideTarget", 2012 bootSource, "BootSourceOverrideEnabled", bootEnable, 2013 "AutomaticRetryConfig", automaticRetryConfig)) 2014 { 2015 return; 2016 } 2017 if (bootSource || bootEnable) 2018 { 2019 setBootSourceProperties(asyncResp, std::move(bootSource), 2020 std::move(bootEnable)); 2021 } 2022 if (automaticRetryConfig) 2023 { 2024 setAutomaticRetry(asyncResp, std::move(*automaticRetryConfig)); 2025 } 2026 } 2027 2028 if (indicatorLed) 2029 { 2030 setIndicatorLedState(asyncResp, std::move(*indicatorLed)); 2031 } 2032 2033 if (powerRestorePolicy) 2034 { 2035 setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy)); 2036 } 2037 } 2038 }; 2039 } // namespace redfish 2040