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