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