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