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