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