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 #include <variant> 22 23 namespace redfish 24 { 25 26 /** 27 * @brief Retrieves computer system properties over dbus 28 * 29 * @param[in] aResp Shared pointer for completing asynchronous calls 30 * @param[in] name Computer system name from request 31 * 32 * @return None. 33 */ 34 void getComputerSystem(std::shared_ptr<AsyncResp> aResp, 35 const std::string &name) 36 { 37 BMCWEB_LOG_DEBUG << "Get available system components."; 38 crow::connections::systemBus->async_method_call( 39 [name, aResp{std::move(aResp)}]( 40 const boost::system::error_code ec, 41 const std::vector<std::pair< 42 std::string, 43 std::vector<std::pair<std::string, std::vector<std::string>>>>> 44 &subtree) { 45 if (ec) 46 { 47 BMCWEB_LOG_DEBUG << "DBUS response error"; 48 messages::internalError(aResp->res); 49 return; 50 } 51 bool foundName = false; 52 // Iterate over all retrieved ObjectPaths. 53 for (const std::pair<std::string, 54 std::vector<std::pair< 55 std::string, std::vector<std::string>>>> 56 &object : subtree) 57 { 58 const std::string &path = object.first; 59 BMCWEB_LOG_DEBUG << "Got path: " << path; 60 const std::vector< 61 std::pair<std::string, std::vector<std::string>>> 62 &connectionNames = object.second; 63 if (connectionNames.size() < 1) 64 { 65 continue; 66 } 67 // Check if computer system exist 68 if (boost::ends_with(path, name)) 69 { 70 foundName = true; 71 BMCWEB_LOG_DEBUG << "Found name: " << name; 72 const std::string connectionName = connectionNames[0].first; 73 crow::connections::systemBus->async_method_call( 74 [aResp, name(std::string(name))]( 75 const boost::system::error_code ec, 76 const std::vector<std::pair< 77 std::string, VariantType>> &propertiesList) { 78 if (ec) 79 { 80 BMCWEB_LOG_ERROR << "DBUS response error: " 81 << ec; 82 messages::internalError(aResp->res); 83 return; 84 } 85 BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() 86 << "properties for system"; 87 for (const std::pair<std::string, VariantType> 88 &property : propertiesList) 89 { 90 const std::string *value = 91 std::get_if<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 std::get_if<bool>(&property.second); 359 if (nullptr != asserted) 360 { 361 callback(*asserted, aResp); 362 } 363 else 364 { 365 callback(false, aResp); 366 } 367 } 368 } 369 } 370 } 371 } 372 } 373 }, 374 "xyz.openbmc_project.LED.GroupManager", 375 "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager", 376 "GetManagedObjects"); 377 } 378 379 template <typename CallbackFunc> 380 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback) 381 { 382 BMCWEB_LOG_DEBUG << "Get identify led properties"; 383 crow::connections::systemBus->async_method_call( 384 [aResp, 385 callback{std::move(callback)}](const boost::system::error_code ec, 386 const PropertiesType &properties) { 387 if (ec) 388 { 389 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 390 messages::internalError(aResp->res); 391 return; 392 } 393 BMCWEB_LOG_DEBUG << "Got " << properties.size() 394 << "led properties."; 395 std::string output; 396 for (const auto &property : properties) 397 { 398 if (property.first == "State") 399 { 400 const std::string *s = 401 std::get_if<std::string>(&property.second); 402 if (nullptr != s) 403 { 404 BMCWEB_LOG_DEBUG << "Identify Led State: " << *s; 405 const auto pos = s->rfind('.'); 406 if (pos != std::string::npos) 407 { 408 auto led = s->substr(pos + 1); 409 for (const std::pair<const char *, const char *> 410 &p : 411 std::array< 412 std::pair<const char *, const char *>, 3>{ 413 {{"On", "Lit"}, 414 {"Blink", "Blinking"}, 415 {"Off", "Off"}}}) 416 { 417 if (led == p.first) 418 { 419 output = p.second; 420 } 421 } 422 } 423 } 424 } 425 } 426 callback(output, aResp); 427 }, 428 "xyz.openbmc_project.LED.Controller.identify", 429 "/xyz/openbmc_project/led/physical/identify", 430 "org.freedesktop.DBus.Properties", "GetAll", 431 "xyz.openbmc_project.Led.Physical"); 432 } 433 434 /** 435 * @brief Retrieves host state properties over dbus 436 * 437 * @param[in] aResp Shared pointer for completing asynchronous calls. 438 * 439 * @return None. 440 */ 441 void getHostState(std::shared_ptr<AsyncResp> aResp) 442 { 443 BMCWEB_LOG_DEBUG << "Get host information."; 444 crow::connections::systemBus->async_method_call( 445 [aResp{std::move(aResp)}](const boost::system::error_code ec, 446 const std::variant<std::string> &hostState) { 447 if (ec) 448 { 449 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 450 messages::internalError(aResp->res); 451 return; 452 } 453 454 const std::string *s = std::get_if<std::string>(&hostState); 455 BMCWEB_LOG_DEBUG << "Host state: " << *s; 456 if (s != nullptr) 457 { 458 // Verify Host State 459 if (*s == "xyz.openbmc_project.State.Host.HostState.Running") 460 { 461 aResp->res.jsonValue["PowerState"] = "On"; 462 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 463 } 464 else 465 { 466 aResp->res.jsonValue["PowerState"] = "Off"; 467 aResp->res.jsonValue["Status"]["State"] = "Disabled"; 468 } 469 } 470 }, 471 "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", 472 "org.freedesktop.DBus.Properties", "Get", 473 "xyz.openbmc_project.State.Host", "CurrentHostState"); 474 } 475 476 /** 477 * SystemsCollection derived class for delivering ComputerSystems Collection 478 * Schema 479 */ 480 class SystemsCollection : public Node 481 { 482 public: 483 SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") 484 { 485 entityPrivileges = { 486 {boost::beast::http::verb::get, {{"Login"}}}, 487 {boost::beast::http::verb::head, {{"Login"}}}, 488 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 489 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 490 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 491 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 492 } 493 494 private: 495 void doGet(crow::Response &res, const crow::Request &req, 496 const std::vector<std::string> ¶ms) override 497 { 498 BMCWEB_LOG_DEBUG << "Get list of available boards."; 499 std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 500 res.jsonValue["@odata.type"] = 501 "#ComputerSystemCollection.ComputerSystemCollection"; 502 res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; 503 res.jsonValue["@odata.context"] = 504 "/redfish/v1/" 505 "$metadata#ComputerSystemCollection.ComputerSystemCollection"; 506 res.jsonValue["Name"] = "Computer System Collection"; 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 std::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 std::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 entityPrivileges = { 656 {boost::beast::http::verb::get, {{"Login"}}}, 657 {boost::beast::http::verb::head, {{"Login"}}}, 658 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 659 {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 660 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 661 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 662 } 663 664 private: 665 /** 666 * Functions triggers appropriate requests on DBus 667 */ 668 void doGet(crow::Response &res, const crow::Request &req, 669 const std::vector<std::string> ¶ms) override 670 { 671 // Check if there is required param, truly entering this shall be 672 // impossible 673 if (params.size() != 1) 674 { 675 messages::internalError(res); 676 res.end(); 677 return; 678 } 679 680 const std::string &name = params[0]; 681 682 res.jsonValue["@odata.type"] = "#ComputerSystem.v1_5_1.ComputerSystem"; 683 res.jsonValue["@odata.context"] = 684 "/redfish/v1/$metadata#ComputerSystem.ComputerSystem"; 685 res.jsonValue["SystemType"] = "Physical"; 686 res.jsonValue["Description"] = "Computer System"; 687 res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = 688 "Disabled"; // TODO(Dawid), get real boot data 689 res.jsonValue["Boot"]["BootSourceOverrideTarget"] = 690 "None"; // TODO(Dawid), get real boot data 691 res.jsonValue["Boot"]["BootSourceOverrideMode"] = 692 "Legacy"; // TODO(Dawid), get real boot data 693 res.jsonValue["Boot"] 694 ["BootSourceOverrideTarget@Redfish.AllowableValues"] = { 695 "None", "Pxe", "Hdd", "Cd", 696 "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot 697 // data 698 res.jsonValue["ProcessorSummary"]["Count"] = 0; 699 res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled"; 700 res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0); 701 res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled"; 702 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name; 703 704 res.jsonValue["Processors"] = { 705 {"@odata.id", "/redfish/v1/Systems/" + name + "/Processors"}}; 706 res.jsonValue["Memory"] = { 707 {"@odata.id", "/redfish/v1/Systems/" + name + "/Memory"}}; 708 // TODO Need to support ForceRestart. 709 res.jsonValue["Actions"]["#ComputerSystem.Reset"] = { 710 {"target", 711 "/redfish/v1/Systems/" + name + "/Actions/ComputerSystem.Reset"}, 712 {"ResetType@Redfish.AllowableValues", 713 {"On", "ForceOff", "GracefulRestart", "GracefulShutdown"}}}; 714 715 res.jsonValue["LogServices"] = { 716 {"@odata.id", "/redfish/v1/Systems/" + name + "/LogServices"}}; 717 718 auto asyncResp = std::make_shared<AsyncResp>(res); 719 720 getLedGroupIdentify( 721 asyncResp, 722 [&](const bool &asserted, const std::shared_ptr<AsyncResp> &aResp) { 723 if (asserted) 724 { 725 // If led group is asserted, then another call is needed to 726 // get led status 727 getLedIdentify( 728 aResp, [](const std::string &ledStatus, 729 const std::shared_ptr<AsyncResp> &aResp) { 730 if (!ledStatus.empty()) 731 { 732 aResp->res.jsonValue["IndicatorLED"] = 733 ledStatus; 734 } 735 }); 736 } 737 else 738 { 739 aResp->res.jsonValue["IndicatorLED"] = "Off"; 740 } 741 }); 742 getComputerSystem(asyncResp, name); 743 getHostState(asyncResp); 744 } 745 746 void doPatch(crow::Response &res, const crow::Request &req, 747 const std::vector<std::string> ¶ms) override 748 { 749 // Check if there is required param, truly entering this shall be 750 // impossible 751 auto asyncResp = std::make_shared<AsyncResp>(res); 752 if (params.size() != 1) 753 { 754 messages::internalError(asyncResp->res); 755 return; 756 } 757 758 const std::string &name = params[0]; 759 760 messages::success(asyncResp->res); 761 762 std::string indicatorLedTemp; 763 std::optional<std::string> indicatorLed = indicatorLedTemp; 764 if (!json_util::readJson(req, res, "IndicatorLed", indicatorLed)) 765 { 766 return; 767 } 768 769 if (indicatorLed) 770 { 771 std::string dbusLedState; 772 if (*indicatorLed == "On") 773 { 774 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Lit"; 775 } 776 else if (*indicatorLed == "Blink") 777 { 778 dbusLedState = 779 "xyz.openbmc_project.Led.Physical.Action.Blinking"; 780 } 781 else if (*indicatorLed == "Off") 782 { 783 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off"; 784 } 785 else 786 { 787 messages::propertyValueNotInList(res, *indicatorLed, 788 "IndicatorLED"); 789 return; 790 } 791 792 getHostState(asyncResp); 793 getComputerSystem(asyncResp, name); 794 795 // Update led group 796 BMCWEB_LOG_DEBUG << "Update led group."; 797 crow::connections::systemBus->async_method_call( 798 [asyncResp{std::move(asyncResp)}]( 799 const boost::system::error_code ec) { 800 if (ec) 801 { 802 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 803 messages::internalError(asyncResp->res); 804 return; 805 } 806 BMCWEB_LOG_DEBUG << "Led group update done."; 807 }, 808 "xyz.openbmc_project.LED.GroupManager", 809 "/xyz/openbmc_project/led/groups/enclosure_identify", 810 "org.freedesktop.DBus.Properties", "Set", 811 "xyz.openbmc_project.Led.Group", "Asserted", 812 std::variant<bool>( 813 (dbusLedState == 814 "xyz.openbmc_project.Led.Physical.Action.Off" 815 ? false 816 : true))); 817 // Update identify led status 818 BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection."; 819 crow::connections::systemBus->async_method_call( 820 [asyncResp{std::move(asyncResp)}, 821 indicatorLed{std::move(*indicatorLed)}]( 822 const boost::system::error_code ec) { 823 if (ec) 824 { 825 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; 826 messages::internalError(asyncResp->res); 827 return; 828 } 829 BMCWEB_LOG_DEBUG << "Led state update done."; 830 }, 831 "xyz.openbmc_project.LED.Controller.identify", 832 "/xyz/openbmc_project/led/physical/identify", 833 "org.freedesktop.DBus.Properties", "Set", 834 "xyz.openbmc_project.Led.Physical", "State", 835 std::variant<std::string>(dbusLedState)); 836 } 837 } 838 }; 839 } // namespace redfish 840