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](const boost::system::error_code ec, 2235 const std::variant<std::string>& /*hostName*/) { 2236 nlohmann::json& ifaceArray = 2237 asyncResp->res.jsonValue["Members"]; 2238 ifaceArray = nlohmann::json::array(); 2239 auto& count = 2240 asyncResp->res.jsonValue["Members@odata.count"]; 2241 ifaceArray.push_back( 2242 {{"@odata.id", "/redfish/v1/Systems/system"}}); 2243 count = ifaceArray.size(); 2244 if (!ec) 2245 { 2246 BMCWEB_LOG_DEBUG << "Hypervisor is available"; 2247 ifaceArray.push_back( 2248 {{"@odata.id", 2249 "/redfish/v1/Systems/hypervisor"}}); 2250 count = ifaceArray.size(); 2251 } 2252 }, 2253 "xyz.openbmc_project.Settings", 2254 "/xyz/openbmc_project/network/hypervisor", 2255 "org.freedesktop.DBus.Properties", "Get", 2256 "xyz.openbmc_project.Network.SystemConfiguration", 2257 "HostName"); 2258 }); 2259 } 2260 2261 /** 2262 * Function transceives data with dbus directly. 2263 */ 2264 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 2265 { 2266 constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; 2267 constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; 2268 constexpr char const* interfaceName = 2269 "xyz.openbmc_project.Control.Host.NMI"; 2270 constexpr char const* method = "NMI"; 2271 2272 crow::connections::systemBus->async_method_call( 2273 [asyncResp](const boost::system::error_code ec) { 2274 if (ec) 2275 { 2276 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; 2277 messages::internalError(asyncResp->res); 2278 return; 2279 } 2280 messages::success(asyncResp->res); 2281 }, 2282 serviceName, objectPath, interfaceName, method); 2283 } 2284 2285 /** 2286 * SystemActionsReset class supports handle POST method for Reset action. 2287 * The class retrieves and sends data directly to D-Bus. 2288 */ 2289 inline void requestRoutesSystemActionsReset(App& app) 2290 { 2291 /** 2292 * Function handles POST method request. 2293 * Analyzes POST body message before sends Reset request data to D-Bus. 2294 */ 2295 BMCWEB_ROUTE(app, 2296 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 2297 .privileges(redfish::privileges::postComputerSystem) 2298 .methods( 2299 boost::beast::http::verb:: 2300 post)([](const crow::Request& req, 2301 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2302 std::string resetType; 2303 if (!json_util::readJson(req, asyncResp->res, "ResetType", 2304 resetType)) 2305 { 2306 return; 2307 } 2308 2309 // Get the command and host vs. chassis 2310 std::string command; 2311 bool hostCommand; 2312 if ((resetType == "On") || (resetType == "ForceOn")) 2313 { 2314 command = "xyz.openbmc_project.State.Host.Transition.On"; 2315 hostCommand = true; 2316 } 2317 else if (resetType == "ForceOff") 2318 { 2319 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 2320 hostCommand = false; 2321 } 2322 else if (resetType == "ForceRestart") 2323 { 2324 command = 2325 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot"; 2326 hostCommand = true; 2327 } 2328 else if (resetType == "GracefulShutdown") 2329 { 2330 command = "xyz.openbmc_project.State.Host.Transition.Off"; 2331 hostCommand = true; 2332 } 2333 else if (resetType == "GracefulRestart") 2334 { 2335 command = "xyz.openbmc_project.State.Host.Transition." 2336 "GracefulWarmReboot"; 2337 hostCommand = true; 2338 } 2339 else if (resetType == "PowerCycle") 2340 { 2341 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 2342 hostCommand = true; 2343 } 2344 else if (resetType == "Nmi") 2345 { 2346 doNMI(asyncResp); 2347 return; 2348 } 2349 else 2350 { 2351 messages::actionParameterUnknown(asyncResp->res, "Reset", 2352 resetType); 2353 return; 2354 } 2355 2356 if (hostCommand) 2357 { 2358 crow::connections::systemBus->async_method_call( 2359 [asyncResp, resetType](const boost::system::error_code ec) { 2360 if (ec) 2361 { 2362 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2363 if (ec.value() == 2364 boost::asio::error::invalid_argument) 2365 { 2366 messages::actionParameterNotSupported( 2367 asyncResp->res, resetType, "Reset"); 2368 } 2369 else 2370 { 2371 messages::internalError(asyncResp->res); 2372 } 2373 return; 2374 } 2375 messages::success(asyncResp->res); 2376 }, 2377 "xyz.openbmc_project.State.Host", 2378 "/xyz/openbmc_project/state/host0", 2379 "org.freedesktop.DBus.Properties", "Set", 2380 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 2381 std::variant<std::string>{command}); 2382 } 2383 else 2384 { 2385 crow::connections::systemBus->async_method_call( 2386 [asyncResp, resetType](const boost::system::error_code ec) { 2387 if (ec) 2388 { 2389 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 2390 if (ec.value() == 2391 boost::asio::error::invalid_argument) 2392 { 2393 messages::actionParameterNotSupported( 2394 asyncResp->res, resetType, "Reset"); 2395 } 2396 else 2397 { 2398 messages::internalError(asyncResp->res); 2399 } 2400 return; 2401 } 2402 messages::success(asyncResp->res); 2403 }, 2404 "xyz.openbmc_project.State.Chassis", 2405 "/xyz/openbmc_project/state/chassis0", 2406 "org.freedesktop.DBus.Properties", "Set", 2407 "xyz.openbmc_project.State.Chassis", 2408 "RequestedPowerTransition", 2409 std::variant<std::string>{command}); 2410 } 2411 }); 2412 } 2413 2414 /** 2415 * Systems derived class for delivering Computer Systems Schema. 2416 */ 2417 inline void requestRoutesSystems(App& app) 2418 { 2419 2420 /** 2421 * Functions triggers appropriate requests on DBus 2422 */ 2423 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2424 .privileges(redfish::privileges::getComputerSystem) 2425 .methods( 2426 boost::beast::http::verb:: 2427 get)([](const crow::Request&, 2428 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2429 asyncResp->res.jsonValue["@odata.type"] = 2430 "#ComputerSystem.v1_15_0.ComputerSystem"; 2431 asyncResp->res.jsonValue["Name"] = "system"; 2432 asyncResp->res.jsonValue["Id"] = "system"; 2433 asyncResp->res.jsonValue["SystemType"] = "Physical"; 2434 asyncResp->res.jsonValue["Description"] = "Computer System"; 2435 asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; 2436 asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = 2437 "Disabled"; 2438 asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = 2439 uint64_t(0); 2440 asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = 2441 "Disabled"; 2442 asyncResp->res.jsonValue["@odata.id"] = 2443 "/redfish/v1/Systems/system"; 2444 2445 asyncResp->res.jsonValue["Processors"] = { 2446 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 2447 asyncResp->res.jsonValue["Memory"] = { 2448 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 2449 asyncResp->res.jsonValue["Storage"] = { 2450 {"@odata.id", "/redfish/v1/Systems/system/Storage"}}; 2451 2452 asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 2453 {"target", 2454 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 2455 {"@Redfish.ActionInfo", 2456 "/redfish/v1/Systems/system/ResetActionInfo"}}; 2457 2458 asyncResp->res.jsonValue["LogServices"] = { 2459 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 2460 2461 asyncResp->res.jsonValue["Bios"] = { 2462 {"@odata.id", "/redfish/v1/Systems/system/Bios"}}; 2463 2464 asyncResp->res.jsonValue["Links"]["ManagedBy"] = { 2465 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 2466 2467 asyncResp->res.jsonValue["Status"] = { 2468 {"Health", "OK"}, 2469 {"State", "Enabled"}, 2470 }; 2471 2472 // Fill in SerialConsole info 2473 asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 2474 15; 2475 asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = { 2476 {"ServiceEnabled", true}, 2477 }; 2478 // TODO (Gunnar): Should look for obmc-console-ssh@2200.service 2479 asyncResp->res.jsonValue["SerialConsole"]["SSH"] = { 2480 {"ServiceEnabled", true}, 2481 {"Port", 2200}, 2482 // https://github.com/openbmc/docs/blob/master/console.md 2483 {"HotKeySequenceDisplay", "Press ~. to exit console"}, 2484 }; 2485 2486 #ifdef BMCWEB_ENABLE_KVM 2487 // Fill in GraphicalConsole info 2488 asyncResp->res.jsonValue["GraphicalConsole"] = { 2489 {"ServiceEnabled", true}, 2490 {"MaxConcurrentSessions", 4}, 2491 {"ConnectTypesSupported", {"KVMIP"}}, 2492 }; 2493 #endif // BMCWEB_ENABLE_KVM 2494 constexpr const std::array<const char*, 4> inventoryForSystems = { 2495 "xyz.openbmc_project.Inventory.Item.Dimm", 2496 "xyz.openbmc_project.Inventory.Item.Cpu", 2497 "xyz.openbmc_project.Inventory.Item.Drive", 2498 "xyz.openbmc_project.Inventory.Item.StorageController"}; 2499 2500 auto health = std::make_shared<HealthPopulate>(asyncResp); 2501 crow::connections::systemBus->async_method_call( 2502 [health](const boost::system::error_code ec, 2503 std::vector<std::string>& resp) { 2504 if (ec) 2505 { 2506 // no inventory 2507 return; 2508 } 2509 2510 health->inventory = std::move(resp); 2511 }, 2512 "xyz.openbmc_project.ObjectMapper", 2513 "/xyz/openbmc_project/object_mapper", 2514 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 2515 int32_t(0), inventoryForSystems); 2516 2517 health->populate(); 2518 2519 getMainChassisId( 2520 asyncResp, [](const std::string& chassisId, 2521 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2522 aRsp->res.jsonValue["Links"]["Chassis"] = { 2523 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 2524 }); 2525 2526 getLocationIndicatorActive(asyncResp); 2527 // TODO (Gunnar): Remove IndicatorLED after enough time has passed 2528 getIndicatorLedState(asyncResp); 2529 getComputerSystem(asyncResp, health); 2530 getHostState(asyncResp); 2531 getBootProperties(asyncResp); 2532 getBootProgress(asyncResp); 2533 getPCIeDeviceList(asyncResp, "PCIeDevices"); 2534 getHostWatchdogTimer(asyncResp); 2535 getPowerRestorePolicy(asyncResp); 2536 getAutomaticRetry(asyncResp); 2537 getLastResetTime(asyncResp); 2538 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE 2539 getProvisioningStatus(asyncResp); 2540 #endif 2541 getTrustedModuleRequiredToBoot(asyncResp); 2542 getPowerMode(asyncResp); 2543 }); 2544 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") 2545 .privileges(redfish::privileges::patchComputerSystem) 2546 .methods(boost::beast::http::verb::patch)( 2547 [](const crow::Request& req, 2548 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2549 std::optional<bool> locationIndicatorActive; 2550 std::optional<std::string> indicatorLed; 2551 std::optional<nlohmann::json> bootProps; 2552 std::optional<nlohmann::json> wdtTimerProps; 2553 std::optional<std::string> assetTag; 2554 std::optional<std::string> powerRestorePolicy; 2555 std::optional<std::string> powerMode; 2556 2557 if (!json_util::readJson( 2558 req, asyncResp->res, "IndicatorLED", indicatorLed, 2559 "LocationIndicatorActive", locationIndicatorActive, 2560 "Boot", bootProps, "WatchdogTimer", wdtTimerProps, 2561 "PowerRestorePolicy", powerRestorePolicy, "AssetTag", 2562 assetTag, "PowerMode", powerMode)) 2563 { 2564 return; 2565 } 2566 2567 asyncResp->res.result(boost::beast::http::status::no_content); 2568 2569 if (assetTag) 2570 { 2571 setAssetTag(asyncResp, *assetTag); 2572 } 2573 2574 if (wdtTimerProps) 2575 { 2576 std::optional<bool> wdtEnable; 2577 std::optional<std::string> wdtTimeOutAction; 2578 2579 if (!json_util::readJson(*wdtTimerProps, asyncResp->res, 2580 "FunctionEnabled", wdtEnable, 2581 "TimeoutAction", wdtTimeOutAction)) 2582 { 2583 return; 2584 } 2585 setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); 2586 } 2587 2588 if (bootProps) 2589 { 2590 std::optional<std::string> bootSource; 2591 std::optional<std::string> bootEnable; 2592 std::optional<std::string> automaticRetryConfig; 2593 2594 if (!json_util::readJson( 2595 *bootProps, asyncResp->res, 2596 "BootSourceOverrideTarget", bootSource, 2597 "BootSourceOverrideEnabled", bootEnable, 2598 "AutomaticRetryConfig", automaticRetryConfig)) 2599 { 2600 return; 2601 } 2602 if (bootSource || bootEnable) 2603 { 2604 setBootSourceProperties(asyncResp, 2605 std::move(bootSource), 2606 std::move(bootEnable)); 2607 } 2608 if (automaticRetryConfig) 2609 { 2610 setAutomaticRetry(asyncResp, *automaticRetryConfig); 2611 } 2612 } 2613 2614 if (locationIndicatorActive) 2615 { 2616 setLocationIndicatorActive(asyncResp, 2617 *locationIndicatorActive); 2618 } 2619 2620 // TODO (Gunnar): Remove IndicatorLED after enough time has 2621 // passed 2622 if (indicatorLed) 2623 { 2624 setIndicatorLedState(asyncResp, *indicatorLed); 2625 asyncResp->res.addHeader( 2626 boost::beast::http::field::warning, 2627 "299 - \"IndicatorLED is deprecated. Use " 2628 "LocationIndicatorActive instead.\""); 2629 } 2630 2631 if (powerRestorePolicy) 2632 { 2633 setPowerRestorePolicy(asyncResp, *powerRestorePolicy); 2634 } 2635 2636 if (powerMode) 2637 { 2638 setPowerMode(asyncResp, *powerMode); 2639 } 2640 }); 2641 } 2642 2643 /** 2644 * SystemResetActionInfo derived class for delivering Computer Systems 2645 * ResetType AllowableValues using ResetInfo schema. 2646 */ 2647 inline void requestRoutesSystemResetActionInfo(App& app) 2648 { 2649 2650 /** 2651 * Functions triggers appropriate requests on DBus 2652 */ 2653 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") 2654 .privileges(redfish::privileges::getActionInfo) 2655 .methods(boost::beast::http::verb::get)( 2656 [](const crow::Request&, 2657 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2658 asyncResp->res.jsonValue = { 2659 {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2660 {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"}, 2661 {"Name", "Reset Action Info"}, 2662 {"Id", "ResetActionInfo"}, 2663 {"Parameters", 2664 {{{"Name", "ResetType"}, 2665 {"Required", true}, 2666 {"DataType", "String"}, 2667 {"AllowableValues", 2668 {"On", "ForceOff", "ForceOn", "ForceRestart", 2669 "GracefulRestart", "GracefulShutdown", "PowerCycle", 2670 "Nmi"}}}}}}; 2671 }); 2672 } 2673 } // namespace redfish 2674