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 <app.hpp> 24 #include <boost/container/flat_map.hpp> 25 #include <registries/privilege_registry.hpp> 26 #include <utils/fw_utils.hpp> 27 #include <utils/json_utils.hpp> 28 29 #include <variant> 30 31 namespace redfish 32 { 33 34 /** 35 * @brief Updates the Functional State of DIMMs 36 * 37 * @param[in] aResp Shared pointer for completing asynchronous calls 38 * @param[in] dimmState Dimm's Functional state, true/false 39 * 40 * @return None. 41 */ 42 inline void 43 updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 44 const std::variant<bool>& dimmState) 45 { 46 const bool* isDimmFunctional = std::get_if<bool>(&dimmState); 47 if (isDimmFunctional == nullptr) 48 { 49 messages::internalError(aResp->res); 50 return; 51 } 52 BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional; 53 54 // Set it as Enabled if at least one DIMM is functional 55 // Update STATE only if previous State was DISABLED and current Dimm is 56 // ENABLED. 57 nlohmann::json& prevMemSummary = 58 aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; 59 if (prevMemSummary == "Disabled") 60 { 61 if (*isDimmFunctional == true) 62 { 63 aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 64 "Enabled"; 65 } 66 } 67 } 68 69 /* 70 * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState 71 * 72 * @param[in] aResp Shared pointer for completing asynchronous calls 73 * @param[in] cpuPresenceState CPU present or not 74 * 75 * @return None. 76 */ 77 inline void 78 modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 79 const std::variant<bool>& cpuPresenceState) 80 { 81 const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState); 82 83 if (isCpuPresent == nullptr) 84 { 85 messages::internalError(aResp->res); 86 return; 87 } 88 BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent; 89 90 if (*isCpuPresent == true) 91 { 92 nlohmann::json& procCount = 93 aResp->res.jsonValue["ProcessorSummary"]["Count"]; 94 auto procCountPtr = 95 procCount.get_ptr<nlohmann::json::number_integer_t*>(); 96 if (procCountPtr != nullptr) 97 { 98 // shouldn't be possible to be nullptr 99 *procCountPtr += 1; 100 } 101 } 102 } 103 104 /* 105 * @brief Update "ProcessorSummary" "Status" "State" based on 106 * CPU Functional State 107 * 108 * @param[in] aResp Shared pointer for completing asynchronous calls 109 * @param[in] cpuFunctionalState is CPU functional true/false 110 * 111 * @return None. 112 */ 113 inline void 114 modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 115 const std::variant<bool>& cpuFunctionalState) 116 { 117 const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState); 118 119 if (isCpuFunctional == nullptr) 120 { 121 messages::internalError(aResp->res); 122 return; 123 } 124 BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional; 125 126 nlohmann::json& prevProcState = 127 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; 128 129 // Set it as Enabled if at least one CPU is functional 130 // Update STATE only if previous State was Non_Functional and current CPU is 131 // Functional. 132 if (prevProcState == "Disabled") 133 { 134 if (*isCpuFunctional == true) 135 { 136 aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 137 "Enabled"; 138 } 139 } 140 } 141 142 /* 143 * @brief Retrieves computer system properties over dbus 144 * 145 * @param[in] aResp Shared pointer for completing asynchronous calls 146 * @param[in] systemHealth Shared HealthPopulate pointer 147 * 148 * @return None. 149 */ 150 inline void 151 getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 152 const std::shared_ptr<HealthPopulate>& systemHealth) 153 { 154 BMCWEB_LOG_DEBUG << "Get available system components."; 155 156 crow::connections::systemBus->async_method_call( 157 [aResp, systemHealth]( 158 const boost::system::error_code ec, 159 const std::vector<std::pair< 160 std::string, 161 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 162 subtree) { 163 if (ec) 164 { 165 BMCWEB_LOG_DEBUG << "DBUS response error"; 166 messages::internalError(aResp->res); 167 return; 168 } 169 // Iterate over all retrieved ObjectPaths. 170 for (const std::pair<std::string, 171 std::vector<std::pair< 172 std::string, std::vector<std::string>>>>& 173 object : subtree) 174 { 175 const std::string& path = object.first; 176 BMCWEB_LOG_DEBUG << "Got path: " << path; 177 const std::vector< 178 std::pair<std::string, std::vector<std::string>>>& 179 connectionNames = object.second; 180 if (connectionNames.size() < 1) 181 { 182 continue; 183 } 184 185 auto memoryHealth = std::make_shared<HealthPopulate>( 186 aResp, aResp->res.jsonValue["MemorySummary"]["Status"]); 187 188 auto cpuHealth = std::make_shared<HealthPopulate>( 189 aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]); 190 191 systemHealth->children.emplace_back(memoryHealth); 192 systemHealth->children.emplace_back(cpuHealth); 193 194 // This is not system, so check if it's cpu, dimm, UUID or 195 // BiosVer 196 for (const auto& connection : connectionNames) 197 { 198 for (const auto& interfaceName : connection.second) 199 { 200 if (interfaceName == 201 "xyz.openbmc_project.Inventory.Item.Dimm") 202 { 203 BMCWEB_LOG_DEBUG 204 << "Found Dimm, now get its properties."; 205 206 crow::connections::systemBus->async_method_call( 207 [aResp, service{connection.first}, 208 path](const boost::system::error_code ec2, 209 const std::vector< 210 std::pair<std::string, VariantType>>& 211 properties) { 212 if (ec2) 213 { 214 BMCWEB_LOG_ERROR 215 << "DBUS response error " << ec2; 216 messages::internalError(aResp->res); 217 return; 218 } 219 BMCWEB_LOG_DEBUG << "Got " 220 << properties.size() 221 << " Dimm properties."; 222 223 if (properties.size() > 0) 224 { 225 for (const std::pair<std::string, 226 VariantType>& 227 property : properties) 228 { 229 if (property.first != 230 "MemorySizeInKB") 231 { 232 continue; 233 } 234 const uint32_t* value = 235 std::get_if<uint32_t>( 236 &property.second); 237 if (value == nullptr) 238 { 239 BMCWEB_LOG_DEBUG 240 << "Find incorrect type of " 241 "MemorySize"; 242 continue; 243 } 244 nlohmann::json& totalMemory = 245 aResp->res 246 .jsonValue["MemorySummar" 247 "y"] 248 ["TotalSystemMe" 249 "moryGiB"]; 250 uint64_t* preValue = 251 totalMemory 252 .get_ptr<uint64_t*>(); 253 if (preValue == nullptr) 254 { 255 continue; 256 } 257 aResp->res 258 .jsonValue["MemorySummary"] 259 ["TotalSystemMemoryGi" 260 "B"] = 261 *value / (1024 * 1024) + 262 *preValue; 263 aResp->res 264 .jsonValue["MemorySummary"] 265 ["Status"]["State"] = 266 "Enabled"; 267 } 268 } 269 else 270 { 271 auto getDimmProperties = 272 [aResp]( 273 const boost::system::error_code 274 ec3, 275 const std::variant<bool>& 276 dimmState) { 277 if (ec3) 278 { 279 BMCWEB_LOG_ERROR 280 << "DBUS response " 281 "error " 282 << ec3; 283 return; 284 } 285 updateDimmProperties(aResp, 286 dimmState); 287 }; 288 crow::connections::systemBus 289 ->async_method_call( 290 std::move(getDimmProperties), 291 service, path, 292 "org.freedesktop.DBus." 293 "Properties", 294 "Get", 295 "xyz.openbmc_project.State." 296 "Decorator.OperationalStatus", 297 "Functional"); 298 } 299 }, 300 connection.first, path, 301 "org.freedesktop.DBus.Properties", "GetAll", 302 "xyz.openbmc_project.Inventory.Item.Dimm"); 303 304 memoryHealth->inventory.emplace_back(path); 305 } 306 else if (interfaceName == 307 "xyz.openbmc_project.Inventory.Item.Cpu") 308 { 309 BMCWEB_LOG_DEBUG 310 << "Found Cpu, now get its properties."; 311 312 crow::connections::systemBus->async_method_call( 313 [aResp, service{connection.first}, 314 path](const boost::system::error_code ec2, 315 const std::vector< 316 std::pair<std::string, VariantType>>& 317 properties) { 318 if (ec2) 319 { 320 BMCWEB_LOG_ERROR 321 << "DBUS response error " << ec2; 322 messages::internalError(aResp->res); 323 return; 324 } 325 BMCWEB_LOG_DEBUG << "Got " 326 << properties.size() 327 << " Cpu properties."; 328 329 if (properties.size() > 0) 330 { 331 const uint64_t* processorId = nullptr; 332 const std::string* procFamily = nullptr; 333 nlohmann::json& procSummary = 334 aResp->res.jsonValue["ProcessorSumm" 335 "ary"]; 336 nlohmann::json& procCount = 337 procSummary["Count"]; 338 339 auto procCountPtr = procCount.get_ptr< 340 nlohmann::json:: 341 number_integer_t*>(); 342 if (procCountPtr == nullptr) 343 { 344 messages::internalError(aResp->res); 345 return; 346 } 347 for (const auto& property : properties) 348 { 349 350 if (property.first == "Id") 351 { 352 processorId = 353 std::get_if<uint64_t>( 354 &property.second); 355 if (nullptr != procFamily) 356 { 357 break; 358 } 359 continue; 360 } 361 362 if (property.first == "Family") 363 { 364 procFamily = 365 std::get_if<std::string>( 366 &property.second); 367 if (nullptr != processorId) 368 { 369 break; 370 } 371 continue; 372 } 373 } 374 375 if (procFamily != nullptr && 376 processorId != nullptr) 377 { 378 if (procCountPtr != nullptr && 379 *processorId != 0) 380 { 381 *procCountPtr += 1; 382 procSummary["Status"]["State"] = 383 "Enabled"; 384 385 procSummary["Model"] = 386 *procFamily; 387 } 388 } 389 } 390 else 391 { 392 auto getCpuPresenceState = 393 [aResp]( 394 const boost::system::error_code 395 ec3, 396 const std::variant<bool>& 397 cpuPresenceCheck) { 398 if (ec3) 399 { 400 BMCWEB_LOG_ERROR 401 << "DBUS response " 402 "error " 403 << ec3; 404 return; 405 } 406 modifyCpuPresenceState( 407 aResp, cpuPresenceCheck); 408 }; 409 410 auto getCpuFunctionalState = 411 [aResp]( 412 const boost::system::error_code 413 ec3, 414 const std::variant<bool>& 415 cpuFunctionalCheck) { 416 if (ec3) 417 { 418 BMCWEB_LOG_ERROR 419 << "DBUS response " 420 "error " 421 << ec3; 422 return; 423 } 424 modifyCpuFunctionalState( 425 aResp, cpuFunctionalCheck); 426 }; 427 // Get the Presence of CPU 428 crow::connections::systemBus 429 ->async_method_call( 430 std::move(getCpuPresenceState), 431 service, path, 432 "org.freedesktop.DBus." 433 "Properties", 434 "Get", 435 "xyz.openbmc_project.Inventory." 436 "Item", 437 "Present"); 438 439 // Get the Functional State 440 crow::connections::systemBus 441 ->async_method_call( 442 std::move( 443 getCpuFunctionalState), 444 service, path, 445 "org.freedesktop.DBus." 446 "Properties", 447 "Get", 448 "xyz.openbmc_project.State." 449 "Decorator." 450 "OperationalStatus", 451 "Functional"); 452 453 // Get the MODEL from 454 // xyz.openbmc_project.Inventory.Decorator.Asset 455 // support it later as Model is Empty 456 // currently. 457 } 458 }, 459 connection.first, path, 460 "org.freedesktop.DBus.Properties", "GetAll", 461 "xyz.openbmc_project.Inventory.Item.Cpu"); 462 463 cpuHealth->inventory.emplace_back(path); 464 } 465 else if (interfaceName == 466 "xyz.openbmc_project.Common.UUID") 467 { 468 BMCWEB_LOG_DEBUG 469 << "Found UUID, now get its properties."; 470 crow::connections::systemBus->async_method_call( 471 [aResp]( 472 const boost::system::error_code ec3, 473 const std::vector< 474 std::pair<std::string, VariantType>>& 475 properties) { 476 if (ec3) 477 { 478 BMCWEB_LOG_DEBUG 479 << "DBUS response error " << ec3; 480 messages::internalError(aResp->res); 481 return; 482 } 483 BMCWEB_LOG_DEBUG << "Got " 484 << properties.size() 485 << " UUID properties."; 486 for (const std::pair<std::string, 487 VariantType>& 488 property : properties) 489 { 490 if (property.first == "UUID") 491 { 492 const std::string* value = 493 std::get_if<std::string>( 494 &property.second); 495 496 if (value != nullptr) 497 { 498 std::string valueStr = *value; 499 if (valueStr.size() == 32) 500 { 501 valueStr.insert(8, 1, '-'); 502 valueStr.insert(13, 1, '-'); 503 valueStr.insert(18, 1, '-'); 504 valueStr.insert(23, 1, '-'); 505 } 506 BMCWEB_LOG_DEBUG << "UUID = " 507 << valueStr; 508 aResp->res.jsonValue["UUID"] = 509 valueStr; 510 } 511 } 512 } 513 }, 514 connection.first, path, 515 "org.freedesktop.DBus.Properties", "GetAll", 516 "xyz.openbmc_project.Common.UUID"); 517 } 518 else if (interfaceName == 519 "xyz.openbmc_project.Inventory.Item.System") 520 { 521 crow::connections::systemBus->async_method_call( 522 [aResp]( 523 const boost::system::error_code ec2, 524 const std::vector< 525 std::pair<std::string, VariantType>>& 526 propertiesList) { 527 if (ec2) 528 { 529 // doesn't have to include this 530 // interface 531 return; 532 } 533 BMCWEB_LOG_DEBUG 534 << "Got " << propertiesList.size() 535 << " properties for system"; 536 for (const std::pair<std::string, 537 VariantType>& 538 property : propertiesList) 539 { 540 const std::string& propertyName = 541 property.first; 542 if ((propertyName == "PartNumber") || 543 (propertyName == "SerialNumber") || 544 (propertyName == "Manufacturer") || 545 (propertyName == "Model") || 546 (propertyName == "SubModel")) 547 { 548 const std::string* value = 549 std::get_if<std::string>( 550 &property.second); 551 if (value != nullptr) 552 { 553 aResp->res 554 .jsonValue[propertyName] = 555 *value; 556 } 557 } 558 } 559 560 // Grab the bios version 561 fw_util::populateFirmwareInformation( 562 aResp, fw_util::biosPurpose, 563 "BiosVersion", false); 564 }, 565 connection.first, path, 566 "org.freedesktop.DBus.Properties", "GetAll", 567 "xyz.openbmc_project.Inventory.Decorator." 568 "Asset"); 569 570 crow::connections::systemBus->async_method_call( 571 [aResp]( 572 const boost::system::error_code ec2, 573 const std::variant<std::string>& property) { 574 if (ec2) 575 { 576 // doesn't have to include this 577 // interface 578 return; 579 } 580 581 const std::string* value = 582 std::get_if<std::string>(&property); 583 if (value != nullptr) 584 { 585 aResp->res.jsonValue["AssetTag"] = 586 *value; 587 } 588 }, 589 connection.first, path, 590 "org.freedesktop.DBus.Properties", "Get", 591 "xyz.openbmc_project.Inventory.Decorator." 592 "AssetTag", 593 "AssetTag"); 594 } 595 } 596 } 597 } 598 }, 599 "xyz.openbmc_project.ObjectMapper", 600 "/xyz/openbmc_project/object_mapper", 601 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 602 "/xyz/openbmc_project/inventory", int32_t(0), 603 std::array<const char*, 5>{ 604 "xyz.openbmc_project.Inventory.Decorator.Asset", 605 "xyz.openbmc_project.Inventory.Item.Cpu", 606 "xyz.openbmc_project.Inventory.Item.Dimm", 607 "xyz.openbmc_project.Inventory.Item.System", 608 "xyz.openbmc_project.Common.UUID", 609 }); 610 } 611 612 /** 613 * @brief Retrieves host state properties over dbus 614 * 615 * @param[in] aResp Shared pointer for completing asynchronous calls. 616 * 617 * @return None. 618 */ 619 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 620 { 621 BMCWEB_LOG_DEBUG << "Get host information."; 622 crow::connections::systemBus->async_method_call( 623 [aResp](const boost::system::error_code ec, 624 const std::variant<std::string>& hostState) { 625 if (ec) 626 { 627 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 628 messages::internalError(aResp->res); 629 return; 630 } 631 632 const std::string* s = std::get_if<std::string>(&hostState); 633 BMCWEB_LOG_DEBUG << "Host state: " << *s; 634 if (s != nullptr) 635 { 636 // Verify Host State 637 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 638 { 639 aResp->res.jsonValue["PowerState"] = "On"; 640 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 641 } 642 else if (*s == "xyz.openbmc_project.State.Host.HostState." 643 "Quiesced") 644 { 645 aResp->res.jsonValue["PowerState"] = "On"; 646 aResp->res.jsonValue["Status"]["State"] = "Quiesced"; 647 } 648 else if (*s == "xyz.openbmc_project.State.Host.HostState." 649 "DiagnosticMode") 650 { 651 aResp->res.jsonValue["PowerState"] = "On"; 652 aResp->res.jsonValue["Status"]["State"] = "InTest"; 653 } 654 else if (*s == "xyz.openbmc_project.State.Host.HostState." 655 "TransitioningToRunning") 656 { 657 aResp->res.jsonValue["PowerState"] = "PoweringOn"; 658 aResp->res.jsonValue["Status"]["State"] = "Starting"; 659 } 660 else if (*s == "xyz.openbmc_project.State.Host.HostState." 661 "TransitioningToOff") 662 { 663 aResp->res.jsonValue["PowerState"] = "PoweringOff"; 664 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 665 } 666 else 667 { 668 aResp->res.jsonValue["PowerState"] = "Off"; 669 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 670 } 671 } 672 }, 673 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 674 "org.freedesktop.DBus.Properties", "Get", 675 "xyz.openbmc_project.State.Host", "CurrentHostState"); 676 } 677 678 /** 679 * @brief Translates boot source DBUS property value to redfish. 680 * 681 * @param[in] dbusSource The boot source in DBUS speak. 682 * 683 * @return Returns as a string, the boot source in Redfish terms. If translation 684 * cannot be done, returns an empty string. 685 */ 686 inline std::string dbusToRfBootSource(const std::string& dbusSource) 687 { 688 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 689 { 690 return "None"; 691 } 692 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 693 { 694 return "Hdd"; 695 } 696 if (dbusSource == 697 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 698 { 699 return "Cd"; 700 } 701 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 702 { 703 return "Pxe"; 704 } 705 if (dbusSource == 706 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") 707 { 708 return "Usb"; 709 } 710 return ""; 711 } 712 713 /** 714 * @brief Translates boot mode DBUS property value to redfish. 715 * 716 * @param[in] dbusMode The boot mode in DBUS speak. 717 * 718 * @return Returns as a string, the boot mode in Redfish terms. If translation 719 * cannot be done, returns an empty string. 720 */ 721 inline std::string dbusToRfBootMode(const std::string& dbusMode) 722 { 723 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 724 { 725 return "None"; 726 } 727 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 728 { 729 return "Diags"; 730 } 731 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 732 { 733 return "BiosSetup"; 734 } 735 return ""; 736 } 737 738 /** 739 * @brief Translates boot source from Redfish to the DBus boot paths. 740 * 741 * @param[in] rfSource The boot source in Redfish. 742 * @param[out] bootSource The DBus source 743 * @param[out] bootMode the DBus boot mode 744 * 745 * @return Integer error code. 746 */ 747 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 748 const std::string& rfSource, 749 std::string& bootSource, std::string& bootMode) 750 { 751 // The caller has initialized the bootSource and bootMode to: 752 // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 753 // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 754 // Only modify the bootSource/bootMode variable needed to achieve the 755 // desired boot action. 756 757 if (rfSource == "None") 758 { 759 return 0; 760 } 761 if (rfSource == "Pxe") 762 { 763 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 764 } 765 else if (rfSource == "Hdd") 766 { 767 bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 768 } 769 else if (rfSource == "Diags") 770 { 771 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 772 } 773 else if (rfSource == "Cd") 774 { 775 bootSource = 776 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 777 } 778 else if (rfSource == "BiosSetup") 779 { 780 bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 781 } 782 else if (rfSource == "Usb") 783 { 784 bootSource = 785 "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; 786 } 787 else 788 { 789 BMCWEB_LOG_DEBUG << "Invalid property value for " 790 "BootSourceOverrideTarget: " 791 << bootSource; 792 messages::propertyValueNotInList(aResp->res, rfSource, 793 "BootSourceTargetOverride"); 794 return -1; 795 } 796 return 0; 797 } 798 799 /** 800 * @brief Retrieves boot progress of the system 801 * 802 * @param[in] aResp Shared pointer for generating response message. 803 * 804 * @return None. 805 */ 806 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 807 { 808 crow::connections::systemBus->async_method_call( 809 [aResp](const boost::system::error_code ec, 810 const std::variant<std::string>& bootProgress) { 811 if (ec) 812 { 813 // BootProgress is an optional object so just do nothing if 814 // not found 815 return; 816 } 817 818 const std::string* bootProgressStr = 819 std::get_if<std::string>(&bootProgress); 820 821 if (!bootProgressStr) 822 { 823 // Interface implemented but property not found, return error 824 // for that 825 messages::internalError(aResp->res); 826 return; 827 } 828 829 BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr; 830 831 // Now convert the D-Bus BootProgress to the appropriate Redfish 832 // enum 833 std::string rfBpLastState = "None"; 834 if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress." 835 "ProgressStages.Unspecified") 836 { 837 rfBpLastState = "None"; 838 } 839 else if (*bootProgressStr == 840 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 841 "PrimaryProcInit") 842 { 843 rfBpLastState = "PrimaryProcessorInitializationStarted"; 844 } 845 else if (*bootProgressStr == 846 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 847 "BusInit") 848 { 849 rfBpLastState = "BusInitializationStarted"; 850 } 851 else if (*bootProgressStr == 852 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 853 "MemoryInit") 854 { 855 rfBpLastState = "MemoryInitializationStarted"; 856 } 857 else if (*bootProgressStr == 858 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 859 "SecondaryProcInit") 860 { 861 rfBpLastState = "SecondaryProcessorInitializationStarted"; 862 } 863 else if (*bootProgressStr == 864 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 865 "PCIInit") 866 { 867 rfBpLastState = "PCIResourceConfigStarted"; 868 } 869 else if (*bootProgressStr == 870 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 871 "SystemInitComplete") 872 { 873 rfBpLastState = "SystemHardwareInitializationComplete"; 874 } 875 else if (*bootProgressStr == 876 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 877 "OSStart") 878 { 879 rfBpLastState = "OSBootStarted"; 880 } 881 else if (*bootProgressStr == 882 "xyz.openbmc_project.State.Boot.Progress.ProgressStages." 883 "OSRunning") 884 { 885 rfBpLastState = "OSRunning"; 886 } 887 else 888 { 889 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " 890 << *bootProgressStr; 891 // Just return the default 892 } 893 894 aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState; 895 }, 896 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 897 "org.freedesktop.DBus.Properties", "Get", 898 "xyz.openbmc_project.State.Boot.Progress", "BootProgress"); 899 } 900 901 /** 902 * @brief Retrieves boot mode over DBUS and fills out the response 903 * 904 * @param[in] aResp Shared pointer for generating response message. 905 * @param[in] bootDbusObj The dbus object to query for boot properties. 906 * 907 * @return None. 908 */ 909 inline void getBootMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 910 const std::string& bootDbusObj) 911 { 912 crow::connections::systemBus->async_method_call( 913 [aResp](const boost::system::error_code ec, 914 const std::variant<std::string>& bootMode) { 915 if (ec) 916 { 917 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 918 messages::internalError(aResp->res); 919 return; 920 } 921 922 const std::string* bootModeStr = 923 std::get_if<std::string>(&bootMode); 924 925 if (!bootModeStr) 926 { 927 messages::internalError(aResp->res); 928 return; 929 } 930 931 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 932 933 // TODO (Santosh): Do we need to support override mode? 934 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 935 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 936 "AllowableValues"] = { 937 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; 938 939 if (*bootModeStr != 940 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 941 { 942 auto rfMode = dbusToRfBootMode(*bootModeStr); 943 if (!rfMode.empty()) 944 { 945 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 946 rfMode; 947 } 948 } 949 950 // If the BootSourceOverrideTarget is still "None" at the end, 951 // reset the BootSourceOverrideEnabled to indicate that 952 // overrides are disabled 953 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 954 "None") 955 { 956 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 957 "Disabled"; 958 } 959 }, 960 "xyz.openbmc_project.Settings", bootDbusObj, 961 "org.freedesktop.DBus.Properties", "Get", 962 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 963 } 964 965 /** 966 * @brief Retrieves boot source over DBUS 967 * 968 * @param[in] aResp Shared pointer for generating response message. 969 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 970 * 971 * @return None. 972 */ 973 inline void getBootSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 974 bool oneTimeEnabled) 975 { 976 std::string bootDbusObj = 977 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 978 : "/xyz/openbmc_project/control/host0/boot"; 979 980 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 981 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 982 (oneTimeEnabled) ? "Once" : "Continuous"; 983 984 crow::connections::systemBus->async_method_call( 985 [aResp, bootDbusObj](const boost::system::error_code ec, 986 const std::variant<std::string>& bootSource) { 987 if (ec) 988 { 989 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 990 messages::internalError(aResp->res); 991 return; 992 } 993 994 const std::string* bootSourceStr = 995 std::get_if<std::string>(&bootSource); 996 997 if (!bootSourceStr) 998 { 999 messages::internalError(aResp->res); 1000 return; 1001 } 1002 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 1003 1004 auto rfSource = dbusToRfBootSource(*bootSourceStr); 1005 if (!rfSource.empty()) 1006 { 1007 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 1008 rfSource; 1009 } 1010 }, 1011 "xyz.openbmc_project.Settings", bootDbusObj, 1012 "org.freedesktop.DBus.Properties", "Get", 1013 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 1014 getBootMode(aResp, bootDbusObj); 1015 } 1016 1017 /** 1018 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1019 * get boot source and boot mode. 1020 * 1021 * @param[in] aResp Shared pointer for generating response message. 1022 * 1023 * @return None. 1024 */ 1025 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1026 { 1027 BMCWEB_LOG_DEBUG << "Get boot information."; 1028 1029 crow::connections::systemBus->async_method_call( 1030 [aResp](const boost::system::error_code ec, 1031 const std::variant<bool>& oneTime) { 1032 if (ec) 1033 { 1034 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1035 // not an error, don't have to have the interface 1036 return; 1037 } 1038 1039 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1040 1041 if (!oneTimePtr) 1042 { 1043 messages::internalError(aResp->res); 1044 return; 1045 } 1046 getBootSource(aResp, *oneTimePtr); 1047 }, 1048 "xyz.openbmc_project.Settings", 1049 "/xyz/openbmc_project/control/host0/boot/one_time", 1050 "org.freedesktop.DBus.Properties", "Get", 1051 "xyz.openbmc_project.Object.Enable", "Enabled"); 1052 } 1053 1054 /** 1055 * @brief Retrieves the Last Reset Time 1056 * 1057 * "Reset" is an overloaded term in Redfish, "Reset" includes power on 1058 * and power off. Even though this is the "system" Redfish object look at the 1059 * chassis D-Bus interface for the LastStateChangeTime since this has the 1060 * last power operation time. 1061 * 1062 * @param[in] aResp Shared pointer for generating response message. 1063 * 1064 * @return None. 1065 */ 1066 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1067 { 1068 BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; 1069 1070 crow::connections::systemBus->async_method_call( 1071 [aResp](const boost::system::error_code ec, 1072 std::variant<uint64_t>& lastResetTime) { 1073 if (ec) 1074 { 1075 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1076 return; 1077 } 1078 1079 const uint64_t* lastResetTimePtr = 1080 std::get_if<uint64_t>(&lastResetTime); 1081 1082 if (!lastResetTimePtr) 1083 { 1084 messages::internalError(aResp->res); 1085 return; 1086 } 1087 // LastStateChangeTime is epoch time, in milliseconds 1088 // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 1089 time_t lastResetTimeStamp = 1090 static_cast<time_t>(*lastResetTimePtr / 1000); 1091 1092 // Convert to ISO 8601 standard 1093 aResp->res.jsonValue["LastResetTime"] = 1094 crow::utility::getDateTime(lastResetTimeStamp); 1095 }, 1096 "xyz.openbmc_project.State.Chassis", 1097 "/xyz/openbmc_project/state/chassis0", 1098 "org.freedesktop.DBus.Properties", "Get", 1099 "xyz.openbmc_project.State.Chassis", "LastStateChangeTime"); 1100 } 1101 1102 /** 1103 * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. 1104 * 1105 * @param[in] aResp Shared pointer for generating response message. 1106 * 1107 * @return None. 1108 */ 1109 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1110 { 1111 BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; 1112 1113 crow::connections::systemBus->async_method_call( 1114 [aResp](const boost::system::error_code ec, 1115 std::variant<bool>& autoRebootEnabled) { 1116 if (ec) 1117 { 1118 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 1119 return; 1120 } 1121 1122 const bool* autoRebootEnabledPtr = 1123 std::get_if<bool>(&autoRebootEnabled); 1124 1125 if (!autoRebootEnabledPtr) 1126 { 1127 messages::internalError(aResp->res); 1128 return; 1129 } 1130 1131 BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr; 1132 if (*autoRebootEnabledPtr == true) 1133 { 1134 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1135 "RetryAttempts"; 1136 // If AutomaticRetry (AutoReboot) is enabled see how many 1137 // attempts are left 1138 crow::connections::systemBus->async_method_call( 1139 [aResp](const boost::system::error_code ec2, 1140 std::variant<uint32_t>& autoRebootAttemptsLeft) { 1141 if (ec2) 1142 { 1143 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; 1144 return; 1145 } 1146 1147 const uint32_t* autoRebootAttemptsLeftPtr = 1148 std::get_if<uint32_t>(&autoRebootAttemptsLeft); 1149 1150 if (!autoRebootAttemptsLeftPtr) 1151 { 1152 messages::internalError(aResp->res); 1153 return; 1154 } 1155 1156 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " 1157 << *autoRebootAttemptsLeftPtr; 1158 1159 aResp->res 1160 .jsonValue["Boot"] 1161 ["RemainingAutomaticRetryAttempts"] = 1162 *autoRebootAttemptsLeftPtr; 1163 }, 1164 "xyz.openbmc_project.State.Host", 1165 "/xyz/openbmc_project/state/host0", 1166 "org.freedesktop.DBus.Properties", "Get", 1167 "xyz.openbmc_project.Control.Boot.RebootAttempts", 1168 "AttemptsLeft"); 1169 } 1170 else 1171 { 1172 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = 1173 "Disabled"; 1174 } 1175 1176 // Not on D-Bus. Hardcoded here: 1177 // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 1178 aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; 1179 1180 // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, 1181 // and RetryAttempts. OpenBMC only supports Disabled and 1182 // RetryAttempts. 1183 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish." 1184 "AllowableValues"] = {"Disabled", 1185 "RetryAttempts"}; 1186 }, 1187 "xyz.openbmc_project.Settings", 1188 "/xyz/openbmc_project/control/host0/auto_reboot", 1189 "org.freedesktop.DBus.Properties", "Get", 1190 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot"); 1191 } 1192 1193 /** 1194 * @brief Retrieves power restore policy over DBUS. 1195 * 1196 * @param[in] aResp Shared pointer for generating response message. 1197 * 1198 * @return None. 1199 */ 1200 inline void 1201 getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1202 { 1203 BMCWEB_LOG_DEBUG << "Get power restore policy"; 1204 1205 crow::connections::systemBus->async_method_call( 1206 [aResp](const boost::system::error_code ec, 1207 std::variant<std::string>& policy) { 1208 if (ec) 1209 { 1210 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1211 return; 1212 } 1213 1214 const boost::container::flat_map<std::string, std::string> 1215 policyMaps = { 1216 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1217 "AlwaysOn", 1218 "AlwaysOn"}, 1219 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1220 "AlwaysOff", 1221 "AlwaysOff"}, 1222 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1223 "Restore", 1224 "LastState"}}; 1225 1226 const std::string* policyPtr = std::get_if<std::string>(&policy); 1227 1228 if (!policyPtr) 1229 { 1230 messages::internalError(aResp->res); 1231 return; 1232 } 1233 1234 auto policyMapsIt = policyMaps.find(*policyPtr); 1235 if (policyMapsIt == policyMaps.end()) 1236 { 1237 messages::internalError(aResp->res); 1238 return; 1239 } 1240 1241 aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; 1242 }, 1243 "xyz.openbmc_project.Settings", 1244 "/xyz/openbmc_project/control/host0/power_restore_policy", 1245 "org.freedesktop.DBus.Properties", "Get", 1246 "xyz.openbmc_project.Control.Power.RestorePolicy", 1247 "PowerRestorePolicy"); 1248 } 1249 1250 /** 1251 * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not 1252 * TPM is required for booting the host. 1253 * 1254 * @param[in] aResp Shared pointer for generating response message. 1255 * 1256 * @return None. 1257 */ 1258 inline void getTrustedModuleRequiredToBoot( 1259 const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1260 { 1261 BMCWEB_LOG_DEBUG << "Get TPM required to boot."; 1262 1263 crow::connections::systemBus->async_method_call( 1264 [aResp]( 1265 const boost::system::error_code ec, 1266 std::vector<std::pair< 1267 std::string, 1268 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1269 subtree) { 1270 if (ec) 1271 { 1272 BMCWEB_LOG_DEBUG 1273 << "DBUS response error on TPM.Policy GetSubTree" << ec; 1274 // This is an optional D-Bus object so just return if 1275 // error occurs 1276 return; 1277 } 1278 if (subtree.size() == 0) 1279 { 1280 // As noted above, this is an optional interface so just return 1281 // if there is no instance found 1282 return; 1283 } 1284 1285 /* When there is more than one TPMEnable object... */ 1286 if (subtree.size() > 1) 1287 { 1288 BMCWEB_LOG_DEBUG 1289 << "DBUS response has more than 1 TPM Enable object:" 1290 << subtree.size(); 1291 // Throw an internal Error and return 1292 messages::internalError(aResp->res); 1293 return; 1294 } 1295 1296 // Make sure the Dbus response map has a service and objectPath 1297 // field 1298 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1299 { 1300 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; 1301 messages::internalError(aResp->res); 1302 return; 1303 } 1304 1305 const std::string& path = subtree[0].first; 1306 const std::string& serv = subtree[0].second.begin()->first; 1307 1308 // Valid TPM Enable object found, now reading the current value 1309 crow::connections::systemBus->async_method_call( 1310 [aResp](const boost::system::error_code ec, 1311 std::variant<bool>& tpmRequired) { 1312 if (ec) 1313 { 1314 BMCWEB_LOG_DEBUG 1315 << "D-BUS response error on TPM.Policy Get" << ec; 1316 messages::internalError(aResp->res); 1317 return; 1318 } 1319 1320 const bool* tpmRequiredVal = 1321 std::get_if<bool>(&tpmRequired); 1322 1323 if (!tpmRequiredVal) 1324 { 1325 messages::internalError(aResp->res); 1326 return; 1327 } 1328 1329 if (*tpmRequiredVal == true) 1330 { 1331 aResp->res 1332 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1333 "Required"; 1334 } 1335 else 1336 { 1337 aResp->res 1338 .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = 1339 "Disabled"; 1340 } 1341 }, 1342 serv, path, "org.freedesktop.DBus.Properties", "Get", 1343 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable"); 1344 }, 1345 "xyz.openbmc_project.ObjectMapper", 1346 "/xyz/openbmc_project/object_mapper", 1347 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1348 std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"}); 1349 } 1350 1351 /** 1352 * @brief Sets boot properties into DBUS object(s). 1353 * 1354 * @param[in] aResp Shared pointer for generating response message. 1355 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 1356 * @param[in] bootSource The boot source to set. 1357 * @param[in] bootEnable The source override "enable" to set. 1358 * 1359 * @return Integer error code. 1360 */ 1361 inline void setBootModeOrSource(std::shared_ptr<bmcweb::AsyncResp> aResp, 1362 bool oneTimeEnabled, 1363 const std::optional<std::string>& bootSource, 1364 const std::optional<std::string>& bootEnable) 1365 { 1366 std::string bootSourceStr = 1367 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 1368 std::string bootModeStr = 1369 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 1370 bool oneTimeSetting = oneTimeEnabled; 1371 bool useBootSource = true; 1372 1373 // Validate incoming parameters 1374 if (bootEnable) 1375 { 1376 if (*bootEnable == "Once") 1377 { 1378 oneTimeSetting = true; 1379 } 1380 else if (*bootEnable == "Continuous") 1381 { 1382 oneTimeSetting = false; 1383 } 1384 else if (*bootEnable == "Disabled") 1385 { 1386 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 1387 oneTimeSetting = false; 1388 useBootSource = false; 1389 } 1390 else 1391 { 1392 BMCWEB_LOG_DEBUG << "Unsupported value for " 1393 "BootSourceOverrideEnabled: " 1394 << *bootEnable; 1395 messages::propertyValueNotInList(aResp->res, *bootEnable, 1396 "BootSourceOverrideEnabled"); 1397 return; 1398 } 1399 } 1400 1401 if (bootSource && useBootSource) 1402 { 1403 // Source target specified 1404 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 1405 // Figure out which DBUS interface and property to use 1406 if (assignBootParameters(aResp, *bootSource, bootSourceStr, 1407 bootModeStr)) 1408 { 1409 BMCWEB_LOG_DEBUG 1410 << "Invalid property value for BootSourceOverrideTarget: " 1411 << *bootSource; 1412 messages::propertyValueNotInList(aResp->res, *bootSource, 1413 "BootSourceTargetOverride"); 1414 return; 1415 } 1416 } 1417 1418 // Act on validated parameters 1419 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 1420 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 1421 const char* bootObj = 1422 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 1423 : "/xyz/openbmc_project/control/host0/boot"; 1424 1425 crow::connections::systemBus->async_method_call( 1426 [aResp](const boost::system::error_code ec) { 1427 if (ec) 1428 { 1429 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1430 messages::internalError(aResp->res); 1431 return; 1432 } 1433 BMCWEB_LOG_DEBUG << "Boot source update done."; 1434 }, 1435 "xyz.openbmc_project.Settings", bootObj, 1436 "org.freedesktop.DBus.Properties", "Set", 1437 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 1438 std::variant<std::string>(bootSourceStr)); 1439 1440 crow::connections::systemBus->async_method_call( 1441 [aResp](const boost::system::error_code ec) { 1442 if (ec) 1443 { 1444 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1445 messages::internalError(aResp->res); 1446 return; 1447 } 1448 BMCWEB_LOG_DEBUG << "Boot mode update done."; 1449 }, 1450 "xyz.openbmc_project.Settings", bootObj, 1451 "org.freedesktop.DBus.Properties", "Set", 1452 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 1453 std::variant<std::string>(bootModeStr)); 1454 1455 crow::connections::systemBus->async_method_call( 1456 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 1457 if (ec) 1458 { 1459 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1460 messages::internalError(aResp->res); 1461 return; 1462 } 1463 BMCWEB_LOG_DEBUG << "Boot enable update done."; 1464 }, 1465 "xyz.openbmc_project.Settings", 1466 "/xyz/openbmc_project/control/host0/boot/one_time", 1467 "org.freedesktop.DBus.Properties", "Set", 1468 "xyz.openbmc_project.Object.Enable", "Enabled", 1469 std::variant<bool>(oneTimeSetting)); 1470 } 1471 1472 /** 1473 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 1474 * set boot source/boot mode properties. 1475 * 1476 * @param[in] aResp Shared pointer for generating response message. 1477 * @param[in] bootSource The boot source from incoming RF request. 1478 * @param[in] bootEnable The boot override enable from incoming RF request. 1479 * 1480 * @return Integer error code. 1481 */ 1482 inline void 1483 setBootSourceProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1484 std::optional<std::string> bootSource, 1485 std::optional<std::string> bootEnable) 1486 { 1487 BMCWEB_LOG_DEBUG << "Set boot information."; 1488 1489 crow::connections::systemBus->async_method_call( 1490 [aResp, bootSource{std::move(bootSource)}, 1491 bootEnable{std::move(bootEnable)}](const boost::system::error_code ec, 1492 const std::variant<bool>& oneTime) { 1493 if (ec) 1494 { 1495 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1496 messages::internalError(aResp->res); 1497 return; 1498 } 1499 1500 const bool* oneTimePtr = std::get_if<bool>(&oneTime); 1501 1502 if (!oneTimePtr) 1503 { 1504 messages::internalError(aResp->res); 1505 return; 1506 } 1507 1508 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 1509 1510 setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable); 1511 }, 1512 "xyz.openbmc_project.Settings", 1513 "/xyz/openbmc_project/control/host0/boot/one_time", 1514 "org.freedesktop.DBus.Properties", "Get", 1515 "xyz.openbmc_project.Object.Enable", "Enabled"); 1516 } 1517 1518 /** 1519 * @brief Sets AssetTag 1520 * 1521 * @param[in] aResp Shared pointer for generating response message. 1522 * @param[in] assetTag "AssetTag" from request. 1523 * 1524 * @return None. 1525 */ 1526 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1527 const std::string& assetTag) 1528 { 1529 crow::connections::systemBus->async_method_call( 1530 [aResp, assetTag]( 1531 const boost::system::error_code ec, 1532 const std::vector<std::pair< 1533 std::string, 1534 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1535 subtree) { 1536 if (ec) 1537 { 1538 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; 1539 messages::internalError(aResp->res); 1540 return; 1541 } 1542 if (subtree.size() == 0) 1543 { 1544 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; 1545 messages::internalError(aResp->res); 1546 return; 1547 } 1548 // Assume only 1 system D-Bus object 1549 // Throw an error if there is more than 1 1550 if (subtree.size() > 1) 1551 { 1552 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; 1553 messages::internalError(aResp->res); 1554 return; 1555 } 1556 if (subtree[0].first.empty() || subtree[0].second.size() != 1) 1557 { 1558 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; 1559 messages::internalError(aResp->res); 1560 return; 1561 } 1562 1563 const std::string& path = subtree[0].first; 1564 const std::string& service = subtree[0].second.begin()->first; 1565 1566 if (service.empty()) 1567 { 1568 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; 1569 messages::internalError(aResp->res); 1570 return; 1571 } 1572 1573 crow::connections::systemBus->async_method_call( 1574 [aResp](const boost::system::error_code ec2) { 1575 if (ec2) 1576 { 1577 BMCWEB_LOG_DEBUG 1578 << "D-Bus response error on AssetTag Set " << ec2; 1579 messages::internalError(aResp->res); 1580 return; 1581 } 1582 }, 1583 service, path, "org.freedesktop.DBus.Properties", "Set", 1584 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", 1585 std::variant<std::string>(assetTag)); 1586 }, 1587 "xyz.openbmc_project.ObjectMapper", 1588 "/xyz/openbmc_project/object_mapper", 1589 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 1590 "/xyz/openbmc_project/inventory", int32_t(0), 1591 std::array<const char*, 1>{ 1592 "xyz.openbmc_project.Inventory.Item.System"}); 1593 } 1594 1595 /** 1596 * @brief Sets automaticRetry (Auto Reboot) 1597 * 1598 * @param[in] aResp Shared pointer for generating response message. 1599 * @param[in] automaticRetryConfig "AutomaticRetryConfig" from request. 1600 * 1601 * @return None. 1602 */ 1603 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1604 const std::string& automaticRetryConfig) 1605 { 1606 BMCWEB_LOG_DEBUG << "Set Automatic Retry."; 1607 1608 // OpenBMC only supports "Disabled" and "RetryAttempts". 1609 bool autoRebootEnabled; 1610 1611 if (automaticRetryConfig == "Disabled") 1612 { 1613 autoRebootEnabled = false; 1614 } 1615 else if (automaticRetryConfig == "RetryAttempts") 1616 { 1617 autoRebootEnabled = true; 1618 } 1619 else 1620 { 1621 BMCWEB_LOG_DEBUG << "Invalid property value for " 1622 "AutomaticRetryConfig: " 1623 << automaticRetryConfig; 1624 messages::propertyValueNotInList(aResp->res, automaticRetryConfig, 1625 "AutomaticRetryConfig"); 1626 return; 1627 } 1628 1629 crow::connections::systemBus->async_method_call( 1630 [aResp](const boost::system::error_code ec) { 1631 if (ec) 1632 { 1633 messages::internalError(aResp->res); 1634 return; 1635 } 1636 }, 1637 "xyz.openbmc_project.Settings", 1638 "/xyz/openbmc_project/control/host0/auto_reboot", 1639 "org.freedesktop.DBus.Properties", "Set", 1640 "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", 1641 std::variant<bool>(autoRebootEnabled)); 1642 } 1643 1644 /** 1645 * @brief Sets power restore policy properties. 1646 * 1647 * @param[in] aResp Shared pointer for generating response message. 1648 * @param[in] policy power restore policy properties from request. 1649 * 1650 * @return None. 1651 */ 1652 inline void 1653 setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1654 const std::string& policy) 1655 { 1656 BMCWEB_LOG_DEBUG << "Set power restore policy."; 1657 1658 const boost::container::flat_map<std::string, std::string> policyMaps = { 1659 {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1660 "AlwaysOn"}, 1661 {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1662 "AlwaysOff"}, 1663 {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy." 1664 "Restore"}}; 1665 1666 std::string powerRestorPolicy; 1667 1668 auto policyMapsIt = policyMaps.find(policy); 1669 if (policyMapsIt == policyMaps.end()) 1670 { 1671 messages::propertyValueNotInList(aResp->res, policy, 1672 "PowerRestorePolicy"); 1673 return; 1674 } 1675 1676 powerRestorPolicy = policyMapsIt->second; 1677 1678 crow::connections::systemBus->async_method_call( 1679 [aResp](const boost::system::error_code ec) { 1680 if (ec) 1681 { 1682 messages::internalError(aResp->res); 1683 return; 1684 } 1685 }, 1686 "xyz.openbmc_project.Settings", 1687 "/xyz/openbmc_project/control/host0/power_restore_policy", 1688 "org.freedesktop.DBus.Properties", "Set", 1689 "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", 1690 std::variant<std::string>(powerRestorPolicy)); 1691 } 1692 1693 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 1694 /** 1695 * @brief Retrieves provisioning status 1696 * 1697 * @param[in] aResp Shared pointer for completing asynchronous calls. 1698 * 1699 * @return None. 1700 */ 1701 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) 1702 { 1703 BMCWEB_LOG_DEBUG << "Get OEM information."; 1704 crow::connections::systemBus->async_method_call( 1705 [aResp](const boost::system::error_code ec, 1706 const std::vector<std::pair<std::string, VariantType>>& 1707 propertiesList) { 1708 nlohmann::json& oemPFR = 1709 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; 1710 aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = 1711 "#OemComputerSystem.OpenBmc"; 1712 oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; 1713 1714 if (ec) 1715 { 1716 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1717 // not an error, don't have to have the interface 1718 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1719 return; 1720 } 1721 1722 const bool* provState = nullptr; 1723 const bool* lockState = nullptr; 1724 for (const std::pair<std::string, VariantType>& property : 1725 propertiesList) 1726 { 1727 if (property.first == "UfmProvisioned") 1728 { 1729 provState = std::get_if<bool>(&property.second); 1730 } 1731 else if (property.first == "UfmLocked") 1732 { 1733 lockState = std::get_if<bool>(&property.second); 1734 } 1735 } 1736 1737 if ((provState == nullptr) || (lockState == nullptr)) 1738 { 1739 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; 1740 messages::internalError(aResp->res); 1741 return; 1742 } 1743 1744 if (*provState == true) 1745 { 1746 if (*lockState == true) 1747 { 1748 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; 1749 } 1750 else 1751 { 1752 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; 1753 } 1754 } 1755 else 1756 { 1757 oemPFR["ProvisioningStatus"] = "NotProvisioned"; 1758 } 1759 }, 1760 "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", 1761 "org.freedesktop.DBus.Properties", "GetAll", 1762 "xyz.openbmc_project.PFR.Attributes"); 1763 } 1764 #endif 1765 1766 /** 1767 * @brief Translate the PowerMode to a response message. 1768 * 1769 * @param[in] aResp Shared pointer for generating response message. 1770 * @param[in] modeValue PowerMode value to be translated 1771 * 1772 * @return None. 1773 */ 1774 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1775 const std::string& modeValue) 1776 { 1777 std::string modeString; 1778 1779 if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1780 "PowerMode.Static") 1781 { 1782 aResp->res.jsonValue["PowerMode"] = "Static"; 1783 } 1784 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1785 "PowerMode.MaximumPerformance") 1786 { 1787 aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; 1788 } 1789 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1790 "PowerMode.PowerSaving") 1791 { 1792 aResp->res.jsonValue["PowerMode"] = "PowerSaving"; 1793 } 1794 else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." 1795 "PowerMode.OEM") 1796 { 1797 aResp->res.jsonValue["PowerMode"] = "OEM"; 1798 } 1799 else 1800 { 1801 // Any other values would be invalid 1802 BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; 1803 messages::internalError(aResp->res); 1804 } 1805 } 1806 1807 /** 1808 * @brief Retrieves system power mode 1809 * 1810 * @param[in] aResp Shared pointer for generating response message. 1811 * 1812 * @return None. 1813 */ 1814 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 1815 { 1816 BMCWEB_LOG_DEBUG << "Get power mode."; 1817 1818 // Get Power Mode object path: 1819 crow::connections::systemBus->async_method_call( 1820 [aResp]( 1821 const boost::system::error_code ec, 1822 const std::vector<std::pair< 1823 std::string, 1824 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1825 subtree) { 1826 if (ec) 1827 { 1828 BMCWEB_LOG_DEBUG 1829 << "DBUS response error on Power.Mode GetSubTree " << ec; 1830 // This is an optional D-Bus object so just return if 1831 // error occurs 1832 return; 1833 } 1834 if (subtree.empty()) 1835 { 1836 // As noted above, this is an optional interface so just return 1837 // if there is no instance found 1838 return; 1839 } 1840 if (subtree.size() > 1) 1841 { 1842 // More then one PowerMode object is not supported and is an 1843 // error 1844 BMCWEB_LOG_DEBUG 1845 << "Found more than 1 system D-Bus Power.Mode objects: " 1846 << subtree.size(); 1847 messages::internalError(aResp->res); 1848 return; 1849 } 1850 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1851 { 1852 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1853 messages::internalError(aResp->res); 1854 return; 1855 } 1856 const std::string& path = subtree[0].first; 1857 const std::string& service = subtree[0].second.begin()->first; 1858 if (service.empty()) 1859 { 1860 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1861 messages::internalError(aResp->res); 1862 return; 1863 } 1864 // Valid Power Mode object found, now read the current value 1865 crow::connections::systemBus->async_method_call( 1866 [aResp](const boost::system::error_code ec, 1867 const std::variant<std::string>& pmode) { 1868 if (ec) 1869 { 1870 BMCWEB_LOG_DEBUG 1871 << "DBUS response error on PowerMode Get: " << ec; 1872 messages::internalError(aResp->res); 1873 return; 1874 } 1875 1876 const std::string* s = std::get_if<std::string>(&pmode); 1877 if (s == nullptr) 1878 { 1879 BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; 1880 messages::internalError(aResp->res); 1881 return; 1882 } 1883 1884 aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = 1885 {"Static", "MaximumPerformance", "PowerSaving"}; 1886 1887 BMCWEB_LOG_DEBUG << "Current power mode: " << *s; 1888 translatePowerMode(aResp, *s); 1889 }, 1890 service, path, "org.freedesktop.DBus.Properties", "Get", 1891 "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); 1892 }, 1893 "xyz.openbmc_project.ObjectMapper", 1894 "/xyz/openbmc_project/object_mapper", 1895 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 1896 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 1897 } 1898 1899 /** 1900 * @brief Validate the specified mode is valid and return the PowerMode 1901 * name associated with that string 1902 * 1903 * @param[in] aResp Shared pointer for generating response message. 1904 * @param[in] modeString String representing the desired PowerMode 1905 * 1906 * @return PowerMode value or empty string if mode is not valid 1907 */ 1908 inline std::string 1909 validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1910 const std::string& modeString) 1911 { 1912 std::string mode; 1913 1914 if (modeString == "Static") 1915 { 1916 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; 1917 } 1918 else if (modeString == "MaximumPerformance") 1919 { 1920 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode." 1921 "MaximumPerformance"; 1922 } 1923 else if (modeString == "PowerSaving") 1924 { 1925 mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; 1926 } 1927 else 1928 { 1929 messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); 1930 } 1931 return mode; 1932 } 1933 1934 /** 1935 * @brief Sets system power mode. 1936 * 1937 * @param[in] aResp Shared pointer for generating response message. 1938 * @param[in] pmode System power mode from request. 1939 * 1940 * @return None. 1941 */ 1942 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 1943 const std::string& pmode) 1944 { 1945 BMCWEB_LOG_DEBUG << "Set power mode."; 1946 1947 std::string powerMode = validatePowerMode(aResp, pmode); 1948 if (powerMode.empty()) 1949 { 1950 return; 1951 } 1952 1953 // Get Power Mode object path: 1954 crow::connections::systemBus->async_method_call( 1955 [aResp, powerMode]( 1956 const boost::system::error_code ec, 1957 const std::vector<std::pair< 1958 std::string, 1959 std::vector<std::pair<std::string, std::vector<std::string>>>>>& 1960 subtree) { 1961 if (ec) 1962 { 1963 BMCWEB_LOG_DEBUG 1964 << "DBUS response error on Power.Mode GetSubTree " << ec; 1965 // This is an optional D-Bus object, but user attempted to patch 1966 messages::internalError(aResp->res); 1967 return; 1968 } 1969 if (subtree.empty()) 1970 { 1971 // This is an optional D-Bus object, but user attempted to patch 1972 messages::resourceNotFound(aResp->res, "ComputerSystem", 1973 "PowerMode"); 1974 return; 1975 } 1976 if (subtree.size() > 1) 1977 { 1978 // More then one PowerMode object is not supported and is an 1979 // error 1980 BMCWEB_LOG_DEBUG 1981 << "Found more than 1 system D-Bus Power.Mode objects: " 1982 << subtree.size(); 1983 messages::internalError(aResp->res); 1984 return; 1985 } 1986 if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) 1987 { 1988 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; 1989 messages::internalError(aResp->res); 1990 return; 1991 } 1992 const std::string& path = subtree[0].first; 1993 const std::string& service = subtree[0].second.begin()->first; 1994 if (service.empty()) 1995 { 1996 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; 1997 messages::internalError(aResp->res); 1998 return; 1999 } 2000 2001 BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " 2002 << path; 2003 2004 // Set the Power Mode property 2005 crow::connections::systemBus->async_method_call( 2006 [aResp](const boost::system::error_code ec) { 2007 if (ec) 2008 { 2009 messages::internalError(aResp->res); 2010 return; 2011 } 2012 }, 2013 service, path, "org.freedesktop.DBus.Properties", "Set", 2014 "xyz.openbmc_project.Control.Power.Mode", "PowerMode", 2015 std::variant<std::string>(powerMode)); 2016 }, 2017 "xyz.openbmc_project.ObjectMapper", 2018 "/xyz/openbmc_project/object_mapper", 2019 "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), 2020 std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); 2021 } 2022 2023 /** 2024 * @brief Translates watchdog timeout action DBUS property value to redfish. 2025 * 2026 * @param[in] dbusAction The watchdog timeout action in D-BUS. 2027 * 2028 * @return Returns as a string, the timeout action in Redfish terms. If 2029 * translation cannot be done, returns an empty string. 2030 */ 2031 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) 2032 { 2033 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") 2034 { 2035 return "None"; 2036 } 2037 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") 2038 { 2039 return "ResetSystem"; 2040 } 2041 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") 2042 { 2043 return "PowerDown"; 2044 } 2045 if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") 2046 { 2047 return "PowerCycle"; 2048 } 2049 2050 return ""; 2051 } 2052 2053 /** 2054 *@brief Translates timeout action from Redfish to DBUS property value. 2055 * 2056 *@param[in] rfAction The timeout action in Redfish. 2057 * 2058 *@return Returns as a string, the time_out action as expected by DBUS. 2059 *If translation cannot be done, returns an empty string. 2060 */ 2061 2062 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) 2063 { 2064 if (rfAction == "None") 2065 { 2066 return "xyz.openbmc_project.State.Watchdog.Action.None"; 2067 } 2068 if (rfAction == "PowerCycle") 2069 { 2070 return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; 2071 } 2072 if (rfAction == "PowerDown") 2073 { 2074 return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; 2075 } 2076 if (rfAction == "ResetSystem") 2077 { 2078 return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; 2079 } 2080 2081 return ""; 2082 } 2083 2084 /** 2085 * @brief Retrieves host watchdog timer properties over DBUS 2086 * 2087 * @param[in] aResp Shared pointer for completing asynchronous calls. 2088 * 2089 * @return None. 2090 */ 2091 inline void 2092 getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) 2093 { 2094 BMCWEB_LOG_DEBUG << "Get host watchodg"; 2095 crow::connections::systemBus->async_method_call( 2096 [aResp](const boost::system::error_code ec, 2097 PropertiesType& properties) { 2098 if (ec) 2099 { 2100 // watchdog service is stopped 2101 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2102 return; 2103 } 2104 2105 BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; 2106 2107 nlohmann::json& hostWatchdogTimer = 2108 aResp->res.jsonValue["HostWatchdogTimer"]; 2109 2110 // watchdog service is running/enabled 2111 hostWatchdogTimer["Status"]["State"] = "Enabled"; 2112 2113 for (const auto& property : properties) 2114 { 2115 BMCWEB_LOG_DEBUG << "prop=" << property.first; 2116 if (property.first == "Enabled") 2117 { 2118 const bool* state = std::get_if<bool>(&property.second); 2119 2120 if (!state) 2121 { 2122 messages::internalError(aResp->res); 2123 return; 2124 } 2125 2126 hostWatchdogTimer["FunctionEnabled"] = *state; 2127 } 2128 else if (property.first == "ExpireAction") 2129 { 2130 const std::string* s = 2131 std::get_if<std::string>(&property.second); 2132 if (!s) 2133 { 2134 messages::internalError(aResp->res); 2135 return; 2136 } 2137 2138 std::string action = dbusToRfWatchdogAction(*s); 2139 if (action.empty()) 2140 { 2141 messages::internalError(aResp->res); 2142 return; 2143 } 2144 hostWatchdogTimer["TimeoutAction"] = action; 2145 } 2146 } 2147 }, 2148 "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", 2149 "org.freedesktop.DBus.Properties", "GetAll", 2150 "xyz.openbmc_project.State.Watchdog"); 2151 } 2152 2153 /** 2154 * @brief Sets Host WatchDog Timer properties. 2155 * 2156 * @param[in] aResp Shared pointer for generating response message. 2157 * @param[in] wdtEnable The WDTimer Enable value (true/false) from incoming 2158 * RF request. 2159 * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. 2160 * 2161 * @return None. 2162 */ 2163 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 2164 const std::optional<bool> wdtEnable, 2165 const std::optional<std::string>& wdtTimeOutAction) 2166 { 2167 BMCWEB_LOG_DEBUG << "Set host watchdog"; 2168 2169 if (wdtTimeOutAction) 2170 { 2171 std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); 2172 // check if TimeOut Action is Valid 2173 if (wdtTimeOutActStr.empty()) 2174 { 2175 BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " 2176 << *wdtTimeOutAction; 2177 messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, 2178 "TimeoutAction"); 2179 return; 2180 } 2181 2182 crow::connections::systemBus->async_method_call( 2183 [aResp](const boost::system::error_code ec) { 2184 if (ec) 2185 { 2186 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2187 messages::internalError(aResp->res); 2188 return; 2189 } 2190 }, 2191 "xyz.openbmc_project.Watchdog", 2192 "/xyz/openbmc_project/watchdog/host0", 2193 "org.freedesktop.DBus.Properties", "Set", 2194 "xyz.openbmc_project.State.Watchdog", "ExpireAction", 2195 std::variant<std::string>(wdtTimeOutActStr)); 2196 } 2197 2198 if (wdtEnable) 2199 { 2200 crow::connections::systemBus->async_method_call( 2201 [aResp](const boost::system::error_code ec) { 2202 if (ec) 2203 { 2204 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 2205 messages::internalError(aResp->res); 2206 return; 2207 } 2208 }, 2209 "xyz.openbmc_project.Watchdog", 2210 "/xyz/openbmc_project/watchdog/host0", 2211 "org.freedesktop.DBus.Properties", "Set", 2212 "xyz.openbmc_project.State.Watchdog", "Enabled", 2213 std::variant<bool>(*wdtEnable)); 2214 } 2215 } 2216 2217 /** 2218 * SystemsCollection derived class for delivering ComputerSystems Collection 2219 * Schema 2220 */ 2221 inline void requestRoutesSystemsCollection(App& app) 2222 { 2223 BMCWEB_ROUTE(app, "/redfish/v1/Systems/") 2224 .privileges(redfish::privileges::getComputerSystemCollection) 2225 .methods(boost::beast::http::verb::get)( 2226 [](const crow::Request& req, 2227 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2228 asyncResp->res.jsonValue["@odata.type"] = 2229 "#ComputerSystemCollection.ComputerSystemCollection"; 2230 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 2231 asyncResp->res.jsonValue["Name"] = "Computer System Collection"; 2232 2233 crow::connections::systemBus->async_method_call( 2234 [asyncResp, 2235 &req](const boost::system::error_code ec, 2236 const std::variant<std::string>& /*hostName*/) { 2237 nlohmann::json& ifaceArray = 2238 asyncResp->res.jsonValue["Members"]; 2239 ifaceArray = nlohmann::json::array(); 2240 auto& count = 2241 asyncResp->res.jsonValue["Members@odata.count"]; 2242 ifaceArray.push_back( 2243 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2244 count = ifaceArray.size(); 2245 if (!ec) 2246 { 2247 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2248 ifaceArray.push_back( 2249 {{"@odata.id", 2250 "/redfish/v1/Systems/hypervisor"}}); 2251 count = ifaceArray.size(); 2252 } 2253 }, 2254 "xyz.openbmc_project.Settings", 2255 "/xyz/openbmc_project/network/hypervisor", 2256 "org.freedesktop.DBus.Properties", "Get", 2257 "xyz.openbmc_project.Network.SystemConfiguration", 2258 "HostName"); 2259 }); 2260 } 2261 2262 /** 2263 * Function transceives data with dbus directly. 2264 */ 2265 void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2266 { 2267 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2268 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2269 constexpr char const* interfaceName = 2270 "xyz.openbmc_project.Control.Host.NMI"; 2271 constexpr char const* method = "NMI"; 2272 2273 crow::connections::systemBus->async_method_call( 2274 [asyncResp](const boost::system::error_code ec) { 2275 if (ec) 2276 { 2277 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2278 messages::internalError(asyncResp->res); 2279 return; 2280 } 2281 messages::success(asyncResp->res); 2282 }, 2283 serviceName, objectPath, interfaceName, method); 2284 } 2285 2286 /** 2287 * SystemActionsReset class supports handle POST method for Reset action. 2288 * The class retrieves and sends data directly to D-Bus. 2289 */ 2290 inline void requestRoutesSystemActionsReset(App& app) 2291 { 2292 /** 2293 * Function handles POST method request. 2294 * Analyzes POST body message before sends Reset request data to D-Bus. 2295 */ 2296 BMCWEB_ROUTE(app, 2297 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2298 .privileges(redfish::privileges::postComputerSystem) 2299 .methods( 2300 boost::beast::http::verb:: 2301 post)([](const crow::Request& req, 2302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2303 std::string resetType; 2304 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2305 resetType)) 2306 { 2307 return; 2308 } 2309 2310 // Get the command and host vs. chassis 2311 std::string command; 2312 bool hostCommand; 2313 if ((resetType == "On") || (resetType == "ForceOn")) 2314 { 2315 command = "xyz.openbmc_project.State.Host.Transition.On"; 2316 hostCommand = true; 2317 } 2318 else if (resetType == "ForceOff") 2319 { 2320 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2321 hostCommand = false; 2322 } 2323 else if (resetType == "ForceRestart") 2324 { 2325 command = 2326 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2327 hostCommand = true; 2328 } 2329 else if (resetType == "GracefulShutdown") 2330 { 2331 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2332 hostCommand = true; 2333 } 2334 else if (resetType == "GracefulRestart") 2335 { 2336 command = "xyz.openbmc_project.State.Host.Transition." 2337 "GracefulWarmReboot"; 2338 hostCommand = true; 2339 } 2340 else if (resetType == "PowerCycle") 2341 { 2342 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2343 hostCommand = true; 2344 } 2345 else if (resetType == "Nmi") 2346 { 2347 doNMI(asyncResp); 2348 return; 2349 } 2350 else 2351 { 2352 messages::actionParameterUnknown(asyncResp->res, "Reset", 2353 resetType); 2354 return; 2355 } 2356 2357 if (hostCommand) 2358 { 2359 crow::connections::systemBus->async_method_call( 2360 [asyncResp, resetType](const boost::system::error_code ec) { 2361 if (ec) 2362 { 2363 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2364 if (ec.value() == 2365 boost::asio::error::invalid_argument) 2366 { 2367 messages::actionParameterNotSupported( 2368 asyncResp->res, resetType, "Reset"); 2369 } 2370 else 2371 { 2372 messages::internalError(asyncResp->res); 2373 } 2374 return; 2375 } 2376 messages::success(asyncResp->res); 2377 }, 2378 "xyz.openbmc_project.State.Host", 2379 "/xyz/openbmc_project/state/host0", 2380 "org.freedesktop.DBus.Properties", "Set", 2381 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2382 std::variant<std::string>{command}); 2383 } 2384 else 2385 { 2386 crow::connections::systemBus->async_method_call( 2387 [asyncResp, resetType](const boost::system::error_code ec) { 2388 if (ec) 2389 { 2390 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2391 if (ec.value() == 2392 boost::asio::error::invalid_argument) 2393 { 2394 messages::actionParameterNotSupported( 2395 asyncResp->res, resetType, "Reset"); 2396 } 2397 else 2398 { 2399 messages::internalError(asyncResp->res); 2400 } 2401 return; 2402 } 2403 messages::success(asyncResp->res); 2404 }, 2405 "xyz.openbmc_project.State.Chassis", 2406 "/xyz/openbmc_project/state/chassis0", 2407 "org.freedesktop.DBus.Properties", "Set", 2408 "xyz.openbmc_project.State.Chassis", 2409 "RequestedPowerTransition", 2410 std::variant<std::string>{command}); 2411 } 2412 }); 2413 } 2414 2415 /** 2416 * Systems derived class for delivering Computer Systems Schema. 2417 */ 2418 inline void requestRoutesSystems(App& app) 2419 { 2420 2421 /** 2422 * Functions triggers appropriate requests on DBus 2423 */ 2424 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2425 .privileges(redfish::privileges::getComputerSystem) 2426 .methods( 2427 boost::beast::http::verb:: 2428 get)([](const crow::Request&, 2429 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2430 asyncResp->res.jsonValue["@odata.type"] = 2431 "#ComputerSystem.v1_15_0.ComputerSystem"; 2432 asyncResp->res.jsonValue["Name"] = "system"; 2433 asyncResp->res.jsonValue["Id"] = "system"; 2434 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2435 asyncResp->res.jsonValue["Description"] = "Computer System"; 2436 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2437 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2438 "Disabled"; 2439 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2440 uint64_t(0); 2441 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2442 "Disabled"; 2443 asyncResp->res.jsonValue["@odata.id"] = 2444 "/redfish/v1/Systems/system"; 2445 2446 asyncResp->res.jsonValue["Processors"] = { 2447 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2448 asyncResp->res.jsonValue["Memory"] = { 2449 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2450 asyncResp->res.jsonValue["Storage"] = { 2451 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2452 2453 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2454 {"target", 2455 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2456 {"@Redfish.ActionInfo", 2457 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2458 2459 asyncResp->res.jsonValue["LogServices"] = { 2460 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2461 2462 asyncResp->res.jsonValue["Bios"] = { 2463 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2464 2465 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2466 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2467 2468 asyncResp->res.jsonValue["Status"] = { 2469 {"Health", "OK"}, 2470 {"State", "Enabled"}, 2471 }; 2472 2473 // Fill in SerialConsole info 2474 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2475 15; 2476 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2477 {"ServiceEnabled", true}, 2478 }; 2479 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2480 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2481 {"ServiceEnabled", true}, 2482 {"Port", 2200}, 2483 // https://github.com/openbmc/docs/blob/master/console.md 2484 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2485 }; 2486 2487 #ifdef BMCWEB_ENABLE_KVM 2488 // Fill in GraphicalConsole info 2489 asyncResp->res.jsonValue["GraphicalConsole"] = { 2490 {"ServiceEnabled", true}, 2491 {"MaxConcurrentSessions", 4}, 2492 {"ConnectTypesSupported", {"KVMIP"}}, 2493 }; 2494 #endif // BMCWEB_ENABLE_KVM 2495 constexpr const std::array<const char*, 4> inventoryForSystems = { 2496 "xyz.openbmc_project.Inventory.Item.Dimm", 2497 "xyz.openbmc_project.Inventory.Item.Cpu", 2498 "xyz.openbmc_project.Inventory.Item.Drive", 2499 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2500 2501 auto health = std::make_shared<HealthPopulate>(asyncResp); 2502 crow::connections::systemBus->async_method_call( 2503 [health](const boost::system::error_code ec, 2504 std::vector<std::string>& resp) { 2505 if (ec) 2506 { 2507 // no inventory 2508 return; 2509 } 2510 2511 health->inventory = std::move(resp); 2512 }, 2513 "xyz.openbmc_project.ObjectMapper", 2514 "/xyz/openbmc_project/object_mapper", 2515 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2516 int32_t(0), inventoryForSystems); 2517 2518 health->populate(); 2519 2520 getMainChassisId( 2521 asyncResp, [](const std::string& chassisId, 2522 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2523 aRsp->res.jsonValue["Links"]["Chassis"] = { 2524 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2525 }); 2526 2527 getLocationIndicatorActive(asyncResp); 2528 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2529 getIndicatorLedState(asyncResp); 2530 getComputerSystem(asyncResp, health); 2531 getHostState(asyncResp); 2532 getBootProperties(asyncResp); 2533 getBootProgress(asyncResp); 2534 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2535 getHostWatchdogTimer(asyncResp); 2536 getPowerRestorePolicy(asyncResp); 2537 getAutomaticRetry(asyncResp); 2538 getLastResetTime(asyncResp); 2539 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2540 getProvisioningStatus(asyncResp); 2541 #endif 2542 getTrustedModuleRequiredToBoot(asyncResp); 2543 getPowerMode(asyncResp); 2544 }); 2545 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2546 .privileges(redfish::privileges::patchComputerSystem) 2547 .methods(boost::beast::http::verb::patch)( 2548 [](const crow::Request& req, 2549 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2550 std::optional<bool> locationIndicatorActive; 2551 std::optional<std::string> indicatorLed; 2552 std::optional<nlohmann::json> bootProps; 2553 std::optional<nlohmann::json> wdtTimerProps; 2554 std::optional<std::string> assetTag; 2555 std::optional<std::string> powerRestorePolicy; 2556 std::optional<std::string> powerMode; 2557 2558 if (!json_util::readJson( 2559 req, asyncResp->res, "IndicatorLED", indicatorLed, 2560 "LocationIndicatorActive", locationIndicatorActive, 2561 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2562 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2563 assetTag, "PowerMode", powerMode)) 2564 { 2565 return; 2566 } 2567 2568 asyncResp->res.result(boost::beast::http::status::no_content); 2569 2570 if (assetTag) 2571 { 2572 setAssetTag(asyncResp, *assetTag); 2573 } 2574 2575 if (wdtTimerProps) 2576 { 2577 std::optional<bool> wdtEnable; 2578 std::optional<std::string> wdtTimeOutAction; 2579 2580 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2581 "FunctionEnabled", wdtEnable, 2582 "TimeoutAction", wdtTimeOutAction)) 2583 { 2584 return; 2585 } 2586 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2587 } 2588 2589 if (bootProps) 2590 { 2591 std::optional<std::string> bootSource; 2592 std::optional<std::string> bootEnable; 2593 std::optional<std::string> automaticRetryConfig; 2594 2595 if (!json_util::readJson( 2596 *bootProps, asyncResp->res, 2597 "BootSourceOverrideTarget", bootSource, 2598 "BootSourceOverrideEnabled", bootEnable, 2599 "AutomaticRetryConfig", automaticRetryConfig)) 2600 { 2601 return; 2602 } 2603 if (bootSource || bootEnable) 2604 { 2605 setBootSourceProperties(asyncResp, 2606 std::move(bootSource), 2607 std::move(bootEnable)); 2608 } 2609 if (automaticRetryConfig) 2610 { 2611 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2612 } 2613 } 2614 2615 if (locationIndicatorActive) 2616 { 2617 setLocationIndicatorActive(asyncResp, 2618 *locationIndicatorActive); 2619 } 2620 2621 // TODO (Gunnar): Remove IndicatorLED after enough time has 2622 // passed 2623 if (indicatorLed) 2624 { 2625 setIndicatorLedState(asyncResp, *indicatorLed); 2626 asyncResp->res.addHeader( 2627 boost::beast::http::field::warning, 2628 "299 - \"IndicatorLED is deprecated. Use " 2629 "LocationIndicatorActive instead.\""); 2630 } 2631 2632 if (powerRestorePolicy) 2633 { 2634 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2635 } 2636 2637 if (powerMode) 2638 { 2639 setPowerMode(asyncResp, *powerMode); 2640 } 2641 }); 2642 } 2643 2644 /** 2645 * SystemResetActionInfo derived class for delivering Computer Systems 2646 * ResetType AllowableValues using ResetInfo schema. 2647 */ 2648 inline void requestRoutesSystemResetActionInfo(App& app) 2649 { 2650 2651 /** 2652 * Functions triggers appropriate requests on DBus 2653 */ 2654 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2655 .privileges(redfish::privileges::getActionInfo) 2656 .methods(boost::beast::http::verb::get)( 2657 [](const crow::Request&, 2658 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2659 asyncResp->res.jsonValue = { 2660 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2661 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2662 {"Name", "Reset Action Info"}, 2663 {"Id", "ResetActionInfo"}, 2664 {"Parameters", 2665 {{{"Name", "ResetType"}, 2666 {"Required", true}, 2667 {"DataType", "String"}, 2668 {"AllowableValues", 2669 {"On", "ForceOff", "ForceOn", "ForceRestart", 2670 "GracefulRestart", "GracefulShutdown", "PowerCycle", 2671 "Nmi"}}}}}}; 2672 }); 2673 } 2674 } // namespace redfish 2675