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