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