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