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