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