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 "redfish_util.hpp" 19 20 #include <boost/container/flat_map.hpp> 21 #include <node.hpp> 22 #include <utils/fw_utils.hpp> 23 #include <utils/json_utils.hpp> 24 #include <variant> 25 26 namespace redfish 27 { 28 29 /** 30 * @brief Retrieves computer system properties over dbus 31 * 32 * @param[in] aResp Shared pointer for completing asynchronous calls 33 * @param[in] name Computer system name from request 34 * 35 * @return None. 36 */ 37 void getComputerSystem(std::shared_ptr<AsyncResp> aResp) 38 { 39 BMCWEB_LOG_DEBUG << "Get available system components."; 40 crow::connections::systemBus->async_method_call( 41 [aResp]( 42 const boost::system::error_code ec, 43 const std::vector<std::pair< 44 std::string, 45 std::vector<std::pair<std::string, std::vector<std::string>>>>> 46 &subtree) { 47 if (ec) 48 { 49 BMCWEB_LOG_DEBUG << "DBUS response error"; 50 messages::internalError(aResp->res); 51 return; 52 } 53 // Iterate over all retrieved ObjectPaths. 54 for (const std::pair<std::string, 55 std::vector<std::pair< 56 std::string, std::vector<std::string>>>> 57 &object : subtree) 58 { 59 const std::string &path = object.first; 60 BMCWEB_LOG_DEBUG << "Got path: " << path; 61 const std::vector< 62 std::pair<std::string, std::vector<std::string>>> 63 &connectionNames = object.second; 64 if (connectionNames.size() < 1) 65 { 66 continue; 67 } 68 69 // This is not system, so check if it's cpu, dimm, UUID or 70 // BiosVer 71 for (const auto &connection : connectionNames) 72 { 73 for (const auto &interfaceName : connection.second) 74 { 75 if (interfaceName == 76 "xyz.openbmc_project.Inventory.Item.Dimm") 77 { 78 BMCWEB_LOG_DEBUG 79 << "Found Dimm, now get its properties."; 80 crow::connections::systemBus->async_method_call( 81 [aResp](const boost::system::error_code ec, 82 const std::vector< 83 std::pair<std::string, VariantType>> 84 &properties) { 85 if (ec) 86 { 87 BMCWEB_LOG_ERROR 88 << "DBUS response error " << ec; 89 messages::internalError(aResp->res); 90 return; 91 } 92 BMCWEB_LOG_DEBUG << "Got " 93 << properties.size() 94 << "Dimm properties."; 95 for (const std::pair<std::string, 96 VariantType> 97 &property : properties) 98 { 99 if (property.first == "MemorySizeInKb") 100 { 101 const uint64_t *value = 102 sdbusplus::message::variant_ns:: 103 get_if<uint64_t>( 104 &property.second); 105 if (value != nullptr) 106 { 107 aResp->res.jsonValue 108 ["TotalSystemMemoryGi" 109 "B"] += 110 *value / (1024 * 1024); 111 aResp->res 112 .jsonValue["MemorySummary"] 113 ["Status"] 114 ["State"] = 115 "Enabled"; 116 } 117 } 118 } 119 }, 120 connection.first, path, 121 "org.freedesktop.DBus.Properties", "GetAll", 122 "xyz.openbmc_project.Inventory.Item.Dimm"); 123 } 124 else if (interfaceName == 125 "xyz.openbmc_project.Inventory.Item.Cpu") 126 { 127 BMCWEB_LOG_DEBUG 128 << "Found Cpu, now get its properties."; 129 crow::connections::systemBus->async_method_call( 130 [aResp](const boost::system::error_code ec, 131 const std::vector< 132 std::pair<std::string, VariantType>> 133 &properties) { 134 if (ec) 135 { 136 BMCWEB_LOG_ERROR 137 << "DBUS response error " << ec; 138 messages::internalError(aResp->res); 139 return; 140 } 141 BMCWEB_LOG_DEBUG << "Got " 142 << properties.size() 143 << "Cpu properties."; 144 for (const auto &property : properties) 145 { 146 if (property.first == "ProcessorFamily") 147 { 148 const std::string *value = 149 sdbusplus::message::variant_ns:: 150 get_if<std::string>( 151 &property.second); 152 if (value != nullptr) 153 { 154 nlohmann::json &procSummary = 155 aResp->res.jsonValue 156 ["ProcessorSumm" 157 "ary"]; 158 nlohmann::json &procCount = 159 procSummary["Count"]; 160 161 procCount = 162 procCount.get<int>() + 1; 163 procSummary["Status"]["State"] = 164 "Enabled"; 165 procSummary["Model"] = *value; 166 } 167 } 168 } 169 }, 170 connection.first, path, 171 "org.freedesktop.DBus.Properties", "GetAll", 172 "xyz.openbmc_project.Inventory.Item.Cpu"); 173 } 174 else if (interfaceName == 175 "xyz.openbmc_project.Common.UUID") 176 { 177 BMCWEB_LOG_DEBUG 178 << "Found UUID, now get its properties."; 179 crow::connections::systemBus->async_method_call( 180 [aResp](const boost::system::error_code ec, 181 const std::vector< 182 std::pair<std::string, VariantType>> 183 &properties) { 184 if (ec) 185 { 186 BMCWEB_LOG_DEBUG 187 << "DBUS response error " << ec; 188 messages::internalError(aResp->res); 189 return; 190 } 191 BMCWEB_LOG_DEBUG << "Got " 192 << properties.size() 193 << "UUID properties."; 194 for (const std::pair<std::string, 195 VariantType> 196 &property : properties) 197 { 198 if (property.first == "UUID") 199 { 200 const std::string *value = 201 sdbusplus::message::variant_ns:: 202 get_if<std::string>( 203 &property.second); 204 205 if (value != nullptr) 206 { 207 std::string valueStr = *value; 208 if (valueStr.size() == 32) 209 { 210 valueStr.insert(8, 1, '-'); 211 valueStr.insert(13, 1, '-'); 212 valueStr.insert(18, 1, '-'); 213 valueStr.insert(23, 1, '-'); 214 } 215 BMCWEB_LOG_DEBUG << "UUID = " 216 << valueStr; 217 aResp->res.jsonValue["UUID"] = 218 valueStr; 219 } 220 } 221 } 222 }, 223 connection.first, path, 224 "org.freedesktop.DBus.Properties", "GetAll", 225 "xyz.openbmc_project.Common.UUID"); 226 } 227 else if (interfaceName == 228 "xyz.openbmc_project.Inventory.Item.System") 229 { 230 crow::connections::systemBus->async_method_call( 231 [aResp](const boost::system::error_code ec, 232 const std::vector< 233 std::pair<std::string, VariantType>> 234 &propertiesList) { 235 if (ec) 236 { 237 BMCWEB_LOG_ERROR 238 << "DBUS response error: " << ec; 239 messages::internalError(aResp->res); 240 return; 241 } 242 BMCWEB_LOG_DEBUG << "Got " 243 << propertiesList.size() 244 << "properties for system"; 245 for (const std::pair<std::string, 246 VariantType> 247 &property : propertiesList) 248 { 249 const std::string &propertyName = 250 property.first; 251 if ((propertyName == "PartNumber") || 252 (propertyName == "SerialNumber") || 253 (propertyName == "Manufacturer") || 254 (propertyName == "Model")) 255 { 256 const std::string *value = 257 std::get_if<std::string>( 258 &property.second); 259 if (value != nullptr) 260 { 261 aResp->res 262 .jsonValue[propertyName] = 263 *value; 264 } 265 } 266 } 267 aResp->res.jsonValue["Name"] = "system"; 268 aResp->res.jsonValue["Id"] = 269 aResp->res.jsonValue["SerialNumber"]; 270 // Grab the bios version 271 fw_util::getActiveFwVersion( 272 aResp, fw_util::biosPurpose, 273 "BiosVersion"); 274 }, 275 connection.first, path, 276 "org.freedesktop.DBus.Properties", "GetAll", 277 "xyz.openbmc_project.Inventory.Decorator." 278 "Asset"); 279 } 280 } 281 } 282 } 283 }, 284 "xyz.openbmc_project.ObjectMapper", 285 "/xyz/openbmc_project/object_mapper", 286 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 287 "/xyz/openbmc_project/inventory", int32_t(0), 288 std::array<const char *, 5>{ 289 "xyz.openbmc_project.Inventory.Decorator.Asset", 290 "xyz.openbmc_project.Inventory.Item.Cpu", 291 "xyz.openbmc_project.Inventory.Item.Dimm", 292 "xyz.openbmc_project.Inventory.Item.System", 293 "xyz.openbmc_project.Common.UUID", 294 }); 295 } 296 297 /** 298 * @brief Retrieves identify led group properties over dbus 299 * 300 * @param[in] aResp Shared pointer for generating response message. 301 * @param[in] callback Callback for process retrieved data. 302 * 303 * @return None. 304 */ 305 template <typename CallbackFunc> 306 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp, 307 CallbackFunc &&callback) 308 { 309 BMCWEB_LOG_DEBUG << "Get led groups"; 310 crow::connections::systemBus->async_method_call( 311 [aResp, 312 callback{std::move(callback)}](const boost::system::error_code &ec, 313 const ManagedObjectsType &resp) { 314 if (ec) 315 { 316 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 317 messages::internalError(aResp->res); 318 return; 319 } 320 BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects."; 321 for (const auto &objPath : resp) 322 { 323 const std::string &path = objPath.first; 324 if (path.rfind("enclosure_identify") != std::string::npos) 325 { 326 for (const auto &interface : objPath.second) 327 { 328 if (interface.first == "xyz.openbmc_project.Led.Group") 329 { 330 for (const auto &property : interface.second) 331 { 332 if (property.first == "Asserted") 333 { 334 const bool *asserted = 335 std::get_if<bool>(&property.second); 336 if (nullptr != asserted) 337 { 338 callback(*asserted, aResp); 339 } 340 else 341 { 342 callback(false, aResp); 343 } 344 } 345 } 346 } 347 } 348 } 349 } 350 }, 351 "xyz.openbmc_project.LED.GroupManager", 352 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager", 353 "GetManagedObjects"); 354 } 355 356 template <typename CallbackFunc> 357 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback) 358 { 359 BMCWEB_LOG_DEBUG << "Get identify led properties"; 360 crow::connections::systemBus->async_method_call( 361 [aResp, 362 callback{std::move(callback)}](const boost::system::error_code ec, 363 const PropertiesType &properties) { 364 if (ec) 365 { 366 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 367 messages::internalError(aResp->res); 368 return; 369 } 370 BMCWEB_LOG_DEBUG << "Got " << properties.size() 371 << "led properties."; 372 std::string output; 373 for (const auto &property : properties) 374 { 375 if (property.first == "State") 376 { 377 const std::string *s = 378 std::get_if<std::string>(&property.second); 379 if (nullptr != s) 380 { 381 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s; 382 const auto pos = s->rfind('.'); 383 if (pos != std::string::npos) 384 { 385 auto led = s->substr(pos + 1); 386 for (const std::pair<const char *, const char *> 387 &p : 388 std::array< 389 std::pair<const char *, const char *>, 3>{ 390 {{"On", "Lit"}, 391 {"Blink", "Blinking"}, 392 {"Off", "Off"}}}) 393 { 394 if (led == p.first) 395 { 396 output = p.second; 397 } 398 } 399 } 400 } 401 } 402 } 403 callback(output, aResp); 404 }, 405 "xyz.openbmc_project.LED.Controller.identify", 406 "/xyz/openbmc_project/led/physical/identify", 407 "org.freedesktop.DBus.Properties", "GetAll", 408 "xyz.openbmc_project.Led.Physical"); 409 } 410 /** 411 * @brief Retrieves host state properties over dbus 412 * 413 * @param[in] aResp Shared pointer for completing asynchronous calls. 414 * 415 * @return None. 416 */ 417 void getHostState(std::shared_ptr<AsyncResp> aResp) 418 { 419 BMCWEB_LOG_DEBUG << "Get host information."; 420 crow::connections::systemBus->async_method_call( 421 [aResp](const boost::system::error_code ec, 422 const std::variant<std::string> &hostState) { 423 if (ec) 424 { 425 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 426 messages::internalError(aResp->res); 427 return; 428 } 429 430 const std::string *s = std::get_if<std::string>(&hostState); 431 BMCWEB_LOG_DEBUG << "Host state: " << *s; 432 if (s != nullptr) 433 { 434 // Verify Host State 435 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 436 { 437 aResp->res.jsonValue["PowerState"] = "On"; 438 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 439 } 440 else 441 { 442 aResp->res.jsonValue["PowerState"] = "Off"; 443 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 444 } 445 } 446 }, 447 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 448 "org.freedesktop.DBus.Properties", "Get", 449 "xyz.openbmc_project.State.Host", "CurrentHostState"); 450 } 451 452 /** 453 * @brief Traslates boot source DBUS property value to redfish. 454 * 455 * @param[in] dbusSource The boot source in DBUS speak. 456 * 457 * @return Returns as a string, the boot source in Redfish terms. If translation 458 * cannot be done, returns an empty string. 459 */ 460 static std::string dbusToRfBootSource(const std::string &dbusSource) 461 { 462 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 463 { 464 return "None"; 465 } 466 else if (dbusSource == 467 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 468 { 469 return "Hdd"; 470 } 471 else if (dbusSource == 472 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 473 { 474 return "Cd"; 475 } 476 else if (dbusSource == 477 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 478 { 479 return "Pxe"; 480 } 481 else if (dbusSource == 482 "xyz.openbmc_project.Control.Boot.Source.Sources.Removable") 483 { 484 return "Usb"; 485 } 486 else 487 { 488 return ""; 489 } 490 } 491 492 /** 493 * @brief Traslates boot mode DBUS property value to redfish. 494 * 495 * @param[in] dbusMode The boot mode in DBUS speak. 496 * 497 * @return Returns as a string, the boot mode in Redfish terms. If translation 498 * cannot be done, returns an empty string. 499 */ 500 static std::string dbusToRfBootMode(const std::string &dbusMode) 501 { 502 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 503 { 504 return "None"; 505 } 506 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 507 { 508 return "Diags"; 509 } 510 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 511 { 512 return "BiosSetup"; 513 } 514 else 515 { 516 return ""; 517 } 518 } 519 520 /** 521 * @brief Traslates boot source from Redfish to DBUS property value. 522 * 523 * @param[in] rfSource The boot source in Redfish. 524 * 525 * @return Returns as a string, the boot source as expected by DBUS. 526 * If translation cannot be done, returns an empty string. 527 */ 528 static std::string rfToDbusBootSource(const std::string &rfSource) 529 { 530 if (rfSource == "None") 531 { 532 return "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 533 } 534 else if (rfSource == "Hdd") 535 { 536 return "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 537 } 538 else if (rfSource == "Cd") 539 { 540 return "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 541 } 542 else if (rfSource == "Pxe") 543 { 544 return "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 545 } 546 else if (rfSource == "Usb") 547 { 548 return "xyz.openbmc_project.Control.Boot.Source.Sources.Removable"; 549 } 550 else 551 { 552 return ""; 553 } 554 } 555 556 /** 557 * @brief Traslates boot mode from Redfish to DBUS property value. 558 * 559 * @param[in] rfMode The boot mode in Redfish. 560 * 561 * @return Returns as a string, the boot mode as expected by DBUS. 562 * If translation cannot be done, returns an empty string. 563 */ 564 static std::string rfToDbusBootMode(const std::string &rfMode) 565 { 566 if (rfMode == "None") 567 { 568 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 569 } 570 else if (rfMode == "Diags") 571 { 572 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 573 } 574 else if (rfMode == "BiosSetup") 575 { 576 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 577 } 578 else 579 { 580 return ""; 581 } 582 } 583 584 /** 585 * @brief Retrieves boot mode over DBUS and fills out the response 586 * 587 * @param[in] aResp Shared pointer for generating response message. 588 * @param[in] bootDbusObj The dbus object to query for boot properties. 589 * 590 * @return None. 591 */ 592 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 593 std::string bootDbusObj) 594 { 595 crow::connections::systemBus->async_method_call( 596 [aResp](const boost::system::error_code ec, 597 const std::variant<std::string> &bootMode) { 598 if (ec) 599 { 600 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 601 messages::internalError(aResp->res); 602 return; 603 } 604 605 const std::string *bootModeStr = 606 std::get_if<std::string>(&bootMode); 607 608 if (!bootModeStr) 609 { 610 messages::internalError(aResp->res); 611 return; 612 } 613 614 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 615 616 // TODO (Santosh): Do we need to support override mode? 617 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 618 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 619 "AllowableValues"] = { 620 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup"}; 621 622 if (*bootModeStr != 623 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 624 { 625 auto rfMode = dbusToRfBootMode(*bootModeStr); 626 if (!rfMode.empty()) 627 { 628 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 629 rfMode; 630 } 631 } 632 633 // If the BootSourceOverrideTarget is still "None" at the end, 634 // reset the BootSourceOverrideEnabled to indicate that 635 // overrides are disabled 636 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 637 "None") 638 { 639 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 640 "Disabled"; 641 } 642 }, 643 "xyz.openbmc_project.Settings", bootDbusObj, 644 "org.freedesktop.DBus.Properties", "Get", 645 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 646 } 647 648 /** 649 * @brief Retrieves boot source over DBUS 650 * 651 * @param[in] aResp Shared pointer for generating response message. 652 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 653 * 654 * @return None. 655 */ 656 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 657 { 658 std::string bootDbusObj = 659 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 660 : "/xyz/openbmc_project/control/host0/boot"; 661 662 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 663 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 664 (oneTimeEnabled) ? "Once" : "Continuous"; 665 666 crow::connections::systemBus->async_method_call( 667 [aResp, bootDbusObj](const boost::system::error_code ec, 668 const std::variant<std::string> &bootSource) { 669 if (ec) 670 { 671 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 672 messages::internalError(aResp->res); 673 return; 674 } 675 676 const std::string *bootSourceStr = 677 std::get_if<std::string>(&bootSource); 678 679 if (!bootSourceStr) 680 { 681 messages::internalError(aResp->res); 682 return; 683 } 684 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 685 686 auto rfSource = dbusToRfBootSource(*bootSourceStr); 687 if (!rfSource.empty()) 688 { 689 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 690 rfSource; 691 } 692 }, 693 "xyz.openbmc_project.Settings", bootDbusObj, 694 "org.freedesktop.DBus.Properties", "Get", 695 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 696 getBootMode(std::move(aResp), std::move(bootDbusObj)); 697 } 698 699 /** 700 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 701 * get boot source and boot mode. 702 * 703 * @param[in] aResp Shared pointer for generating response message. 704 * 705 * @return None. 706 */ 707 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 708 { 709 BMCWEB_LOG_DEBUG << "Get boot information."; 710 711 crow::connections::systemBus->async_method_call( 712 [aResp](const boost::system::error_code ec, 713 const sdbusplus::message::variant<bool> &oneTime) { 714 if (ec) 715 { 716 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 717 messages::internalError(aResp->res); 718 return; 719 } 720 721 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 722 723 if (!oneTimePtr) 724 { 725 messages::internalError(aResp->res); 726 return; 727 } 728 getBootSource(aResp, *oneTimePtr); 729 }, 730 "xyz.openbmc_project.Settings", 731 "/xyz/openbmc_project/control/host0/boot/one_time", 732 "org.freedesktop.DBus.Properties", "Get", 733 "xyz.openbmc_project.Object.Enable", "Enabled"); 734 } 735 736 /** 737 * @brief Sets boot properties into DBUS object(s). 738 * 739 * @param[in] aResp Shared pointer for generating response message. 740 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 741 * @param[in] bootSource The boot source to set. 742 * @param[in] bootEnable The source override "enable" to set. 743 * 744 * @return None. 745 */ 746 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 747 bool oneTimeEnabled, 748 std::optional<std::string> bootSource, 749 std::optional<std::string> bootEnable) 750 { 751 if (bootEnable && (bootEnable != "Once") && (bootEnable != "Continuous") && 752 (bootEnable != "Disabled")) 753 { 754 BMCWEB_LOG_DEBUG << "Unsupported value for BootSourceOverrideEnabled: " 755 << *bootEnable; 756 messages::propertyValueNotInList(aResp->res, *bootEnable, 757 "BootSourceOverrideEnabled"); 758 return; 759 } 760 761 bool oneTimeSetting = oneTimeEnabled; 762 // Validate incoming parameters 763 if (bootEnable) 764 { 765 if (*bootEnable == "Once") 766 { 767 oneTimeSetting = true; 768 } 769 else if (*bootEnable == "Continuous") 770 { 771 oneTimeSetting = false; 772 } 773 else if (*bootEnable == "Disabled") 774 { 775 oneTimeSetting = false; 776 } 777 else 778 { 779 780 BMCWEB_LOG_DEBUG << "Unsupported value for " 781 "BootSourceOverrideEnabled: " 782 << *bootEnable; 783 messages::propertyValueNotInList(aResp->res, *bootEnable, 784 "BootSourceOverrideEnabled"); 785 return; 786 } 787 } 788 std::string bootSourceStr; 789 std::string bootModeStr; 790 if (bootSource) 791 { 792 bootSourceStr = rfToDbusBootSource(*bootSource); 793 bootModeStr = rfToDbusBootMode(*bootSource); 794 795 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 796 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 797 798 if (bootSourceStr.empty() && bootModeStr.empty()) 799 { 800 BMCWEB_LOG_DEBUG << "Invalid property value for " 801 "BootSourceOverrideTarget: " 802 << *bootSource; 803 messages::propertyValueNotInList(aResp->res, *bootSource, 804 "BootSourceTargetOverride"); 805 return; 806 } 807 } 808 const char *bootObj = 809 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 810 : "/xyz/openbmc_project/control/host0/boot"; 811 // Figure out what properties to set 812 if (bootEnable && (*bootEnable == "Disabled")) 813 { 814 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 815 // Request to only turn OFF/ON enabled, if turning enabled OFF, need 816 // to reset the source and mode too. If turning it ON, we only need 817 // to set the enabled property 818 bootSourceStr = 819 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 820 bootModeStr = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 821 } 822 else if (bootSource) 823 { 824 // Source target specified 825 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 826 // Figure out which DBUS interface and property to use 827 bootSourceStr = rfToDbusBootSource(*bootSource); 828 bootModeStr = rfToDbusBootMode(*bootSource); 829 830 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 831 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 832 833 if (bootSourceStr.empty() && bootModeStr.empty()) 834 { 835 BMCWEB_LOG_DEBUG << "Invalid property value for " 836 "BootSourceOverrideTarget: " 837 << *bootSource; 838 messages::propertyValueNotInList(aResp->res, *bootSource, 839 "BootSourceTargetOverride"); 840 return; 841 } 842 843 if (!bootSourceStr.empty()) 844 { 845 // If setting to anything other than default, also reset boot 846 // mode property 847 if (bootSourceStr != 848 "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 849 { 850 bootModeStr = 851 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 852 } 853 } 854 else // if (!bootModeStr.empty()) 855 { 856 // If setting to anything other than default, also reset boot 857 // source property 858 if (bootModeStr != 859 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 860 { 861 bootSourceStr = 862 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 863 } 864 } 865 } 866 if (!bootSourceStr.empty()) 867 { 868 crow::connections::systemBus->async_method_call( 869 [aResp](const boost::system::error_code ec) { 870 if (ec) 871 { 872 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 873 messages::internalError(aResp->res); 874 return; 875 } 876 BMCWEB_LOG_DEBUG << "Boot source update done."; 877 }, 878 "xyz.openbmc_project.Settings", bootObj, 879 "org.freedesktop.DBus.Properties", "Set", 880 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 881 std::variant<std::string>(bootSourceStr)); 882 } 883 if (!bootModeStr.empty()) 884 { 885 crow::connections::systemBus->async_method_call( 886 [aResp](const boost::system::error_code ec) { 887 if (ec) 888 { 889 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 890 messages::internalError(aResp->res); 891 return; 892 } 893 BMCWEB_LOG_DEBUG << "Boot mode update done."; 894 }, 895 "xyz.openbmc_project.Settings", bootObj, 896 "org.freedesktop.DBus.Properties", "Set", 897 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 898 std::variant<std::string>(bootModeStr)); 899 } 900 crow::connections::systemBus->async_method_call( 901 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 902 if (ec) 903 { 904 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 905 messages::internalError(aResp->res); 906 return; 907 } 908 BMCWEB_LOG_DEBUG << "Boot enable update done."; 909 }, 910 "xyz.openbmc_project.Settings", 911 "/xyz/openbmc_project/control/host0/boot/one_time", 912 "org.freedesktop.DBus.Properties", "Set", 913 "xyz.openbmc_project.Object.Enable", "Enabled", 914 std::variant<bool>(oneTimeSetting)); 915 } 916 917 /** 918 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 919 * set boot source/boot mode properties. 920 * 921 * @param[in] aResp Shared pointer for generating response message. 922 * @param[in] bootSource The boot source from incoming RF request. 923 * @param[in] bootEnable The boot override enable from incoming RF request. 924 * 925 * @return None. 926 */ 927 static void setBootProperties(std::shared_ptr<AsyncResp> aResp, 928 std::optional<std::string> bootSource, 929 std::optional<std::string> bootEnable) 930 { 931 BMCWEB_LOG_DEBUG << "Set boot information."; 932 933 crow::connections::systemBus->async_method_call( 934 [aResp{std::move(aResp)}, bootSource{std::move(bootSource)}, 935 bootEnable{std::move(bootEnable)}]( 936 const boost::system::error_code ec, 937 const sdbusplus::message::variant<bool> &oneTime) { 938 if (ec) 939 { 940 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 941 messages::internalError(aResp->res); 942 return; 943 } 944 945 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 946 947 if (!oneTimePtr) 948 { 949 messages::internalError(aResp->res); 950 return; 951 } 952 953 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 954 955 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 956 std::move(bootEnable)); 957 }, 958 "xyz.openbmc_project.Settings", 959 "/xyz/openbmc_project/control/host0/boot/one_time", 960 "org.freedesktop.DBus.Properties", "Get", 961 "xyz.openbmc_project.Object.Enable", "Enabled"); 962 } 963 964 /** 965 * SystemsCollection derived class for delivering ComputerSystems Collection 966 * Schema 967 */ 968 class SystemsCollection : public Node 969 { 970 public: 971 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 972 { 973 entityPrivileges = { 974 {boost::beast::http::verb::get, {{"Login"}}}, 975 {boost::beast::http::verb::head, {{"Login"}}}, 976 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 977 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 978 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 979 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 980 } 981 982 private: 983 void doGet(crow::Response &res, const crow::Request &req, 984 const std::vector<std::string> ¶ms) override 985 { 986 res.jsonValue["@odata.type"] = 987 "#ComputerSystemCollection.ComputerSystemCollection"; 988 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 989 res.jsonValue["@odata.context"] = 990 "/redfish/v1/" 991 "$metadata#ComputerSystemCollection.ComputerSystemCollection"; 992 res.jsonValue["Name"] = "Computer System Collection"; 993 res.jsonValue["Members"] = { 994 {{"@odata.id", "/redfish/v1/Systems/system"}}}; 995 res.jsonValue["Members@odata.count"] = 1; 996 res.end(); 997 } 998 }; 999 1000 /** 1001 * SystemActionsReset class supports handle POST method for Reset action. 1002 * The class retrieves and sends data directly to D-Bus. 1003 */ 1004 class SystemActionsReset : public Node 1005 { 1006 public: 1007 SystemActionsReset(CrowApp &app) : 1008 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1009 { 1010 entityPrivileges = { 1011 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1012 } 1013 1014 private: 1015 /** 1016 * Function handles POST method request. 1017 * Analyzes POST body message before sends Reset request data to D-Bus. 1018 */ 1019 void doPost(crow::Response &res, const crow::Request &req, 1020 const std::vector<std::string> ¶ms) override 1021 { 1022 auto asyncResp = std::make_shared<AsyncResp>(res); 1023 1024 std::string resetType; 1025 if (!json_util::readJson(req, res, "ResetType", resetType)) 1026 { 1027 return; 1028 } 1029 1030 // Get the command and host vs. chassis 1031 std::string command; 1032 bool hostCommand; 1033 if (resetType == "On") 1034 { 1035 command = "xyz.openbmc_project.State.Host.Transition.On"; 1036 hostCommand = true; 1037 } 1038 else if (resetType == "ForceOff") 1039 { 1040 command = "xyz.openbmc_project.State.Chassis.Transition.Off"; 1041 hostCommand = false; 1042 } 1043 else if (resetType == "ForceOn") 1044 { 1045 command = "xyz.openbmc_project.State.Host.Transition.On"; 1046 hostCommand = true; 1047 } 1048 else if (resetType == "ForceRestart") 1049 { 1050 command = "xyz.openbmc_project.State.Chassis.Transition.Reset"; 1051 hostCommand = false; 1052 } 1053 else if (resetType == "GracefulShutdown") 1054 { 1055 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1056 hostCommand = true; 1057 } 1058 else if (resetType == "GracefulRestart") 1059 { 1060 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1061 hostCommand = true; 1062 } 1063 else if (resetType == "PowerCycle") 1064 { 1065 command = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle"; 1066 hostCommand = false; 1067 } 1068 else 1069 { 1070 messages::actionParameterUnknown(res, "Reset", resetType); 1071 return; 1072 } 1073 1074 if (hostCommand) 1075 { 1076 crow::connections::systemBus->async_method_call( 1077 [asyncResp, resetType](const boost::system::error_code ec) { 1078 if (ec) 1079 { 1080 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1081 if (ec.value() == boost::asio::error::invalid_argument) 1082 { 1083 messages::actionParameterNotSupported( 1084 asyncResp->res, resetType, "Reset"); 1085 } 1086 else 1087 { 1088 messages::internalError(asyncResp->res); 1089 } 1090 return; 1091 } 1092 messages::success(asyncResp->res); 1093 }, 1094 "xyz.openbmc_project.State.Host", 1095 "/xyz/openbmc_project/state/host0", 1096 "org.freedesktop.DBus.Properties", "Set", 1097 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1098 std::variant<std::string>{command}); 1099 } 1100 else 1101 { 1102 crow::connections::systemBus->async_method_call( 1103 [asyncResp, resetType](const boost::system::error_code ec) { 1104 if (ec) 1105 { 1106 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1107 if (ec.value() == boost::asio::error::invalid_argument) 1108 { 1109 messages::actionParameterNotSupported( 1110 asyncResp->res, resetType, "Reset"); 1111 } 1112 else 1113 { 1114 messages::internalError(asyncResp->res); 1115 } 1116 return; 1117 } 1118 messages::success(asyncResp->res); 1119 }, 1120 "xyz.openbmc_project.State.Chassis", 1121 "/xyz/openbmc_project/state/chassis0", 1122 "org.freedesktop.DBus.Properties", "Set", 1123 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1124 std::variant<std::string>{command}); 1125 } 1126 } 1127 }; 1128 1129 /** 1130 * Systems derived class for delivering Computer Systems Schema. 1131 */ 1132 class Systems : public Node 1133 { 1134 public: 1135 /* 1136 * Default Constructor 1137 */ 1138 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1139 { 1140 entityPrivileges = { 1141 {boost::beast::http::verb::get, {{"Login"}}}, 1142 {boost::beast::http::verb::head, {{"Login"}}}, 1143 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1144 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1145 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1146 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1147 } 1148 1149 private: 1150 /** 1151 * Functions triggers appropriate requests on DBus 1152 */ 1153 void doGet(crow::Response &res, const crow::Request &req, 1154 const std::vector<std::string> ¶ms) override 1155 { 1156 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1157 res.jsonValue["@odata.context"] = 1158 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 1159 res.jsonValue["Name"] = "Computer System"; 1160 res.jsonValue["Id"] = "system"; 1161 res.jsonValue["SystemType"] = "Physical"; 1162 res.jsonValue["Description"] = "Computer System"; 1163 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1164 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1165 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 1166 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1167 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1168 1169 res.jsonValue["Processors"] = { 1170 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1171 res.jsonValue["Memory"] = { 1172 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1173 1174 // TODO Need to support ForceRestart. 1175 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1176 {"target", 1177 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1178 {"ResetType@Redfish.AllowableValues", 1179 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart", 1180 "GracefulShutdown", "PowerCycle"}}}; 1181 1182 res.jsonValue["LogServices"] = { 1183 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1184 1185 res.jsonValue["Links"]["ManagedBy"] = { 1186 {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 1187 1188 res.jsonValue["Status"] = { 1189 {"Health", "OK"}, 1190 {"State", "Enabled"}, 1191 }; 1192 auto asyncResp = std::make_shared<AsyncResp>(res); 1193 1194 crow::connections::systemBus->async_method_call( 1195 [asyncResp](const boost::system::error_code ec, 1196 const VariantType &biosId) { 1197 if (ec) 1198 { 1199 BMCWEB_LOG_ERROR << ec; 1200 messages::internalError(asyncResp->res); 1201 return; 1202 } 1203 const std::string *strBiosId = 1204 std::get_if<std::string>(&biosId); 1205 if (strBiosId != nullptr) 1206 { 1207 BMCWEB_LOG_DEBUG << "bios ver. = " << strBiosId; 1208 asyncResp->res.jsonValue["BiosVersion"] = *strBiosId; 1209 } 1210 }, 1211 "xyz.openbmc_project.Settings", "/xyz/openbmc_project/bios", 1212 "org.freedesktop.DBus.Properties", "Get", 1213 "xyz.openbmc_project.Inventory.Item.Bios", "BiosId"); 1214 1215 getMainChassisId(asyncResp, [](const std::string &chassisId, 1216 std::shared_ptr<AsyncResp> aRsp) { 1217 aRsp->res.jsonValue["Links"]["Chassis"] = { 1218 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 1219 }); 1220 getLedGroupIdentify( 1221 asyncResp, 1222 [](const bool &asserted, const std::shared_ptr<AsyncResp> aRsp) { 1223 if (asserted) 1224 { 1225 // If led group is asserted, then another call is needed to 1226 // get led status 1227 getLedIdentify( 1228 aRsp, [](const std::string &ledStatus, 1229 const std::shared_ptr<AsyncResp> aRsp) { 1230 if (!ledStatus.empty()) 1231 { 1232 aRsp->res.jsonValue["IndicatorLED"] = ledStatus; 1233 } 1234 }); 1235 } 1236 else 1237 { 1238 aRsp->res.jsonValue["IndicatorLED"] = "Off"; 1239 } 1240 }); 1241 getComputerSystem(asyncResp); 1242 getHostState(asyncResp); 1243 getBootProperties(asyncResp); 1244 } 1245 1246 void doPatch(crow::Response &res, const crow::Request &req, 1247 const std::vector<std::string> ¶ms) override 1248 { 1249 std::optional<std::string> indicatorLed; 1250 std::optional<nlohmann::json> bootProps; 1251 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1252 bootProps)) 1253 { 1254 return; 1255 } 1256 1257 auto asyncResp = std::make_shared<AsyncResp>(res); 1258 asyncResp->res.result(boost::beast::http::status::no_content); 1259 1260 if (bootProps) 1261 { 1262 std::optional<std::string> bootSource; 1263 std::optional<std::string> bootEnable; 1264 1265 if (!json_util::readJson(*bootProps, asyncResp->res, 1266 "BootSourceOverrideTarget", bootSource, 1267 "BootSourceOverrideEnabled", bootEnable)) 1268 { 1269 return; 1270 } 1271 setBootProperties(asyncResp, std::move(bootSource), 1272 std::move(bootEnable)); 1273 } 1274 if (indicatorLed) 1275 { 1276 std::string dbusLedState; 1277 if (*indicatorLed == "Lit") 1278 { 1279 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On"; 1280 } 1281 else if (*indicatorLed == "Blinking") 1282 { 1283 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink"; 1284 } 1285 else if (*indicatorLed == "Off") 1286 { 1287 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 1288 } 1289 else 1290 { 1291 messages::propertyValueNotInList(res, *indicatorLed, 1292 "IndicatorLED"); 1293 return; 1294 } 1295 1296 // Update led group 1297 BMCWEB_LOG_DEBUG << "Update led group."; 1298 crow::connections::systemBus->async_method_call( 1299 [asyncResp](const boost::system::error_code ec) { 1300 if (ec) 1301 { 1302 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1303 messages::internalError(asyncResp->res); 1304 return; 1305 } 1306 BMCWEB_LOG_DEBUG << "Led group update done."; 1307 }, 1308 "xyz.openbmc_project.LED.GroupManager", 1309 "/xyz/openbmc_project/led/groups/enclosure_identify", 1310 "org.freedesktop.DBus.Properties", "Set", 1311 "xyz.openbmc_project.Led.Group", "Asserted", 1312 std::variant<bool>( 1313 (dbusLedState == 1314 "xyz.openbmc_project.Led.Physical.Action.Off" 1315 ? false 1316 : true))); 1317 // Update identify led status 1318 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 1319 crow::connections::systemBus->async_method_call( 1320 [asyncResp{std::move(asyncResp)}, 1321 indicatorLed{std::move(*indicatorLed)}]( 1322 const boost::system::error_code ec) { 1323 if (ec) 1324 { 1325 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1326 messages::internalError(asyncResp->res); 1327 return; 1328 } 1329 BMCWEB_LOG_DEBUG << "Led state update done."; 1330 }, 1331 "xyz.openbmc_project.LED.Controller.identify", 1332 "/xyz/openbmc_project/led/physical/identify", 1333 "org.freedesktop.DBus.Properties", "Set", 1334 "xyz.openbmc_project.Led.Physical", "State", 1335 std::variant<std::string>(dbusLedState)); 1336 } 1337 } 1338 }; 1339 } // namespace redfish 1340