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