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