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 <boost/container/flat_map.hpp> 19 #include <node.hpp> 20 #include <utils/fw_utils.hpp> 21 #include <utils/json_utils.hpp> 22 #include <variant> 23 24 namespace redfish 25 { 26 27 /** 28 * @brief Retrieves computer system properties over dbus 29 * 30 * @param[in] aResp Shared pointer for completing asynchronous calls 31 * @param[in] name Computer system name from request 32 * 33 * @return None. 34 */ 35 void getComputerSystem(std::shared_ptr<AsyncResp> aResp) 36 { 37 BMCWEB_LOG_DEBUG << "Get available system components."; 38 crow::connections::systemBus->async_method_call( 39 [aResp{std::move(aResp)}]( 40 const boost::system::error_code ec, 41 const std::vector<std::pair< 42 std::string, 43 std::vector<std::pair<std::string, std::vector<std::string>>>>> 44 &subtree) { 45 if (ec) 46 { 47 BMCWEB_LOG_DEBUG << "DBUS response error"; 48 messages::internalError(aResp->res); 49 return; 50 } 51 // Iterate over all retrieved ObjectPaths. 52 for (const std::pair<std::string, 53 std::vector<std::pair< 54 std::string, std::vector<std::string>>>> 55 &object : subtree) 56 { 57 const std::string &path = object.first; 58 BMCWEB_LOG_DEBUG << "Got path: " << path; 59 const std::vector< 60 std::pair<std::string, std::vector<std::string>>> 61 &connectionNames = object.second; 62 if (connectionNames.size() < 1) 63 { 64 continue; 65 } 66 67 // This is not system, so check if it's cpu, dimm, UUID or 68 // BiosVer 69 for (const auto &connection : connectionNames) 70 { 71 for (const auto &interfaceName : connection.second) 72 { 73 if (interfaceName == 74 "xyz.openbmc_project.Inventory.Item.Dimm") 75 { 76 BMCWEB_LOG_DEBUG 77 << "Found Dimm, now get its properties."; 78 crow::connections::systemBus->async_method_call( 79 [aResp](const boost::system::error_code ec, 80 const std::vector< 81 std::pair<std::string, VariantType>> 82 &properties) { 83 if (ec) 84 { 85 BMCWEB_LOG_ERROR 86 << "DBUS response error " << ec; 87 messages::internalError(aResp->res); 88 return; 89 } 90 BMCWEB_LOG_DEBUG << "Got " 91 << properties.size() 92 << "Dimm properties."; 93 for (const std::pair<std::string, 94 VariantType> 95 &property : properties) 96 { 97 if (property.first == "MemorySizeInKb") 98 { 99 const uint64_t *value = 100 sdbusplus::message::variant_ns:: 101 get_if<uint64_t>( 102 &property.second); 103 if (value != nullptr) 104 { 105 aResp->res.jsonValue 106 ["TotalSystemMemoryGi" 107 "B"] += 108 *value / (1024 * 1024); 109 aResp->res 110 .jsonValue["MemorySummary"] 111 ["Status"] 112 ["State"] = 113 "Enabled"; 114 } 115 } 116 } 117 }, 118 connection.first, path, 119 "org.freedesktop.DBus.Properties", "GetAll", 120 "xyz.openbmc_project.Inventory.Item.Dimm"); 121 } 122 else if (interfaceName == 123 "xyz.openbmc_project.Inventory.Item.Cpu") 124 { 125 BMCWEB_LOG_DEBUG 126 << "Found Cpu, now get its properties."; 127 crow::connections::systemBus->async_method_call( 128 [aResp](const boost::system::error_code ec, 129 const std::vector< 130 std::pair<std::string, VariantType>> 131 &properties) { 132 if (ec) 133 { 134 BMCWEB_LOG_ERROR 135 << "DBUS response error " << ec; 136 messages::internalError(aResp->res); 137 return; 138 } 139 BMCWEB_LOG_DEBUG << "Got " 140 << properties.size() 141 << "Cpu properties."; 142 for (const auto &property : properties) 143 { 144 if (property.first == "ProcessorFamily") 145 { 146 const std::string *value = 147 sdbusplus::message::variant_ns:: 148 get_if<std::string>( 149 &property.second); 150 if (value != nullptr) 151 { 152 nlohmann::json &procSummary = 153 aResp->res.jsonValue 154 ["ProcessorSumm" 155 "ary"]; 156 nlohmann::json &procCount = 157 procSummary["Count"]; 158 159 procCount = 160 procCount.get<int>() + 1; 161 procSummary["Status"]["State"] = 162 "Enabled"; 163 procSummary["Model"] = *value; 164 } 165 } 166 } 167 }, 168 connection.first, path, 169 "org.freedesktop.DBus.Properties", "GetAll", 170 "xyz.openbmc_project.Inventory.Item.Cpu"); 171 } 172 else if (interfaceName == 173 "xyz.openbmc_project.Common.UUID") 174 { 175 BMCWEB_LOG_DEBUG 176 << "Found UUID, now get its properties."; 177 crow::connections::systemBus->async_method_call( 178 [aResp](const boost::system::error_code ec, 179 const std::vector< 180 std::pair<std::string, VariantType>> 181 &properties) { 182 if (ec) 183 { 184 BMCWEB_LOG_DEBUG 185 << "DBUS response error " << ec; 186 messages::internalError(aResp->res); 187 return; 188 } 189 BMCWEB_LOG_DEBUG << "Got " 190 << properties.size() 191 << "UUID properties."; 192 for (const std::pair<std::string, 193 VariantType> 194 &property : properties) 195 { 196 if (property.first == "UUID") 197 { 198 const std::string *value = 199 sdbusplus::message::variant_ns:: 200 get_if<std::string>( 201 &property.second); 202 203 if (value != nullptr) 204 { 205 std::string valueStr = *value; 206 if (valueStr.size() == 32) 207 { 208 valueStr.insert(8, 1, '-'); 209 valueStr.insert(13, 1, '-'); 210 valueStr.insert(18, 1, '-'); 211 valueStr.insert(23, 1, '-'); 212 } 213 BMCWEB_LOG_DEBUG << "UUID = " 214 << valueStr; 215 aResp->res.jsonValue["UUID"] = 216 valueStr; 217 } 218 } 219 } 220 }, 221 connection.first, path, 222 "org.freedesktop.DBus.Properties", "GetAll", 223 "xyz.openbmc_project.Common.UUID"); 224 } 225 else if (interfaceName == 226 "xyz.openbmc_project.Inventory.Item.System") 227 { 228 crow::connections::systemBus->async_method_call( 229 [aResp](const boost::system::error_code ec, 230 const std::vector< 231 std::pair<std::string, VariantType>> 232 &propertiesList) { 233 if (ec) 234 { 235 BMCWEB_LOG_ERROR 236 << "DBUS response error: " << ec; 237 messages::internalError(aResp->res); 238 return; 239 } 240 BMCWEB_LOG_DEBUG << "Got " 241 << propertiesList.size() 242 << "properties for system"; 243 for (const std::pair<std::string, 244 VariantType> 245 &property : propertiesList) 246 { 247 const std::string &propertyName = 248 property.first; 249 if ((propertyName == "PartNumber") || 250 (propertyName == "SerialNumber") || 251 (propertyName == "Manufacturer") || 252 (propertyName == "Model")) 253 { 254 const std::string *value = 255 std::get_if<std::string>( 256 &property.second); 257 if (value != nullptr) 258 { 259 aResp->res 260 .jsonValue[propertyName] = 261 *value; 262 } 263 } 264 } 265 aResp->res.jsonValue["Name"] = "system"; 266 aResp->res.jsonValue["Id"] = 267 aResp->res.jsonValue["SerialNumber"]; 268 // Grab the bios version 269 fw_util::getActiveFwVersion( 270 aResp, fw_util::biosPurpose, 271 "BiosVersion"); 272 }, 273 connection.first, path, 274 "org.freedesktop.DBus.Properties", "GetAll", 275 "xyz.openbmc_project.Inventory.Decorator." 276 "Asset"); 277 } 278 } 279 } 280 } 281 }, 282 "xyz.openbmc_project.ObjectMapper", 283 "/xyz/openbmc_project/object_mapper", 284 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 285 "/xyz/openbmc_project/inventory", int32_t(0), 286 std::array<const char *, 5>{ 287 "xyz.openbmc_project.Inventory.Decorator.Asset", 288 "xyz.openbmc_project.Inventory.Item.Cpu", 289 "xyz.openbmc_project.Inventory.Item.Dimm", 290 "xyz.openbmc_project.Inventory.Item.System", 291 "xyz.openbmc_project.Common.UUID", 292 }); 293 } 294 295 /** 296 * @brief Retrieves identify led group properties over dbus 297 * 298 * @param[in] aResp Shared pointer for generating response message. 299 * @param[in] callback Callback for process retrieved data. 300 * 301 * @return None. 302 */ 303 template <typename CallbackFunc> 304 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp, 305 CallbackFunc &&callback) 306 { 307 BMCWEB_LOG_DEBUG << "Get led groups"; 308 crow::connections::systemBus->async_method_call( 309 [aResp{std::move(aResp)}, 310 callback{std::move(callback)}](const boost::system::error_code &ec, 311 const ManagedObjectsType &resp) { 312 if (ec) 313 { 314 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 315 messages::internalError(aResp->res); 316 return; 317 } 318 BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects."; 319 for (const auto &objPath : resp) 320 { 321 const std::string &path = objPath.first; 322 if (path.rfind("enclosure_identify") != std::string::npos) 323 { 324 for (const auto &interface : objPath.second) 325 { 326 if (interface.first == "xyz.openbmc_project.Led.Group") 327 { 328 for (const auto &property : interface.second) 329 { 330 if (property.first == "Asserted") 331 { 332 const bool *asserted = 333 std::get_if<bool>(&property.second); 334 if (nullptr != asserted) 335 { 336 callback(*asserted, aResp); 337 } 338 else 339 { 340 callback(false, aResp); 341 } 342 } 343 } 344 } 345 } 346 } 347 } 348 }, 349 "xyz.openbmc_project.LED.GroupManager", 350 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager", 351 "GetManagedObjects"); 352 } 353 354 template <typename CallbackFunc> 355 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback) 356 { 357 BMCWEB_LOG_DEBUG << "Get identify led properties"; 358 crow::connections::systemBus->async_method_call( 359 [aResp, 360 callback{std::move(callback)}](const boost::system::error_code ec, 361 const PropertiesType &properties) { 362 if (ec) 363 { 364 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 365 messages::internalError(aResp->res); 366 return; 367 } 368 BMCWEB_LOG_DEBUG << "Got " << properties.size() 369 << "led properties."; 370 std::string output; 371 for (const auto &property : properties) 372 { 373 if (property.first == "State") 374 { 375 const std::string *s = 376 std::get_if<std::string>(&property.second); 377 if (nullptr != s) 378 { 379 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s; 380 const auto pos = s->rfind('.'); 381 if (pos != std::string::npos) 382 { 383 auto led = s->substr(pos + 1); 384 for (const std::pair<const char *, const char *> 385 &p : 386 std::array< 387 std::pair<const char *, const char *>, 3>{ 388 {{"On", "Lit"}, 389 {"Blink", "Blinking"}, 390 {"Off", "Off"}}}) 391 { 392 if (led == p.first) 393 { 394 output = p.second; 395 } 396 } 397 } 398 } 399 } 400 } 401 callback(output, aResp); 402 }, 403 "xyz.openbmc_project.LED.Controller.identify", 404 "/xyz/openbmc_project/led/physical/identify", 405 "org.freedesktop.DBus.Properties", "GetAll", 406 "xyz.openbmc_project.Led.Physical"); 407 } 408 409 /** 410 * @brief Retrieves host state properties over dbus 411 * 412 * @param[in] aResp Shared pointer for completing asynchronous calls. 413 * 414 * @return None. 415 */ 416 void getHostState(std::shared_ptr<AsyncResp> aResp) 417 { 418 BMCWEB_LOG_DEBUG << "Get host information."; 419 crow::connections::systemBus->async_method_call( 420 [aResp{std::move(aResp)}](const boost::system::error_code ec, 421 const std::variant<std::string> &hostState) { 422 if (ec) 423 { 424 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 425 messages::internalError(aResp->res); 426 return; 427 } 428 429 const std::string *s = std::get_if<std::string>(&hostState); 430 BMCWEB_LOG_DEBUG << "Host state: " << *s; 431 if (s != nullptr) 432 { 433 // Verify Host State 434 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 435 { 436 aResp->res.jsonValue["PowerState"] = "On"; 437 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 438 } 439 else 440 { 441 aResp->res.jsonValue["PowerState"] = "Off"; 442 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 443 } 444 } 445 }, 446 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 447 "org.freedesktop.DBus.Properties", "Get", 448 "xyz.openbmc_project.State.Host", "CurrentHostState"); 449 } 450 451 /** 452 * @brief Traslates boot source DBUS property value to redfish. 453 * 454 * @param[in] dbusSource The boot source in DBUS speak. 455 * 456 * @return Returns as a string, the boot source in Redfish terms. If translation 457 * cannot be done, returns an empty string. 458 */ 459 static std::string dbusToRfBootSource(const std::string &dbusSource) 460 { 461 if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 462 { 463 return "None"; 464 } 465 else if (dbusSource == 466 "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") 467 { 468 return "Hdd"; 469 } 470 else if (dbusSource == 471 "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") 472 { 473 return "Cd"; 474 } 475 else if (dbusSource == 476 "xyz.openbmc_project.Control.Boot.Source.Sources.Network") 477 { 478 return "Pxe"; 479 } 480 else if (dbusSource == 481 "xyz.openbmc_project.Control.Boot.Source.Sources.Removable") 482 { 483 return "Usb"; 484 } 485 else 486 { 487 return ""; 488 } 489 } 490 491 /** 492 * @brief Traslates boot mode DBUS property value to redfish. 493 * 494 * @param[in] dbusMode The boot mode in DBUS speak. 495 * 496 * @return Returns as a string, the boot mode in Redfish terms. If translation 497 * cannot be done, returns an empty string. 498 */ 499 static std::string dbusToRfBootMode(const std::string &dbusMode) 500 { 501 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 502 { 503 return "None"; 504 } 505 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 506 { 507 return "Diags"; 508 } 509 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 510 { 511 return "BiosSetup"; 512 } 513 else 514 { 515 return ""; 516 } 517 } 518 519 /** 520 * @brief Traslates boot source from Redfish to DBUS property value. 521 * 522 * @param[in] rfSource The boot source in Redfish. 523 * 524 * @return Returns as a string, the boot source as expected by DBUS. 525 * If translation cannot be done, returns an empty string. 526 */ 527 static std::string rfToDbusBootSource(const std::string &rfSource) 528 { 529 if (rfSource == "None") 530 { 531 return "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 532 } 533 else if (rfSource == "Hdd") 534 { 535 return "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 536 } 537 else if (rfSource == "Cd") 538 { 539 return "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 540 } 541 else if (rfSource == "Pxe") 542 { 543 return "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 544 } 545 else if (rfSource == "Usb") 546 { 547 return "xyz.openbmc_project.Control.Boot.Source.Sources.Removable"; 548 } 549 else 550 { 551 return ""; 552 } 553 } 554 555 /** 556 * @brief Traslates boot mode from Redfish to DBUS property value. 557 * 558 * @param[in] rfMode The boot mode in Redfish. 559 * 560 * @return Returns as a string, the boot mode as expected by DBUS. 561 * If translation cannot be done, returns an empty string. 562 */ 563 static std::string rfToDbusBootMode(const std::string &rfMode) 564 { 565 if (rfMode == "None") 566 { 567 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 568 } 569 else if (rfMode == "Diags") 570 { 571 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 572 } 573 else if (rfMode == "BiosSetup") 574 { 575 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 576 } 577 else 578 { 579 return ""; 580 } 581 } 582 583 /** 584 * @brief Retrieves boot mode over DBUS and fills out the response 585 * 586 * @param[in] aResp Shared pointer for generating response message. 587 * @param[in] bootDbusObj The dbus object to query for boot properties. 588 * 589 * @return None. 590 */ 591 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 592 std::string bootDbusObj) 593 { 594 crow::connections::systemBus->async_method_call( 595 [aResp](const boost::system::error_code ec, 596 const std::variant<std::string> &bootMode) { 597 if (ec) 598 { 599 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 600 messages::internalError(aResp->res); 601 return; 602 } 603 604 const std::string *bootModeStr = 605 std::get_if<std::string>(&bootMode); 606 607 if (!bootModeStr) 608 { 609 messages::internalError(aResp->res); 610 return; 611 } 612 613 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 614 615 // TODO (Santosh): Do we need to support override mode? 616 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 617 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 618 "AllowableValues"] = { 619 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup"}; 620 621 if (*bootModeStr != 622 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 623 { 624 auto rfMode = dbusToRfBootMode(*bootModeStr); 625 if (!rfMode.empty()) 626 { 627 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 628 rfMode; 629 } 630 } 631 632 // If the BootSourceOverrideTarget is still "None" at the end, 633 // reset the BootSourceOverrideEnabled to indicate that 634 // overrides are disabled 635 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 636 "None") 637 { 638 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 639 "Disabled"; 640 } 641 }, 642 "xyz.openbmc_project.Settings", bootDbusObj, 643 "org.freedesktop.DBus.Properties", "Get", 644 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 645 } 646 647 /** 648 * @brief Retrieves boot source over DBUS 649 * 650 * @param[in] aResp Shared pointer for generating response message. 651 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 652 * 653 * @return None. 654 */ 655 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 656 { 657 std::string bootDbusObj = 658 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 659 : "/xyz/openbmc_project/control/host0/boot"; 660 661 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 662 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 663 (oneTimeEnabled) ? "Once" : "Continuous"; 664 665 crow::connections::systemBus->async_method_call( 666 [aResp, bootDbusObj](const boost::system::error_code ec, 667 const std::variant<std::string> &bootSource) { 668 if (ec) 669 { 670 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 671 messages::internalError(aResp->res); 672 return; 673 } 674 675 const std::string *bootSourceStr = 676 std::get_if<std::string>(&bootSource); 677 678 if (!bootSourceStr) 679 { 680 messages::internalError(aResp->res); 681 return; 682 } 683 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 684 685 auto rfSource = dbusToRfBootSource(*bootSourceStr); 686 if (!rfSource.empty()) 687 { 688 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 689 rfSource; 690 } 691 }, 692 "xyz.openbmc_project.Settings", bootDbusObj, 693 "org.freedesktop.DBus.Properties", "Get", 694 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 695 getBootMode(std::move(aResp), std::move(bootDbusObj)); 696 } 697 698 /** 699 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 700 * get boot source and boot mode. 701 * 702 * @param[in] aResp Shared pointer for generating response message. 703 * 704 * @return None. 705 */ 706 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 707 { 708 BMCWEB_LOG_DEBUG << "Get boot information."; 709 710 crow::connections::systemBus->async_method_call( 711 [aResp{std::move(aResp)}]( 712 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 auto asyncResp = std::make_shared<AsyncResp>(res); 1186 1187 getLedGroupIdentify( 1188 asyncResp, 1189 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) { 1190 if (asserted) 1191 { 1192 // If led group is asserted, then another call is needed to 1193 // get led status 1194 getLedIdentify( 1195 aResp, [](const std::string &ledStatus, 1196 const std::shared_ptr<AsyncResp> &aResp) { 1197 if (!ledStatus.empty()) 1198 { 1199 aResp->res.jsonValue["IndicatorLED"] = 1200 ledStatus; 1201 } 1202 }); 1203 } 1204 else 1205 { 1206 aResp->res.jsonValue["IndicatorLED"] = "Off"; 1207 } 1208 }); 1209 getComputerSystem(asyncResp); 1210 getHostState(asyncResp); 1211 getBootProperties(asyncResp); 1212 } 1213 1214 void doPatch(crow::Response &res, const crow::Request &req, 1215 const std::vector<std::string> ¶ms) override 1216 { 1217 std::optional<std::string> indicatorLed; 1218 std::optional<nlohmann::json> bootProps; 1219 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1220 bootProps)) 1221 { 1222 return; 1223 } 1224 1225 auto asyncResp = std::make_shared<AsyncResp>(res); 1226 asyncResp->res.result(boost::beast::http::status::no_content); 1227 1228 if (bootProps) 1229 { 1230 std::optional<std::string> bootSource; 1231 std::optional<std::string> bootEnable; 1232 1233 if (!json_util::readJson(*bootProps, asyncResp->res, 1234 "BootSourceOverrideTarget", bootSource, 1235 "BootSourceOverrideEnabled", bootEnable)) 1236 { 1237 return; 1238 } 1239 setBootProperties(asyncResp, std::move(bootSource), 1240 std::move(bootEnable)); 1241 } 1242 if (indicatorLed) 1243 { 1244 std::string dbusLedState; 1245 if (*indicatorLed == "Lit") 1246 { 1247 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On"; 1248 } 1249 else if (*indicatorLed == "Blinking") 1250 { 1251 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink"; 1252 } 1253 else if (*indicatorLed == "Off") 1254 { 1255 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 1256 } 1257 else 1258 { 1259 messages::propertyValueNotInList(res, *indicatorLed, 1260 "IndicatorLED"); 1261 return; 1262 } 1263 1264 // Update led group 1265 BMCWEB_LOG_DEBUG << "Update led group."; 1266 crow::connections::systemBus->async_method_call( 1267 [asyncResp](const boost::system::error_code ec) { 1268 if (ec) 1269 { 1270 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1271 messages::internalError(asyncResp->res); 1272 return; 1273 } 1274 BMCWEB_LOG_DEBUG << "Led group update done."; 1275 }, 1276 "xyz.openbmc_project.LED.GroupManager", 1277 "/xyz/openbmc_project/led/groups/enclosure_identify", 1278 "org.freedesktop.DBus.Properties", "Set", 1279 "xyz.openbmc_project.Led.Group", "Asserted", 1280 std::variant<bool>( 1281 (dbusLedState == 1282 "xyz.openbmc_project.Led.Physical.Action.Off" 1283 ? false 1284 : true))); 1285 // Update identify led status 1286 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 1287 crow::connections::systemBus->async_method_call( 1288 [asyncResp{std::move(asyncResp)}, 1289 indicatorLed{std::move(*indicatorLed)}]( 1290 const boost::system::error_code ec) { 1291 if (ec) 1292 { 1293 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1294 messages::internalError(asyncResp->res); 1295 return; 1296 } 1297 BMCWEB_LOG_DEBUG << "Led state update done."; 1298 }, 1299 "xyz.openbmc_project.LED.Controller.identify", 1300 "/xyz/openbmc_project/led/physical/identify", 1301 "org.freedesktop.DBus.Properties", "Set", 1302 "xyz.openbmc_project.Led.Physical", "State", 1303 std::variant<std::string>(dbusLedState)); 1304 } 1305 } 1306 }; 1307 } // namespace redfish 1308