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 481 { 482 return ""; 483 } 484 } 485 486 /** 487 * @brief Traslates boot mode DBUS property value to redfish. 488 * 489 * @param[in] dbusMode The boot mode in DBUS speak. 490 * 491 * @return Returns as a string, the boot mode in Redfish terms. If translation 492 * cannot be done, returns an empty string. 493 */ 494 static std::string dbusToRfBootMode(const std::string &dbusMode) 495 { 496 if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 497 { 498 return "None"; 499 } 500 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") 501 { 502 return "Diags"; 503 } 504 else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") 505 { 506 return "BiosSetup"; 507 } 508 else 509 { 510 return ""; 511 } 512 } 513 514 /** 515 * @brief Traslates boot source from Redfish to DBUS property value. 516 * 517 * @param[in] rfSource The boot source in Redfish. 518 * 519 * @return Returns as a string, the boot source as expected by DBUS. 520 * If translation cannot be done, returns an empty string. 521 */ 522 static std::string rfToDbusBootSource(const std::string &rfSource) 523 { 524 if (rfSource == "None") 525 { 526 return "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 527 } 528 else if (rfSource == "Hdd") 529 { 530 return "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; 531 } 532 else if (rfSource == "Cd") 533 { 534 return "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; 535 } 536 else if (rfSource == "Pxe") 537 { 538 return "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; 539 } 540 else 541 { 542 return ""; 543 } 544 } 545 546 /** 547 * @brief Traslates boot mode from Redfish to DBUS property value. 548 * 549 * @param[in] rfMode The boot mode in Redfish. 550 * 551 * @return Returns as a string, the boot mode as expected by DBUS. 552 * If translation cannot be done, returns an empty string. 553 */ 554 static std::string rfToDbusBootMode(const std::string &rfMode) 555 { 556 if (rfMode == "None") 557 { 558 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 559 } 560 else if (rfMode == "Diags") 561 { 562 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; 563 } 564 else if (rfMode == "BiosSetup") 565 { 566 return "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; 567 } 568 else 569 { 570 return ""; 571 } 572 } 573 574 /** 575 * @brief Retrieves boot mode over DBUS and fills out the response 576 * 577 * @param[in] aResp Shared pointer for generating response message. 578 * @param[in] bootDbusObj The dbus object to query for boot properties. 579 * 580 * @return None. 581 */ 582 static void getBootMode(std::shared_ptr<AsyncResp> aResp, 583 std::string bootDbusObj) 584 { 585 crow::connections::systemBus->async_method_call( 586 [aResp](const boost::system::error_code ec, 587 const std::variant<std::string> &bootMode) { 588 if (ec) 589 { 590 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 591 messages::internalError(aResp->res); 592 return; 593 } 594 595 const std::string *bootModeStr = 596 std::get_if<std::string>(&bootMode); 597 598 if (!bootModeStr) 599 { 600 messages::internalError(aResp->res); 601 return; 602 } 603 604 BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr; 605 606 // TODO (Santosh): Do we need to support override mode? 607 aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy"; 608 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish." 609 "AllowableValues"] = { 610 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup"}; 611 612 if (*bootModeStr != 613 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 614 { 615 auto rfMode = dbusToRfBootMode(*bootModeStr); 616 if (!rfMode.empty()) 617 { 618 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 619 rfMode; 620 } 621 } 622 623 // If the BootSourceOverrideTarget is still "None" at the end, 624 // reset the BootSourceOverrideEnabled to indicate that 625 // overrides are disabled 626 if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] == 627 "None") 628 { 629 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 630 "Disabled"; 631 } 632 }, 633 "xyz.openbmc_project.Settings", bootDbusObj, 634 "org.freedesktop.DBus.Properties", "Get", 635 "xyz.openbmc_project.Control.Boot.Mode", "BootMode"); 636 } 637 638 /** 639 * @brief Retrieves boot source over DBUS 640 * 641 * @param[in] aResp Shared pointer for generating response message. 642 * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time. 643 * 644 * @return None. 645 */ 646 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled) 647 { 648 std::string bootDbusObj = 649 oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time" 650 : "/xyz/openbmc_project/control/host0/boot"; 651 652 BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled; 653 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 654 (oneTimeEnabled) ? "Once" : "Continuous"; 655 656 crow::connections::systemBus->async_method_call( 657 [aResp, bootDbusObj](const boost::system::error_code ec, 658 const std::variant<std::string> &bootSource) { 659 if (ec) 660 { 661 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 662 messages::internalError(aResp->res); 663 return; 664 } 665 666 const std::string *bootSourceStr = 667 std::get_if<std::string>(&bootSource); 668 669 if (!bootSourceStr) 670 { 671 messages::internalError(aResp->res); 672 return; 673 } 674 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr; 675 676 auto rfSource = dbusToRfBootSource(*bootSourceStr); 677 if (!rfSource.empty()) 678 { 679 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 680 rfSource; 681 } 682 }, 683 "xyz.openbmc_project.Settings", bootDbusObj, 684 "org.freedesktop.DBus.Properties", "Get", 685 "xyz.openbmc_project.Control.Boot.Source", "BootSource"); 686 getBootMode(std::move(aResp), std::move(bootDbusObj)); 687 } 688 689 /** 690 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 691 * get boot source and boot mode. 692 * 693 * @param[in] aResp Shared pointer for generating response message. 694 * 695 * @return None. 696 */ 697 static void getBootProperties(std::shared_ptr<AsyncResp> aResp) 698 { 699 BMCWEB_LOG_DEBUG << "Get boot information."; 700 701 crow::connections::systemBus->async_method_call( 702 [aResp{std::move(aResp)}]( 703 const boost::system::error_code ec, 704 const sdbusplus::message::variant<bool> &oneTime) { 705 if (ec) 706 { 707 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 708 messages::internalError(aResp->res); 709 return; 710 } 711 712 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 713 714 if (!oneTimePtr) 715 { 716 messages::internalError(aResp->res); 717 return; 718 } 719 getBootSource(aResp, *oneTimePtr); 720 }, 721 "xyz.openbmc_project.Settings", 722 "/xyz/openbmc_project/control/host0/boot/one_time", 723 "org.freedesktop.DBus.Properties", "Get", 724 "xyz.openbmc_project.Object.Enable", "Enabled"); 725 } 726 727 /** 728 * @brief Sets boot properties into DBUS object(s). 729 * 730 * @param[in] aResp Shared pointer for generating response message. 731 * @param[in] oneTimeEnabled Is "one-time" setting already enabled. 732 * @param[in] bootSource The boot source to set. 733 * @param[in] bootEnable The source override "enable" to set. 734 * 735 * @return None. 736 */ 737 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp, 738 bool oneTimeEnabled, 739 std::optional<std::string> bootSource, 740 std::optional<std::string> bootEnable) 741 { 742 if (bootEnable && (bootEnable != "Once") && (bootEnable != "Continuous") && 743 (bootEnable != "Disabled")) 744 { 745 BMCWEB_LOG_DEBUG << "Unsupported value for BootSourceOverrideEnabled: " 746 << *bootEnable; 747 messages::propertyValueNotInList(aResp->res, *bootEnable, 748 "BootSourceOverrideEnabled"); 749 return; 750 } 751 752 bool oneTimeSetting = oneTimeEnabled; 753 // Validate incoming parameters 754 if (bootEnable) 755 { 756 if (*bootEnable == "Once") 757 { 758 oneTimeSetting = true; 759 } 760 else if (*bootEnable == "Continuous") 761 { 762 oneTimeSetting = false; 763 } 764 else if (*bootEnable == "Disabled") 765 { 766 oneTimeSetting = false; 767 } 768 else 769 { 770 771 BMCWEB_LOG_DEBUG << "Unsupported value for " 772 "BootSourceOverrideEnabled: " 773 << *bootEnable; 774 messages::propertyValueNotInList(aResp->res, *bootEnable, 775 "BootSourceOverrideEnabled"); 776 return; 777 } 778 } 779 std::string bootSourceStr; 780 std::string bootModeStr; 781 if (bootSource) 782 { 783 bootSourceStr = rfToDbusBootSource(*bootSource); 784 bootModeStr = rfToDbusBootMode(*bootSource); 785 786 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 787 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 788 789 if (bootSourceStr.empty() && bootModeStr.empty()) 790 { 791 BMCWEB_LOG_DEBUG << "Invalid property value for " 792 "BootSourceOverrideTarget: " 793 << *bootSource; 794 messages::propertyValueNotInList(aResp->res, *bootSource, 795 "BootSourceTargetOverride"); 796 return; 797 } 798 } 799 const char *bootObj = 800 oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time" 801 : "/xyz/openbmc_project/control/host0/boot"; 802 // Figure out what properties to set 803 if (bootEnable && (*bootEnable == "Disabled")) 804 { 805 BMCWEB_LOG_DEBUG << "Boot source override will be disabled"; 806 // Request to only turn OFF/ON enabled, if turning enabled OFF, need 807 // to reset the source and mode too. If turning it ON, we only need 808 // to set the enabled property 809 bootSourceStr = 810 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 811 bootModeStr = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 812 } 813 else if (bootSource) 814 { 815 // Source target specified 816 BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; 817 // Figure out which DBUS interface and property to use 818 bootSourceStr = rfToDbusBootSource(*bootSource); 819 bootModeStr = rfToDbusBootMode(*bootSource); 820 821 BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; 822 BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; 823 824 if (bootSourceStr.empty() && bootModeStr.empty()) 825 { 826 BMCWEB_LOG_DEBUG << "Invalid property value for " 827 "BootSourceOverrideTarget: " 828 << *bootSource; 829 messages::propertyValueNotInList(aResp->res, *bootSource, 830 "BootSourceTargetOverride"); 831 return; 832 } 833 834 if (!bootSourceStr.empty()) 835 { 836 // If setting to anything other than default, also reset boot 837 // mode property 838 if (bootSourceStr != 839 "xyz.openbmc_project.Control.Boot.Source.Sources.Default") 840 { 841 bootModeStr = 842 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 843 } 844 } 845 else // if (!bootModeStr.empty()) 846 { 847 // If setting to anything other than default, also reset boot 848 // source property 849 if (bootModeStr != 850 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") 851 { 852 bootSourceStr = 853 "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; 854 } 855 } 856 } 857 if (!bootSourceStr.empty()) 858 { 859 crow::connections::systemBus->async_method_call( 860 [aResp](const boost::system::error_code ec) { 861 if (ec) 862 { 863 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 864 messages::internalError(aResp->res); 865 return; 866 } 867 BMCWEB_LOG_DEBUG << "Boot source update done."; 868 }, 869 "xyz.openbmc_project.Settings", bootObj, 870 "org.freedesktop.DBus.Properties", "Set", 871 "xyz.openbmc_project.Control.Boot.Source", "BootSource", 872 std::variant<std::string>(bootSourceStr)); 873 } 874 if (!bootModeStr.empty()) 875 { 876 crow::connections::systemBus->async_method_call( 877 [aResp](const boost::system::error_code ec) { 878 if (ec) 879 { 880 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 881 messages::internalError(aResp->res); 882 return; 883 } 884 BMCWEB_LOG_DEBUG << "Boot mode update done."; 885 }, 886 "xyz.openbmc_project.Settings", bootObj, 887 "org.freedesktop.DBus.Properties", "Set", 888 "xyz.openbmc_project.Control.Boot.Mode", "BootMode", 889 std::variant<std::string>(bootModeStr)); 890 } 891 crow::connections::systemBus->async_method_call( 892 [aResp{std::move(aResp)}](const boost::system::error_code ec) { 893 if (ec) 894 { 895 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 896 messages::internalError(aResp->res); 897 return; 898 } 899 BMCWEB_LOG_DEBUG << "Boot enable update done."; 900 }, 901 "xyz.openbmc_project.Settings", 902 "/xyz/openbmc_project/control/host0/boot/one_time", 903 "org.freedesktop.DBus.Properties", "Set", 904 "xyz.openbmc_project.Object.Enable", "Enabled", 905 std::variant<bool>(oneTimeSetting)); 906 } 907 908 /** 909 * @brief Retrieves "One time" enabled setting over DBUS and calls function to 910 * set boot source/boot mode properties. 911 * 912 * @param[in] aResp Shared pointer for generating response message. 913 * @param[in] bootSource The boot source from incoming RF request. 914 * @param[in] bootEnable The boot override enable from incoming RF request. 915 * 916 * @return None. 917 */ 918 static void setBootProperties(std::shared_ptr<AsyncResp> aResp, 919 std::optional<std::string> bootSource, 920 std::optional<std::string> bootEnable) 921 { 922 BMCWEB_LOG_DEBUG << "Set boot information."; 923 924 crow::connections::systemBus->async_method_call( 925 [aResp{std::move(aResp)}, bootSource{std::move(bootSource)}, 926 bootEnable{std::move(bootEnable)}]( 927 const boost::system::error_code ec, 928 const sdbusplus::message::variant<bool> &oneTime) { 929 if (ec) 930 { 931 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 932 messages::internalError(aResp->res); 933 return; 934 } 935 936 const bool *oneTimePtr = std::get_if<bool>(&oneTime); 937 938 if (!oneTimePtr) 939 { 940 messages::internalError(aResp->res); 941 return; 942 } 943 944 BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr; 945 946 setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource), 947 std::move(bootEnable)); 948 }, 949 "xyz.openbmc_project.Settings", 950 "/xyz/openbmc_project/control/host0/boot/one_time", 951 "org.freedesktop.DBus.Properties", "Get", 952 "xyz.openbmc_project.Object.Enable", "Enabled"); 953 } 954 955 /** 956 * SystemsCollection derived class for delivering ComputerSystems Collection 957 * Schema 958 */ 959 class SystemsCollection : public Node 960 { 961 public: 962 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 963 { 964 entityPrivileges = { 965 {boost::beast::http::verb::get, {{"Login"}}}, 966 {boost::beast::http::verb::head, {{"Login"}}}, 967 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 968 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 969 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 970 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 971 } 972 973 private: 974 void doGet(crow::Response &res, const crow::Request &req, 975 const std::vector<std::string> ¶ms) override 976 { 977 res.jsonValue["@odata.type"] = 978 "#ComputerSystemCollection.ComputerSystemCollection"; 979 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 980 res.jsonValue["@odata.context"] = 981 "/redfish/v1/" 982 "$metadata#ComputerSystemCollection.ComputerSystemCollection"; 983 res.jsonValue["Name"] = "Computer System Collection"; 984 res.jsonValue["Members"] = { 985 {{"@odata.id", "/redfish/v1/Systems/system"}}}; 986 res.jsonValue["Members@odata.count"] = 1; 987 res.end(); 988 } 989 }; 990 991 /** 992 * SystemActionsReset class supports handle POST method for Reset action. 993 * The class retrieves and sends data directly to D-Bus. 994 */ 995 class SystemActionsReset : public Node 996 { 997 public: 998 SystemActionsReset(CrowApp &app) : 999 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 1000 { 1001 entityPrivileges = { 1002 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1003 } 1004 1005 private: 1006 /** 1007 * Function handles POST method request. 1008 * Analyzes POST body message before sends Reset request data to D-Bus. 1009 */ 1010 void doPost(crow::Response &res, const crow::Request &req, 1011 const std::vector<std::string> ¶ms) override 1012 { 1013 auto asyncResp = std::make_shared<AsyncResp>(res); 1014 1015 std::string resetType; 1016 if (!json_util::readJson(req, res, "ResetType", resetType)) 1017 { 1018 return; 1019 } 1020 1021 if (resetType == "ForceOff") 1022 { 1023 // Force off acts on the chassis 1024 crow::connections::systemBus->async_method_call( 1025 [asyncResp](const boost::system::error_code ec) { 1026 if (ec) 1027 { 1028 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1029 messages::internalError(asyncResp->res); 1030 return; 1031 } 1032 // TODO Consider support polling mechanism to verify 1033 // status of host and chassis after execute the 1034 // requested action. 1035 messages::success(asyncResp->res); 1036 }, 1037 "xyz.openbmc_project.State.Chassis", 1038 "/xyz/openbmc_project/state/chassis0", 1039 "org.freedesktop.DBus.Properties", "Set", 1040 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 1041 std::variant<std::string>{ 1042 "xyz.openbmc_project.State.Chassis.Transition.Off"}); 1043 return; 1044 } 1045 // all other actions operate on the host 1046 std::string command; 1047 // Execute Reset Action regarding to each reset type. 1048 if (resetType == "On") 1049 { 1050 command = "xyz.openbmc_project.State.Host.Transition.On"; 1051 } 1052 else if (resetType == "GracefulShutdown") 1053 { 1054 command = "xyz.openbmc_project.State.Host.Transition.Off"; 1055 } 1056 else if (resetType == "GracefulRestart") 1057 { 1058 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 1059 } 1060 else 1061 { 1062 messages::actionParameterUnknown(res, "Reset", resetType); 1063 return; 1064 } 1065 1066 crow::connections::systemBus->async_method_call( 1067 [asyncResp](const boost::system::error_code ec) { 1068 if (ec) 1069 { 1070 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 1071 messages::internalError(asyncResp->res); 1072 return; 1073 } 1074 // TODO Consider support polling mechanism to verify 1075 // status of host and chassis after execute the 1076 // requested action. 1077 messages::success(asyncResp->res); 1078 }, 1079 "xyz.openbmc_project.State.Host", 1080 "/xyz/openbmc_project/state/host0", 1081 "org.freedesktop.DBus.Properties", "Set", 1082 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 1083 std::variant<std::string>{command}); 1084 } 1085 }; 1086 1087 /** 1088 * Systems derived class for delivering Computer Systems Schema. 1089 */ 1090 class Systems : public Node 1091 { 1092 public: 1093 /* 1094 * Default Constructor 1095 */ 1096 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 1097 { 1098 entityPrivileges = { 1099 {boost::beast::http::verb::get, {{"Login"}}}, 1100 {boost::beast::http::verb::head, {{"Login"}}}, 1101 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 1102 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 1103 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 1104 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 1105 } 1106 1107 private: 1108 /** 1109 * Functions triggers appropriate requests on DBus 1110 */ 1111 void doGet(crow::Response &res, const crow::Request &req, 1112 const std::vector<std::string> ¶ms) override 1113 { 1114 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem"; 1115 res.jsonValue["@odata.context"] = 1116 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 1117 res.jsonValue["Name"] = "Computer System"; 1118 res.jsonValue["Id"] = "system"; 1119 res.jsonValue["SystemType"] = "Physical"; 1120 res.jsonValue["Description"] = "Computer System"; 1121 res.jsonValue["ProcessorSummary"]["Count"] = 0; 1122 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 1123 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 1124 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 1125 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 1126 1127 res.jsonValue["Processors"] = { 1128 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 1129 res.jsonValue["Memory"] = { 1130 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 1131 1132 // TODO Need to support ForceRestart. 1133 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 1134 {"target", 1135 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 1136 {"ResetType@Redfish.AllowableValues", 1137 {"On", "ForceOff", "GracefulRestart", "GracefulShutdown"}}}; 1138 1139 res.jsonValue["LogServices"] = { 1140 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 1141 1142 auto asyncResp = std::make_shared<AsyncResp>(res); 1143 1144 getLedGroupIdentify( 1145 asyncResp, 1146 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) { 1147 if (asserted) 1148 { 1149 // If led group is asserted, then another call is needed to 1150 // get led status 1151 getLedIdentify( 1152 aResp, [](const std::string &ledStatus, 1153 const std::shared_ptr<AsyncResp> &aResp) { 1154 if (!ledStatus.empty()) 1155 { 1156 aResp->res.jsonValue["IndicatorLED"] = 1157 ledStatus; 1158 } 1159 }); 1160 } 1161 else 1162 { 1163 aResp->res.jsonValue["IndicatorLED"] = "Off"; 1164 } 1165 }); 1166 getComputerSystem(asyncResp); 1167 getHostState(asyncResp); 1168 getBootProperties(asyncResp); 1169 } 1170 1171 void doPatch(crow::Response &res, const crow::Request &req, 1172 const std::vector<std::string> ¶ms) override 1173 { 1174 std::optional<std::string> indicatorLed; 1175 std::optional<nlohmann::json> bootProps; 1176 if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot", 1177 bootProps)) 1178 { 1179 return; 1180 } 1181 1182 auto asyncResp = std::make_shared<AsyncResp>(res); 1183 messages::success(asyncResp->res); 1184 1185 if (bootProps) 1186 { 1187 std::optional<std::string> bootSource; 1188 std::optional<std::string> bootEnable; 1189 1190 if (!json_util::readJson(*bootProps, asyncResp->res, 1191 "BootSourceOverrideTarget", bootSource, 1192 "BootSourceOverrideEnabled", bootEnable)) 1193 { 1194 return; 1195 } 1196 setBootProperties(asyncResp, std::move(bootSource), 1197 std::move(bootEnable)); 1198 } 1199 if (indicatorLed) 1200 { 1201 std::string dbusLedState; 1202 if (*indicatorLed == "On") 1203 { 1204 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Lit"; 1205 } 1206 else if (*indicatorLed == "Blinking") 1207 { 1208 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink"; 1209 } 1210 else if (*indicatorLed == "Off") 1211 { 1212 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 1213 } 1214 else 1215 { 1216 messages::propertyValueNotInList(res, *indicatorLed, 1217 "IndicatorLED"); 1218 return; 1219 } 1220 1221 getHostState(asyncResp); 1222 getComputerSystem(asyncResp); 1223 1224 // Update led group 1225 BMCWEB_LOG_DEBUG << "Update led group."; 1226 crow::connections::systemBus->async_method_call( 1227 [asyncResp](const boost::system::error_code ec) { 1228 if (ec) 1229 { 1230 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1231 messages::internalError(asyncResp->res); 1232 return; 1233 } 1234 BMCWEB_LOG_DEBUG << "Led group update done."; 1235 }, 1236 "xyz.openbmc_project.LED.GroupManager", 1237 "/xyz/openbmc_project/led/groups/enclosure_identify", 1238 "org.freedesktop.DBus.Properties", "Set", 1239 "xyz.openbmc_project.Led.Group", "Asserted", 1240 std::variant<bool>( 1241 (dbusLedState == 1242 "xyz.openbmc_project.Led.Physical.Action.Off" 1243 ? false 1244 : true))); 1245 // Update identify led status 1246 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 1247 crow::connections::systemBus->async_method_call( 1248 [asyncResp{std::move(asyncResp)}, 1249 indicatorLed{std::move(*indicatorLed)}]( 1250 const boost::system::error_code ec) { 1251 if (ec) 1252 { 1253 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 1254 messages::internalError(asyncResp->res); 1255 return; 1256 } 1257 BMCWEB_LOG_DEBUG << "Led state update done."; 1258 }, 1259 "xyz.openbmc_project.LED.Controller.identify", 1260 "/xyz/openbmc_project/led/physical/identify", 1261 "org.freedesktop.DBus.Properties", "Set", 1262 "xyz.openbmc_project.Led.Physical", "State", 1263 std::variant<std::string>(dbusLedState)); 1264 } 1265 } 1266 }; 1267 } // namespace redfish 1268