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