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