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