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.DVD") 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.DVD"; 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 if (resetType == "ForceOff") 1031 { 1032 // Force off acts on the chassis 1033 crow::connections::systemBus->async_method_call( 1034 [asyncResp](const boost::system::error_code ec) { 1035 if (ec) 1036 { 1037 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1038 messages::internalError(asyncResp->res); 1039 return; 1040 } 1041 // TODO Consider support polling mechanism to verify 1042 // status of host and chassis after execute the 1043 // requested action. 1044 messages::success(asyncResp->res); 1045 }, 1046 "xyz.openbmc_project.State.Chassis", 1047 "/xyz/openbmc_project/state/chassis0", 1048 "org.freedesktop.DBus.Properties", "Set", 1049 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1050 std::variant<std::string>{ 1051 "xyz.openbmc_project.State.Chassis.Transition.Off"}); 1052 return; 1053 } 1054 // all other actions operate on the host 1055 std::string command; 1056 // Execute Reset Action regarding to each reset type. 1057 if (resetType == "On") 1058 { 1059 command = "xyz.openbmc_project.State.Host.Transition.On"; 1060 } 1061 else if (resetType == "GracefulShutdown") 1062 { 1063 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1064 } 1065 else if (resetType == "GracefulRestart") 1066 { 1067 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1068 } 1069 else 1070 { 1071 messages::actionParameterUnknown(res, "Reset", resetType); 1072 return; 1073 } 1074 1075 crow::connections::systemBus->async_method_call( 1076 [asyncResp](const boost::system::error_code ec) { 1077 if (ec) 1078 { 1079 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1080 messages::internalError(asyncResp->res); 1081 return; 1082 } 1083 // TODO Consider support polling mechanism to verify 1084 // status of host and chassis after execute the 1085 // requested action. 1086 messages::success(asyncResp->res); 1087 }, 1088 "xyz.openbmc_project.State.Host", 1089 "/xyz/openbmc_project/state/host0", 1090 "org.freedesktop.DBus.Properties", "Set", 1091 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1092 std::variant<std::string>{command}); 1093 } 1094 }; 1095 1096 /** 1097 * Systems derived class for delivering Computer Systems Schema. 1098 */ 1099 class Systems : public Node 1100 { 1101 public: 1102 /* 1103 * Default Constructor 1104 */ 1105 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1106 { 1107 entityPrivileges = { 1108 {boost::beast::http::verb::get, {{"Login"}}}, 1109 {boost::beast::http::verb::head, {{"Login"}}}, 1110 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1111 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1112 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1113 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1114 } 1115 1116 private: 1117 /** 1118 * Functions triggers appropriate requests on DBus 1119 */ 1120 void doGet(crow::Response &res, const crow::Request &req, 1121 const std::vector<std::string> ¶ms) override 1122 { 1123 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1124 res.jsonValue["@odata.context"] = 1125 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 1126 res.jsonValue["Name"] = "Computer System"; 1127 res.jsonValue["Id"] = "system"; 1128 res.jsonValue["SystemType"] = "Physical"; 1129 res.jsonValue["Description"] = "Computer System"; 1130 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1131 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1132 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 1133 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1134 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1135 1136 res.jsonValue["Processors"] = { 1137 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1138 res.jsonValue["Memory"] = { 1139 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1140 1141 // TODO Need to support ForceRestart. 1142 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1143 {"target", 1144 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1145 {"ResetType@Redfish.AllowableValues", 1146 {"On", "ForceOff", "GracefulRestart", "GracefulShutdown"}}}; 1147 1148 res.jsonValue["LogServices"] = { 1149 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1150 1151 auto asyncResp = std::make_shared<AsyncResp>(res); 1152 1153 getLedGroupIdentify( 1154 asyncResp, 1155 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) { 1156 if (asserted) 1157 { 1158 // If led group is asserted, then another call is needed to 1159 // get led status 1160 getLedIdentify( 1161 aResp, [](const std::string &ledStatus, 1162 const std::shared_ptr<AsyncResp> &aResp) { 1163 if (!ledStatus.empty()) 1164 { 1165 aResp->res.jsonValue["IndicatorLED"] = 1166 ledStatus; 1167 } 1168 }); 1169 } 1170 else 1171 { 1172 aResp->res.jsonValue["IndicatorLED"] = "Off"; 1173 } 1174 }); 1175 getComputerSystem(asyncResp); 1176 getHostState(asyncResp); 1177 getBootProperties(asyncResp); 1178 } 1179 1180 void doPatch(crow::Response &res, const crow::Request &req, 1181 const std::vector<std::string> ¶ms) override 1182 { 1183 std::optional<std::string> indicatorLed; 1184 std::optional<nlohmann::json> bootProps; 1185 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1186 bootProps)) 1187 { 1188 return; 1189 } 1190 1191 auto asyncResp = std::make_shared<AsyncResp>(res); 1192 asyncResp->res.result(boost::beast::http::status::no_content); 1193 1194 if (bootProps) 1195 { 1196 std::optional<std::string> bootSource; 1197 std::optional<std::string> bootEnable; 1198 1199 if (!json_util::readJson(*bootProps, asyncResp->res, 1200 "BootSourceOverrideTarget", bootSource, 1201 "BootSourceOverrideEnabled", bootEnable)) 1202 { 1203 return; 1204 } 1205 setBootProperties(asyncResp, std::move(bootSource), 1206 std::move(bootEnable)); 1207 } 1208 if (indicatorLed) 1209 { 1210 std::string dbusLedState; 1211 if (*indicatorLed == "Lit") 1212 { 1213 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On"; 1214 } 1215 else if (*indicatorLed == "Blinking") 1216 { 1217 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink"; 1218 } 1219 else if (*indicatorLed == "Off") 1220 { 1221 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 1222 } 1223 else 1224 { 1225 messages::propertyValueNotInList(res, *indicatorLed, 1226 "IndicatorLED"); 1227 return; 1228 } 1229 1230 // Update led group 1231 BMCWEB_LOG_DEBUG << "Update led group."; 1232 crow::connections::systemBus->async_method_call( 1233 [asyncResp](const boost::system::error_code ec) { 1234 if (ec) 1235 { 1236 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1237 messages::internalError(asyncResp->res); 1238 return; 1239 } 1240 BMCWEB_LOG_DEBUG << "Led group update done."; 1241 }, 1242 "xyz.openbmc_project.LED.GroupManager", 1243 "/xyz/openbmc_project/led/groups/enclosure_identify", 1244 "org.freedesktop.DBus.Properties", "Set", 1245 "xyz.openbmc_project.Led.Group", "Asserted", 1246 std::variant<bool>( 1247 (dbusLedState == 1248 "xyz.openbmc_project.Led.Physical.Action.Off" 1249 ? false 1250 : true))); 1251 // Update identify led status 1252 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 1253 crow::connections::systemBus->async_method_call( 1254 [asyncResp{std::move(asyncResp)}, 1255 indicatorLed{std::move(*indicatorLed)}]( 1256 const boost::system::error_code ec) { 1257 if (ec) 1258 { 1259 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1260 messages::internalError(asyncResp->res); 1261 return; 1262 } 1263 BMCWEB_LOG_DEBUG << "Led state update done."; 1264 }, 1265 "xyz.openbmc_project.LED.Controller.identify", 1266 "/xyz/openbmc_project/led/physical/identify", 1267 "org.freedesktop.DBus.Properties", "Set", 1268 "xyz.openbmc_project.Led.Physical", "State", 1269 std::variant<std::string>(dbusLedState)); 1270 } 1271 } 1272 }; 1273 } // namespace redfish 1274