1 /* 2 // Copyright (c) 2018 Intel Corporation 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 */ 16 #pragma once 17 18 #include <boost/container/flat_map.hpp> 19 #include <node.hpp> 20 #include <utils/json_utils.hpp> 21 #include <variant> 22 23 namespace redfish 24 { 25 26 /** 27 * @brief Retrieves computer system properties over dbus 28 * 29 * @param[in] aResp Shared pointer for completing asynchronous calls 30 * @param[in] name Computer system name from request 31 * 32 * @return None. 33 */ 34 void getComputerSystem(std::shared_ptr<AsyncResp> aResp) 35 { 36 BMCWEB_LOG_DEBUG << "Get available system components."; 37 crow::connections::systemBus->async_method_call( 38 [aResp{std::move(aResp)}]( 39 const boost::system::error_code ec, 40 const std::vector<std::pair< 41 std::string, 42 std::vector<std::pair<std::string, std::vector<std::string>>>>> 43 &subtree) { 44 if (ec) 45 { 46 BMCWEB_LOG_DEBUG << "DBUS response error"; 47 messages::internalError(aResp->res); 48 return; 49 } 50 // Iterate over all retrieved ObjectPaths. 51 for (const std::pair<std::string, 52 std::vector<std::pair< 53 std::string, std::vector<std::string>>>> 54 &object : subtree) 55 { 56 const std::string &path = object.first; 57 BMCWEB_LOG_DEBUG << "Got path: " << path; 58 const std::vector< 59 std::pair<std::string, std::vector<std::string>>> 60 &connectionNames = object.second; 61 if (connectionNames.size() < 1) 62 { 63 continue; 64 } 65 66 // This is not system, so check if it's cpu, dimm, UUID or 67 // BiosVer 68 for (const auto &connection : connectionNames) 69 { 70 for (const auto &interfaceName : connection.second) 71 { 72 if (interfaceName == 73 "xyz.openbmc_project.Inventory.Item.Dimm") 74 { 75 BMCWEB_LOG_DEBUG 76 << "Found Dimm, now get its properties."; 77 crow::connections::systemBus->async_method_call( 78 [aResp](const boost::system::error_code ec, 79 const std::vector< 80 std::pair<std::string, VariantType>> 81 &properties) { 82 if (ec) 83 { 84 BMCWEB_LOG_ERROR 85 << "DBUS response error " << ec; 86 messages::internalError(aResp->res); 87 return; 88 } 89 BMCWEB_LOG_DEBUG << "Got " 90 << properties.size() 91 << "Dimm properties."; 92 for (const std::pair<std::string, 93 VariantType> 94 &property : properties) 95 { 96 if (property.first == "MemorySizeInKb") 97 { 98 const uint64_t *value = 99 sdbusplus::message::variant_ns:: 100 get_if<uint64_t>( 101 &property.second); 102 if (value != nullptr) 103 { 104 aResp->res.jsonValue 105 ["TotalSystemMemoryGi" 106 "B"] += 107 *value / (1024 * 1024); 108 aResp->res 109 .jsonValue["MemorySummary"] 110 ["Status"] 111 ["State"] = 112 "Enabled"; 113 } 114 } 115 } 116 }, 117 connection.first, path, 118 "org.freedesktop.DBus.Properties", "GetAll", 119 "xyz.openbmc_project.Inventory.Item.Dimm"); 120 } 121 else if (interfaceName == 122 "xyz.openbmc_project.Inventory.Item.Cpu") 123 { 124 BMCWEB_LOG_DEBUG 125 << "Found Cpu, now get its properties."; 126 crow::connections::systemBus->async_method_call( 127 [aResp](const boost::system::error_code ec, 128 const std::vector< 129 std::pair<std::string, VariantType>> 130 &properties) { 131 if (ec) 132 { 133 BMCWEB_LOG_ERROR 134 << "DBUS response error " << ec; 135 messages::internalError(aResp->res); 136 return; 137 } 138 BMCWEB_LOG_DEBUG << "Got " 139 << properties.size() 140 << "Cpu properties."; 141 for (const auto &property : properties) 142 { 143 if (property.first == "ProcessorFamily") 144 { 145 const std::string *value = 146 sdbusplus::message::variant_ns:: 147 get_if<std::string>( 148 &property.second); 149 if (value != nullptr) 150 { 151 nlohmann::json &procSummary = 152 aResp->res.jsonValue 153 ["ProcessorSumm" 154 "ary"]; 155 nlohmann::json &procCount = 156 procSummary["Count"]; 157 158 procCount = 159 procCount.get<int>() + 1; 160 procSummary["Status"]["State"] = 161 "Enabled"; 162 procSummary["Model"] = *value; 163 } 164 } 165 } 166 }, 167 connection.first, path, 168 "org.freedesktop.DBus.Properties", "GetAll", 169 "xyz.openbmc_project.Inventory.Item.Cpu"); 170 } 171 else if (interfaceName == 172 "xyz.openbmc_project.Common.UUID") 173 { 174 BMCWEB_LOG_DEBUG 175 << "Found UUID, now get its properties."; 176 crow::connections::systemBus->async_method_call( 177 [aResp](const boost::system::error_code ec, 178 const std::vector< 179 std::pair<std::string, VariantType>> 180 &properties) { 181 if (ec) 182 { 183 BMCWEB_LOG_DEBUG 184 << "DBUS response error " << ec; 185 messages::internalError(aResp->res); 186 return; 187 } 188 BMCWEB_LOG_DEBUG << "Got " 189 << properties.size() 190 << "UUID properties."; 191 for (const std::pair<std::string, 192 VariantType> 193 &property : properties) 194 { 195 if (property.first == "BIOSVer") 196 { 197 const std::string *value = 198 sdbusplus::message::variant_ns:: 199 get_if<std::string>( 200 &property.second); 201 if (value != nullptr) 202 { 203 aResp->res 204 .jsonValue["BiosVersion"] = 205 *value; 206 } 207 } 208 if (property.first == "UUID") 209 { 210 const std::string *value = 211 sdbusplus::message::variant_ns:: 212 get_if<std::string>( 213 &property.second); 214 215 if (value != nullptr) 216 { 217 std::string valueStr = *value; 218 if (valueStr.size() == 32) 219 { 220 valueStr.insert(8, 1, '-'); 221 valueStr.insert(13, 1, '-'); 222 valueStr.insert(18, 1, '-'); 223 valueStr.insert(23, 1, '-'); 224 } 225 BMCWEB_LOG_DEBUG << "UUID = " 226 << valueStr; 227 aResp->res.jsonValue["UUID"] = 228 valueStr; 229 } 230 } 231 } 232 }, 233 connection.first, path, 234 "org.freedesktop.DBus.Properties", "GetAll", 235 "xyz.openbmc_project.Common.UUID"); 236 } 237 else if (interfaceName == 238 "xyz.openbmc_project.Inventory.Item.System") 239 { 240 crow::connections::systemBus->async_method_call( 241 [aResp](const boost::system::error_code ec, 242 const std::vector< 243 std::pair<std::string, VariantType>> 244 &propertiesList) { 245 if (ec) 246 { 247 BMCWEB_LOG_ERROR 248 << "DBUS response error: " << ec; 249 messages::internalError(aResp->res); 250 return; 251 } 252 BMCWEB_LOG_DEBUG << "Got " 253 << propertiesList.size() 254 << "properties for system"; 255 for (const std::pair<std::string, 256 VariantType> 257 &property : propertiesList) 258 { 259 const std::string *value = 260 sdbusplus::message::variant_ns:: 261 get_if<std::string>( 262 &property.second); 263 if (value != nullptr) 264 { 265 aResp->res 266 .jsonValue[property.first] = 267 *value; 268 } 269 } 270 aResp->res.jsonValue["Name"] = "system"; 271 aResp->res.jsonValue["Id"] = 272 aResp->res.jsonValue["SerialNumber"]; 273 }, 274 connection.first, path, 275 "org.freedesktop.DBus.Properties", "GetAll", 276 "xyz.openbmc_project.Inventory.Decorator." 277 "Asset"); 278 } 279 } 280 } 281 } 282 }, 283 "xyz.openbmc_project.ObjectMapper", 284 "/xyz/openbmc_project/object_mapper", 285 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 286 "/xyz/openbmc_project/inventory", int32_t(0), 287 std::array<const char *, 5>{ 288 "xyz.openbmc_project.Inventory.Decorator.Asset", 289 "xyz.openbmc_project.Inventory.Item.Cpu", 290 "xyz.openbmc_project.Inventory.Item.Dimm", 291 "xyz.openbmc_project.Inventory.Item.System", 292 "xyz.openbmc_project.Common.UUID", 293 }); 294 } 295 296 /** 297 * @brief Retrieves identify led group properties over dbus 298 * 299 * @param[in] aResp Shared pointer for completing asynchronous calls. 300 * @param[in] callback Callback for process retrieved data. 301 * 302 * @return None. 303 */ 304 template <typename CallbackFunc> 305 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp, 306 CallbackFunc &&callback) 307 { 308 BMCWEB_LOG_DEBUG << "Get led groups"; 309 crow::connections::systemBus->async_method_call( 310 [aResp{std::move(aResp)}, 311 callback{std::move(callback)}](const boost::system::error_code &ec, 312 const ManagedObjectsType &resp) { 313 if (ec) 314 { 315 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 316 messages::internalError(aResp->res); 317 return; 318 } 319 BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects."; 320 for (const auto &objPath : resp) 321 { 322 const std::string &path = objPath.first; 323 if (path.rfind("enclosure_identify") != std::string::npos) 324 { 325 for (const auto &interface : objPath.second) 326 { 327 if (interface.first == "xyz.openbmc_project.Led.Group") 328 { 329 for (const auto &property : interface.second) 330 { 331 if (property.first == "Asserted") 332 { 333 const bool *asserted = 334 std::get_if<bool>(&property.second); 335 if (nullptr != asserted) 336 { 337 callback(*asserted, aResp); 338 } 339 else 340 { 341 callback(false, aResp); 342 } 343 } 344 } 345 } 346 } 347 } 348 } 349 }, 350 "xyz.openbmc_project.LED.GroupManager", 351 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager", 352 "GetManagedObjects"); 353 } 354 355 template <typename CallbackFunc> 356 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback) 357 { 358 BMCWEB_LOG_DEBUG << "Get identify led properties"; 359 crow::connections::systemBus->async_method_call( 360 [aResp, 361 callback{std::move(callback)}](const boost::system::error_code ec, 362 const PropertiesType &properties) { 363 if (ec) 364 { 365 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 366 messages::internalError(aResp->res); 367 return; 368 } 369 BMCWEB_LOG_DEBUG << "Got " << properties.size() 370 << "led properties."; 371 std::string output; 372 for (const auto &property : properties) 373 { 374 if (property.first == "State") 375 { 376 const std::string *s = 377 std::get_if<std::string>(&property.second); 378 if (nullptr != s) 379 { 380 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s; 381 const auto pos = s->rfind('.'); 382 if (pos != std::string::npos) 383 { 384 auto led = s->substr(pos + 1); 385 for (const std::pair<const char *, const char *> 386 &p : 387 std::array< 388 std::pair<const char *, const char *>, 3>{ 389 {{"On", "Lit"}, 390 {"Blink", "Blinking"}, 391 {"Off", "Off"}}}) 392 { 393 if (led == p.first) 394 { 395 output = p.second; 396 } 397 } 398 } 399 } 400 } 401 } 402 callback(output, aResp); 403 }, 404 "xyz.openbmc_project.LED.Controller.identify", 405 "/xyz/openbmc_project/led/physical/identify", 406 "org.freedesktop.DBus.Properties", "GetAll", 407 "xyz.openbmc_project.Led.Physical"); 408 } 409 410 /** 411 * @brief Retrieves host state properties over dbus 412 * 413 * @param[in] aResp Shared pointer for completing asynchronous calls. 414 * 415 * @return None. 416 */ 417 void getHostState(std::shared_ptr<AsyncResp> aResp) 418 { 419 BMCWEB_LOG_DEBUG << "Get host information."; 420 crow::connections::systemBus->async_method_call( 421 [aResp{std::move(aResp)}](const boost::system::error_code ec, 422 const std::variant<std::string> &hostState) { 423 if (ec) 424 { 425 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 426 messages::internalError(aResp->res); 427 return; 428 } 429 430 const std::string *s = std::get_if<std::string>(&hostState); 431 BMCWEB_LOG_DEBUG << "Host state: " << *s; 432 if (s != nullptr) 433 { 434 // Verify Host State 435 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 436 { 437 aResp->res.jsonValue["PowerState"] = "On"; 438 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 439 } 440 else 441 { 442 aResp->res.jsonValue["PowerState"] = "Off"; 443 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 444 } 445 } 446 }, 447 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 448 "org.freedesktop.DBus.Properties", "Get", 449 "xyz.openbmc_project.State.Host", "CurrentHostState"); 450 } 451 452 /** 453 * SystemsCollection derived class for delivering ComputerSystems Collection 454 * Schema 455 */ 456 class SystemsCollection : public Node 457 { 458 public: 459 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 460 { 461 entityPrivileges = { 462 {boost::beast::http::verb::get, {{"Login"}}}, 463 {boost::beast::http::verb::head, {{"Login"}}}, 464 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 465 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 466 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 467 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 468 } 469 470 private: 471 void doGet(crow::Response &res, const crow::Request &req, 472 const std::vector<std::string> ¶ms) override 473 { 474 res.jsonValue["@odata.type"] = 475 "#ComputerSystemCollection.ComputerSystemCollection"; 476 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 477 res.jsonValue["@odata.context"] = 478 "/redfish/v1/" 479 "$metadata#ComputerSystemCollection.ComputerSystemCollection"; 480 res.jsonValue["Name"] = "Computer System Collection"; 481 res.jsonValue["Members"] = { 482 {{"@odata.id", "/redfish/v1/Systems/system"}}}; 483 res.jsonValue["Members@odata.count"] = 1; 484 res.end(); 485 } 486 }; 487 488 /** 489 * SystemActionsReset class supports handle POST method for Reset action. 490 * The class retrieves and sends data directly to D-Bus. 491 */ 492 class SystemActionsReset : public Node 493 { 494 public: 495 SystemActionsReset(CrowApp &app) : 496 Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/") 497 { 498 entityPrivileges = { 499 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 500 } 501 502 private: 503 /** 504 * Function handles POST method request. 505 * Analyzes POST body message before sends Reset request data to D-Bus. 506 */ 507 void doPost(crow::Response &res, const crow::Request &req, 508 const std::vector<std::string> ¶ms) override 509 { 510 auto asyncResp = std::make_shared<AsyncResp>(res); 511 512 std::string resetType; 513 if (!json_util::readJson(req, res, "ResetType", resetType)) 514 { 515 return; 516 } 517 518 if (resetType == "ForceOff") 519 { 520 // Force off acts on the chassis 521 crow::connections::systemBus->async_method_call( 522 [asyncResp](const boost::system::error_code ec) { 523 if (ec) 524 { 525 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 526 messages::internalError(asyncResp->res); 527 return; 528 } 529 // TODO Consider support polling mechanism to verify 530 // status of host and chassis after execute the 531 // requested action. 532 messages::success(asyncResp->res); 533 }, 534 "xyz.openbmc_project.State.Chassis", 535 "/xyz/openbmc_project/state/chassis0", 536 "org.freedesktop.DBus.Properties", "Set", 537 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition", 538 std::variant<std::string>{ 539 "xyz.openbmc_project.State.Chassis.Transition.Off"}); 540 return; 541 } 542 // all other actions operate on the host 543 std::string command; 544 // Execute Reset Action regarding to each reset type. 545 if (resetType == "On") 546 { 547 command = "xyz.openbmc_project.State.Host.Transition.On"; 548 } 549 else if (resetType == "GracefulShutdown") 550 { 551 command = "xyz.openbmc_project.State.Host.Transition.Off"; 552 } 553 else if (resetType == "GracefulRestart") 554 { 555 command = "xyz.openbmc_project.State.Host.Transition.Reboot"; 556 } 557 else 558 { 559 messages::actionParameterUnknown(res, "Reset", resetType); 560 return; 561 } 562 563 crow::connections::systemBus->async_method_call( 564 [asyncResp](const boost::system::error_code ec) { 565 if (ec) 566 { 567 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; 568 messages::internalError(asyncResp->res); 569 return; 570 } 571 // TODO Consider support polling mechanism to verify 572 // status of host and chassis after execute the 573 // requested action. 574 messages::success(asyncResp->res); 575 }, 576 "xyz.openbmc_project.State.Host", 577 "/xyz/openbmc_project/state/host0", 578 "org.freedesktop.DBus.Properties", "Set", 579 "xyz.openbmc_project.State.Host", "RequestedHostTransition", 580 std::variant<std::string>{command}); 581 } 582 }; 583 584 /** 585 * Systems derived class for delivering Computer Systems Schema. 586 */ 587 class Systems : public Node 588 { 589 public: 590 /* 591 * Default Constructor 592 */ 593 Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/") 594 { 595 entityPrivileges = { 596 {boost::beast::http::verb::get, {{"Login"}}}, 597 {boost::beast::http::verb::head, {{"Login"}}}, 598 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 599 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 600 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 601 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 602 } 603 604 private: 605 /** 606 * Functions triggers appropriate requests on DBus 607 */ 608 void doGet(crow::Response &res, const crow::Request &req, 609 const std::vector<std::string> ¶ms) override 610 { 611 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_5_1.ComputerSystem"; 612 res.jsonValue["@odata.context"] = 613 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 614 res.jsonValue["Name"] = "Computer System"; 615 res.jsonValue["Id"] = "system"; 616 res.jsonValue["SystemType"] = "Physical"; 617 res.jsonValue["Description"] = "Computer System"; 618 res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 619 "Disabled"; // TODO(Dawid), get real boot data 620 res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 621 "None"; // TODO(Dawid), get real boot data 622 res.jsonValue["Boot"]["BootSourceOverrideMode"] = 623 "Legacy"; // TODO(Dawid), get real boot data 624 res.jsonValue["Boot"] 625 ["BootSourceOverrideTarget@Redfish.AllowableValues"] = { 626 "None", "Pxe", "Hdd", "Cd", 627 "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot 628 // data 629 res.jsonValue["ProcessorSummary"]["Count"] = 0; 630 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 631 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 632 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 633 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system"; 634 635 res.jsonValue["Processors"] = { 636 {"@odata.id", "/redfish/v1/Systems/system/Processors"}}; 637 res.jsonValue["Memory"] = { 638 {"@odata.id", "/redfish/v1/Systems/system/Memory"}}; 639 640 // TODO Need to support ForceRestart. 641 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 642 {"target", 643 "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"}, 644 {"ResetType@Redfish.AllowableValues", 645 {"On", "ForceOff", "GracefulRestart", "GracefulShutdown"}}}; 646 647 res.jsonValue["LogServices"] = { 648 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}}; 649 650 auto asyncResp = std::make_shared<AsyncResp>(res); 651 652 getLedGroupIdentify( 653 asyncResp, 654 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) { 655 if (asserted) 656 { 657 // If led group is asserted, then another call is needed to 658 // get led status 659 getLedIdentify( 660 aResp, [](const std::string &ledStatus, 661 const std::shared_ptr<AsyncResp> &aResp) { 662 if (!ledStatus.empty()) 663 { 664 aResp->res.jsonValue["IndicatorLED"] = 665 ledStatus; 666 } 667 }); 668 } 669 else 670 { 671 aResp->res.jsonValue["IndicatorLED"] = "Off"; 672 } 673 }); 674 getComputerSystem(asyncResp); 675 getHostState(asyncResp); 676 } 677 678 void doPatch(crow::Response &res, const crow::Request &req, 679 const std::vector<std::string> ¶ms) override 680 { 681 std::string indicatorLedTemp; 682 std::optional<std::string> indicatorLed = indicatorLedTemp; 683 if (!json_util::readJson(req, res, "IndicatorLed", indicatorLed)) 684 { 685 return; 686 } 687 auto asyncResp = std::make_shared<AsyncResp>(res); 688 messages::success(asyncResp->res); 689 if (indicatorLed) 690 { 691 std::string dbusLedState; 692 if (*indicatorLed == "On") 693 { 694 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Lit"; 695 } 696 else if (*indicatorLed == "Blink") 697 { 698 dbusLedState = 699 "xyz.openbmc_project.Led.Physical.Action.Blinking"; 700 } 701 else if (*indicatorLed == "Off") 702 { 703 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 704 } 705 else 706 { 707 messages::propertyValueNotInList(res, *indicatorLed, 708 "IndicatorLED"); 709 return; 710 } 711 712 getHostState(asyncResp); 713 getComputerSystem(asyncResp); 714 715 // Update led group 716 BMCWEB_LOG_DEBUG << "Update led group."; 717 crow::connections::systemBus->async_method_call( 718 [asyncResp{std::move(asyncResp)}]( 719 const boost::system::error_code ec) { 720 if (ec) 721 { 722 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 723 messages::internalError(asyncResp->res); 724 return; 725 } 726 BMCWEB_LOG_DEBUG << "Led group update done."; 727 }, 728 "xyz.openbmc_project.LED.GroupManager", 729 "/xyz/openbmc_project/led/groups/enclosure_identify", 730 "org.freedesktop.DBus.Properties", "Set", 731 "xyz.openbmc_project.Led.Group", "Asserted", 732 std::variant<bool>( 733 (dbusLedState == 734 "xyz.openbmc_project.Led.Physical.Action.Off" 735 ? false 736 : true))); 737 // Update identify led status 738 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 739 crow::connections::systemBus->async_method_call( 740 [asyncResp{std::move(asyncResp)}, 741 indicatorLed{std::move(*indicatorLed)}]( 742 const boost::system::error_code ec) { 743 if (ec) 744 { 745 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 746 messages::internalError(asyncResp->res); 747 return; 748 } 749 BMCWEB_LOG_DEBUG << "Led state update done."; 750 }, 751 "xyz.openbmc_project.LED.Controller.identify", 752 "/xyz/openbmc_project/led/physical/identify", 753 "org.freedesktop.DBus.Properties", "Set", 754 "xyz.openbmc_project.Led.Physical", "State", 755 std::variant<std::string>(dbusLedState)); 756 } 757 } 758 }; 759 } // namespace redfish 760