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 <error_messages.hpp> 19 #include <utils/json_utils.hpp> 20 #include "node.hpp" 21 #include "boost/container/flat_map.hpp" 22 23 namespace redfish { 24 25 /** 26 * SystemAsyncResp 27 * Gathers data needed for response processing after async calls are done 28 */ 29 class SystemAsyncResp { 30 public: 31 SystemAsyncResp(crow::Response &response) : res(response) {} 32 33 ~SystemAsyncResp() { 34 if (res.result() != (boost::beast::http::status::ok)) { 35 // Reset the json object to clear out any data that made it in before the 36 // error happened 37 // todo(ed) handle error condition with proper code 38 res.jsonValue = messages::internalError(); 39 } 40 res.end(); 41 } 42 43 void setErrorStatus() { 44 res.result(boost::beast::http::status::internal_server_error); 45 } 46 47 crow::Response &res; 48 }; 49 50 /** 51 * OnDemandSystemsProvider 52 * Board provider class that retrieves data directly from dbus, before seting 53 * it into JSON output. This does not cache any data. 54 * 55 * Class can be a good example on how to scale different data providing 56 * solutions to produce single schema output. 57 * 58 * TODO(Pawel) 59 * This perhaps shall be different file, which has to be chosen on compile time 60 * depending on OEM needs 61 */ 62 class OnDemandSystemsProvider { 63 public: 64 template <typename CallbackFunc> 65 void getBaseboardList(CallbackFunc &&callback) { 66 BMCWEB_LOG_DEBUG << "Get list of available boards."; 67 crow::connections::systemBus->async_method_call( 68 [callback{std::move(callback)}](const boost::system::error_code ec, 69 const std::vector<std::string> &resp) { 70 // Callback requires vector<string> to retrieve all available board 71 // list. 72 std::vector<std::string> boardList; 73 if (ec) { 74 // Something wrong on DBus, the error_code is not important at this 75 // moment, just return success=false, and empty output. Since size 76 // of vector may vary depending on information from Entity Manager, 77 // and empty output could not be treated same way as error. 78 callback(false, boardList); 79 return; 80 } 81 BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards."; 82 // Iterate over all retrieved ObjectPaths. 83 for (const std::string &objpath : resp) { 84 std::size_t lastPos = objpath.rfind("/"); 85 if (lastPos != std::string::npos) { 86 boardList.emplace_back(objpath.substr(lastPos + 1)); 87 } 88 } 89 // Finally make a callback with useful data 90 callback(true, boardList); 91 }, 92 "xyz.openbmc_project.ObjectMapper", 93 "/xyz/openbmc_project/object_mapper", 94 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 95 "/xyz/openbmc_project/inventory", int32_t(0), 96 std::array<const char *, 1>{ 97 "xyz.openbmc_project.Inventory.Item.Board"}); 98 }; 99 100 /** 101 * @brief Retrieves computer system properties over dbus 102 * 103 * @param[in] aResp Shared pointer for completing asynchronous calls 104 * @param[in] name Computer system name from request 105 * 106 * @return None. 107 */ 108 void getComputerSystem(std::shared_ptr<SystemAsyncResp> aResp, 109 const std::string &name) { 110 const std::array<const char *, 5> interfaces = { 111 "xyz.openbmc_project.Inventory.Decorator.Asset", 112 "xyz.openbmc_project.Inventory.Item.Cpu", 113 "xyz.openbmc_project.Inventory.Item.Dimm", 114 "xyz.openbmc_project.Inventory.Item.System", 115 "xyz.openbmc_project.Common.UUID", 116 }; 117 BMCWEB_LOG_DEBUG << "Get available system components."; 118 crow::connections::systemBus->async_method_call( 119 [ name, aResp{std::move(aResp)} ]( 120 const boost::system::error_code ec, 121 const std::vector<std::pair< 122 std::string, 123 std::vector<std::pair<std::string, std::vector<std::string>>>>> 124 &subtree) { 125 if (ec) { 126 BMCWEB_LOG_DEBUG << "DBUS response error"; 127 aResp->setErrorStatus(); 128 return; 129 } 130 bool foundName = false; 131 // Iterate over all retrieved ObjectPaths. 132 for (const std::pair<std::string, 133 std::vector<std::pair<std::string, 134 std::vector<std::string>>>> 135 &object : subtree) { 136 const std::string &path = object.first; 137 BMCWEB_LOG_DEBUG << "Got path: " << path; 138 const std::vector<std::pair<std::string, std::vector<std::string>>> 139 &connectionNames = object.second; 140 if (connectionNames.size() < 1) { 141 continue; 142 } 143 // Check if computer system exist 144 if (boost::ends_with(path, name)) { 145 foundName = true; 146 BMCWEB_LOG_DEBUG << "Found name: " << name; 147 const std::string connectionName = connectionNames[0].first; 148 crow::connections::systemBus->async_method_call( 149 [ aResp, name(std::string(name)) ]( 150 const boost::system::error_code ec, 151 const std::vector<std::pair<std::string, VariantType>> 152 &propertiesList) { 153 if (ec) { 154 BMCWEB_LOG_ERROR << "DBUS response error: " << ec; 155 aResp->setErrorStatus(); 156 return; 157 } 158 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 159 << "properties for system"; 160 for (const std::pair<std::string, VariantType> &property : 161 propertiesList) { 162 const std::string *value = 163 mapbox::getPtr<const std::string>(property.second); 164 if (value != nullptr) { 165 aResp->res.jsonValue[property.first] = *value; 166 } 167 } 168 aResp->res.jsonValue["Name"] = name; 169 aResp->res.jsonValue["Id"] = 170 aResp->res.jsonValue["SerialNumber"]; 171 }, 172 connectionName, path, "org.freedesktop.DBus.Properties", 173 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset"); 174 } else { 175 // This is not system, so check if it's cpu, dimm, UUID or BiosVer 176 for (auto const &s : connectionNames) { 177 for (auto const &i : s.second) { 178 if (boost::ends_with(i, "Dimm")) { 179 BMCWEB_LOG_DEBUG << "Found Dimm, now get it properties."; 180 crow::connections::systemBus->async_method_call( 181 [&, aResp](const boost::system::error_code ec, 182 const std::vector<std::pair< 183 std::string, VariantType>> &properties) { 184 if (ec) { 185 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 186 aResp->setErrorStatus(); 187 return; 188 } 189 BMCWEB_LOG_DEBUG << "Got " << properties.size() 190 << "Dimm properties."; 191 for (const auto &p : properties) { 192 if (p.first == "MemorySize") { 193 const std::string *value = 194 mapbox::getPtr<const std::string>(p.second); 195 if ((value != nullptr) && (*value != "NULL")) { 196 // Remove units char 197 int32_t unitCoeff; 198 if (boost::ends_with(*value, "MB")) { 199 unitCoeff = 1000; 200 } else if (boost::ends_with(*value, "KB")) { 201 unitCoeff = 1000000; 202 } else { 203 BMCWEB_LOG_ERROR 204 << "Unsupported memory units"; 205 aResp->setErrorStatus(); 206 return; 207 } 208 209 auto memSize = boost::lexical_cast<int>( 210 value->substr(0, value->length() - 2)); 211 aResp->res.jsonValue["TotalSystemMemoryGiB"] += 212 memSize * unitCoeff; 213 aResp->res.jsonValue["MemorySummary"]["Status"] 214 ["State"] = "Enabled"; 215 } 216 } 217 } 218 }, 219 s.first, path, "org.freedesktop.DBus.Properties", 220 "GetAll", "xyz.openbmc_project.Inventory.Item.Dimm"); 221 } else if (boost::ends_with(i, "Cpu")) { 222 BMCWEB_LOG_DEBUG << "Found Cpu, now get it properties."; 223 crow::connections::systemBus->async_method_call( 224 [&, aResp](const boost::system::error_code ec, 225 const std::vector<std::pair< 226 std::string, VariantType>> &properties) { 227 if (ec) { 228 BMCWEB_LOG_ERROR << "DBUS response error " << ec; 229 aResp->setErrorStatus(); 230 return; 231 } 232 BMCWEB_LOG_DEBUG << "Got " << properties.size() 233 << "Cpu properties."; 234 for (const auto &p : properties) { 235 if (p.first == "ProcessorFamily") { 236 const std::string *value = 237 mapbox::getPtr<const std::string>(p.second); 238 if (value != nullptr) { 239 aResp->res 240 .jsonValue["ProcessorSummary"]["Count"] = 241 aResp->res 242 .jsonValue["ProcessorSummary"]["Count"] 243 .get<int>() + 244 1; 245 aResp->res.jsonValue["ProcessorSummary"] 246 ["Status"]["State"] = 247 "Enabled"; 248 aResp->res 249 .jsonValue["ProcessorSummary"]["Model"] = 250 *value; 251 } 252 } 253 } 254 }, 255 s.first, path, "org.freedesktop.DBus.Properties", 256 "GetAll", "xyz.openbmc_project.Inventory.Item.Cpu"); 257 } else if (boost::ends_with(i, "UUID")) { 258 BMCWEB_LOG_DEBUG << "Found UUID, now get it properties."; 259 crow::connections::systemBus->async_method_call( 260 [aResp](const boost::system::error_code ec, 261 const std::vector<std::pair< 262 std::string, VariantType>> &properties) { 263 if (ec) { 264 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 265 aResp->setErrorStatus(); 266 return; 267 } 268 BMCWEB_LOG_DEBUG << "Got " << properties.size() 269 << "UUID properties."; 270 for (const std::pair<std::string, VariantType> &p : 271 properties) { 272 if (p.first == "BIOSVer") { 273 const std::string *value = 274 mapbox::getPtr<const std::string>(p.second); 275 if (value != nullptr) { 276 aResp->res.jsonValue["BiosVersion"] = *value; 277 } 278 } 279 if (p.first == "UUID") { 280 const std::string *value = 281 mapbox::getPtr<const std::string>(p.second); 282 BMCWEB_LOG_DEBUG << "UUID = " << *value 283 << " length " << value->length(); 284 if (value != nullptr) { 285 // Workaround for to short return str in smbios 286 // demo app, 32 bytes are described by spec 287 if (value->length() > 0 && 288 value->length() < 32) { 289 std::string correctedValue = *value; 290 correctedValue.append(32 - value->length(), 291 '0'); 292 value = &correctedValue; 293 } else if (value->length() == 32) { 294 aResp->res.jsonValue["UUID"] = 295 value->substr(0, 8) + "-" + 296 value->substr(8, 4) + "-" + 297 value->substr(12, 4) + "-" + 298 value->substr(16, 4) + "-" + 299 value->substr(20, 12); 300 } 301 } 302 } 303 } 304 }, 305 s.first, path, "org.freedesktop.DBus.Properties", 306 "GetAll", "xyz.openbmc_project.Common.UUID"); 307 } 308 } 309 } 310 } 311 } 312 if (foundName == false) { 313 aResp->setErrorStatus(); 314 } 315 }, 316 "xyz.openbmc_project.ObjectMapper", 317 "/xyz/openbmc_project/object_mapper", 318 "xyz.openbmc_project.ObjectMapper", "GetSubTree", 319 "/xyz/openbmc_project/inventory", int32_t(0), interfaces); 320 } 321 322 /** 323 * @brief Retrieves identify led group properties over dbus 324 * 325 * @param[in] aResp Shared pointer for completing asynchronous calls. 326 * @param[in] callback Callback for process retrieved data. 327 * 328 * @return None. 329 */ 330 template <typename CallbackFunc> 331 void getLedGroupIdentify(std::shared_ptr<SystemAsyncResp> aResp, 332 CallbackFunc &&callback) { 333 BMCWEB_LOG_DEBUG << "Get led groups"; 334 crow::connections::systemBus->async_method_call( 335 [ 336 aResp{std::move(aResp)}, &callback 337 ](const boost::system::error_code &ec, const ManagedObjectsType &resp) { 338 if (ec) { 339 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 340 aResp->setErrorStatus(); 341 return; 342 } 343 BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects."; 344 for (const auto &objPath : resp) { 345 const std::string &path = objPath.first; 346 if (path.rfind("enclosure_identify") != std::string::npos) { 347 for (const auto &interface : objPath.second) { 348 if (interface.first == "xyz.openbmc_project.Led.Group") { 349 for (const auto &property : interface.second) { 350 if (property.first == "Asserted") { 351 const bool *asserted = 352 mapbox::getPtr<const bool>(property.second); 353 if (nullptr != asserted) { 354 callback(*asserted, aResp); 355 } else { 356 callback(false, aResp); 357 } 358 } 359 } 360 } 361 } 362 } 363 } 364 }, 365 "xyz.openbmc_project.LED.GroupManager", 366 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager", 367 "GetManagedObjects"); 368 } 369 370 template <typename CallbackFunc> 371 void getLedIdentify(std::shared_ptr<SystemAsyncResp> aResp, 372 CallbackFunc &&callback) { 373 BMCWEB_LOG_DEBUG << "Get identify led properties"; 374 crow::connections::systemBus->async_method_call( 375 [ aResp{std::move(aResp)}, &callback ]( 376 const boost::system::error_code ec, 377 const PropertiesType &properties) { 378 if (ec) { 379 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 380 aResp->setErrorStatus(); 381 return; 382 } 383 BMCWEB_LOG_DEBUG << "Got " << properties.size() << "led properties."; 384 std::string output; 385 for (const auto &property : properties) { 386 if (property.first == "State") { 387 const std::string *s = 388 mapbox::getPtr<std::string>(property.second); 389 if (nullptr != s) { 390 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s; 391 const auto pos = s->rfind('.'); 392 if (pos != std::string::npos) { 393 auto led = s->substr(pos + 1); 394 for (const std::pair<const char *, const char *> &p : 395 std::array<std::pair<const char *, const char *>, 3>{ 396 {{"On", "Lit"}, 397 {"Blink", "Blinking"}, 398 {"Off", "Off"}}}) { 399 if (led == p.first) { 400 output = p.second; 401 } 402 } 403 } 404 } 405 } 406 } 407 callback(output, aResp); 408 }, 409 "xyz.openbmc_project.LED.Controller.identify", 410 "/xyz/openbmc_project/led/physical/identify", 411 "org.freedesktop.DBus.Properties", "GetAll", 412 "xyz.openbmc_project.Led.Physical"); 413 } 414 415 /** 416 * @brief Retrieves host state properties over dbus 417 * 418 * @param[in] aResp Shared pointer for completing asynchronous calls. 419 * 420 * @return None. 421 */ 422 void getHostState(std::shared_ptr<SystemAsyncResp> aResp) { 423 BMCWEB_LOG_DEBUG << "Get host information."; 424 crow::connections::systemBus->async_method_call( 425 [aResp{std::move(aResp)}](const boost::system::error_code ec, 426 const PropertiesType &properties) { 427 if (ec) { 428 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 429 aResp->setErrorStatus(); 430 return; 431 } 432 BMCWEB_LOG_DEBUG << "Got " << properties.size() << "host properties."; 433 for (const auto &property : properties) { 434 if (property.first == "CurrentHostState") { 435 const std::string *s = 436 mapbox::getPtr<const std::string>(property.second); 437 BMCWEB_LOG_DEBUG << "Host state: " << *s; 438 if (nullptr != s) { 439 const auto pos = s->rfind('.'); 440 if (pos != std::string::npos) { 441 // Verify Host State 442 if (s->substr(pos + 1) == "Running") { 443 aResp->res.jsonValue["PowerState"] = "On"; 444 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 445 } else { 446 aResp->res.jsonValue["PowerState"] = "Off"; 447 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 448 } 449 } 450 } 451 } 452 } 453 }, 454 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 455 "org.freedesktop.DBus.Properties", "GetAll", 456 "xyz.openbmc_project.State.Host"); 457 } 458 }; 459 460 /** 461 * SystemsCollection derived class for delivering ComputerSystems Collection 462 * Schema 463 */ 464 class SystemsCollection : public Node { 465 public: 466 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") { 467 Node::json["@odata.type"] = 468 "#ComputerSystemCollection.ComputerSystemCollection"; 469 Node::json["@odata.id"] = "/redfish/v1/Systems"; 470 Node::json["@odata.context"] = 471 "/redfish/v1/" 472 "$metadata#ComputerSystemCollection.ComputerSystemCollection"; 473 Node::json["Name"] = "Computer System Collection"; 474 475 entityPrivileges = { 476 {boost::beast::http::verb::get, {{"Login"}}}, 477 {boost::beast::http::verb::head, {{"Login"}}}, 478 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 479 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 480 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 481 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 482 } 483 484 private: 485 /** 486 * Functions triggers appropriate requests on DBus 487 */ 488 void doGet(crow::Response &res, const crow::Request &req, 489 const std::vector<std::string> ¶ms) override { 490 // Get board list, and call the below callback for JSON preparation 491 provider.getBaseboardList( 492 [&](const bool &success, const std::vector<std::string> &output) { 493 if (success) { 494 // ... prepare json array with appropriate @odata.id links 495 nlohmann::json boardArray = nlohmann::json::array(); 496 for (const std::string &boardItem : output) { 497 boardArray.push_back( 498 {{"@odata.id", "/redfish/v1/Systems/" + boardItem}}); 499 } 500 // Then attach members, count size and return, 501 Node::json["Members"] = boardArray; 502 Node::json["Members@odata.count"] = boardArray.size(); 503 res.jsonValue = Node::json; 504 } else { 505 // ... otherwise, return INTERNALL ERROR 506 res.result(boost::beast::http::status::internal_server_error); 507 } 508 res.end(); 509 }); 510 } 511 512 OnDemandSystemsProvider provider; 513 }; 514 515 /** 516 * Systems override class for delivering ComputerSystems Schema 517 */ 518 class Systems : public Node { 519 public: 520 /* 521 * Default Constructor 522 */ 523 Systems(CrowApp &app) 524 : Node(app, "/redfish/v1/Systems/<str>/", std::string()) { 525 Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem"; 526 Node::json["@odata.context"] = 527 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 528 Node::json["SystemType"] = "Physical"; 529 Node::json["Description"] = "Computer System"; 530 Node::json["Boot"]["BootSourceOverrideEnabled"] = 531 "Disabled"; // TODO(Dawid), get real boot data 532 Node::json["Boot"]["BootSourceOverrideTarget"] = 533 "None"; // TODO(Dawid), get real boot data 534 Node::json["Boot"]["BootSourceOverrideMode"] = 535 "Legacy"; // TODO(Dawid), get real boot data 536 Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] = { 537 "None", "Pxe", "Hdd", "Cd", 538 "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot data 539 Node::json["ProcessorSummary"]["Count"] = int(0); 540 Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled"; 541 Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 542 Node::json["MemorySummary"]["Status"]["State"] = "Disabled"; 543 544 entityPrivileges = { 545 {boost::beast::http::verb::get, {{"Login"}}}, 546 {boost::beast::http::verb::head, {{"Login"}}}, 547 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 548 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 549 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 550 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 551 } 552 553 private: 554 OnDemandSystemsProvider provider; 555 556 /** 557 * Functions triggers appropriate requests on DBus 558 */ 559 void doGet(crow::Response &res, const crow::Request &req, 560 const std::vector<std::string> ¶ms) override { 561 // Check if there is required param, truly entering this shall be 562 // impossible 563 if (params.size() != 1) { 564 res.result(boost::beast::http::status::internal_server_error); 565 res.end(); 566 return; 567 } 568 569 const std::string &name = params[0]; 570 571 res.jsonValue = Node::json; 572 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name; 573 574 auto asyncResp = std::make_shared<SystemAsyncResp>(res); 575 576 provider.getLedGroupIdentify( 577 asyncResp, [&](const bool &asserted, 578 const std::shared_ptr<SystemAsyncResp> &aResp) { 579 if (asserted) { 580 // If led group is asserted, then another call is needed to 581 // get led status 582 provider.getLedIdentify( 583 aResp, [](const std::string &ledStatus, 584 const std::shared_ptr<SystemAsyncResp> &aResp) { 585 if (!ledStatus.empty()) { 586 aResp->res.jsonValue["IndicatorLED"] = ledStatus; 587 } 588 }); 589 } else { 590 aResp->res.jsonValue["IndicatorLED"] = "Off"; 591 } 592 }); 593 provider.getComputerSystem(asyncResp, name); 594 provider.getHostState(asyncResp); 595 } 596 597 void doPatch(crow::Response &res, const crow::Request &req, 598 const std::vector<std::string> ¶ms) override { 599 // Check if there is required param, truly entering this shall be 600 // impossible 601 if (params.size() != 1) { 602 res.result(boost::beast::http::status::internal_server_error); 603 res.end(); 604 return; 605 } 606 // Parse JSON request body 607 nlohmann::json patch; 608 if (!json_util::processJsonFromRequest(res, req, patch)) { 609 return; 610 } 611 // Find key with new led value 612 const std::string &name = params[0]; 613 const std::string *reqLedState = nullptr; 614 json_util::Result r = json_util::getString( 615 "IndicatorLED", patch, reqLedState, 616 static_cast<int>(json_util::MessageSetting::TYPE_ERROR) | 617 static_cast<int>(json_util::MessageSetting::MISSING), 618 res.jsonValue, std::string("/" + name + "/IndicatorLED")); 619 if ((r != json_util::Result::SUCCESS) || (reqLedState == nullptr)) { 620 res.result(boost::beast::http::status::bad_request); 621 res.end(); 622 return; 623 } 624 // Verify key value 625 std::string dbusLedState; 626 for (const auto &p : boost::container::flat_map<const char *, const char *>{ 627 {"On", "Lit"}, {"Blink", "Blinking"}, {"Off", "Off"}}) { 628 if (*reqLedState == p.second) { 629 dbusLedState = p.first; 630 } 631 } 632 633 // Update led status 634 auto asyncResp = std::make_shared<SystemAsyncResp>(res); 635 res.jsonValue = Node::json; 636 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name; 637 638 provider.getHostState(asyncResp); 639 provider.getComputerSystem(asyncResp, name); 640 641 if (dbusLedState.empty()) { 642 messages::addMessageToJsonRoot( 643 res.jsonValue, 644 messages::propertyValueNotInList(*reqLedState, "IndicatorLED")); 645 } else { 646 // Update led group 647 BMCWEB_LOG_DEBUG << "Update led group."; 648 crow::connections::systemBus->async_method_call( 649 [&, asyncResp{std::move(asyncResp)} ]( 650 const boost::system::error_code ec) { 651 if (ec) { 652 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 653 asyncResp->setErrorStatus(); 654 return; 655 } 656 BMCWEB_LOG_DEBUG << "Led group update done."; 657 }, 658 "xyz.openbmc_project.LED.GroupManager", 659 "/xyz/openbmc_project/led/groups/enclosure_identify", 660 "org.freedesktop.DBus.Properties", "Set", 661 "xyz.openbmc_project.Led.Group", "Asserted", 662 sdbusplus::message::variant<bool>( 663 (dbusLedState == "Off" ? false : true))); 664 // Update identify led status 665 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 666 crow::connections::systemBus->async_method_call( 667 [&, asyncResp{std::move(asyncResp)} ]( 668 const boost::system::error_code ec) { 669 if (ec) { 670 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 671 asyncResp->setErrorStatus(); 672 return; 673 } 674 BMCWEB_LOG_DEBUG << "Led state update done."; 675 res.jsonValue["IndicatorLED"] = *reqLedState; 676 }, 677 "xyz.openbmc_project.LED.Controller.identify", 678 "/xyz/openbmc_project/led/physical/identify", 679 "org.freedesktop.DBus.Properties", "Set", 680 "xyz.openbmc_project.Led.Physical", "State", 681 sdbusplus::message::variant<std::string>( 682 "xyz.openbmc_project.Led.Physical.Action." + dbusLedState)); 683 } 684 } 685 }; 686 } // namespace redfish 687