xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 9712f8ac42746e65f32c2bc3de0835846652568e)
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> &params) 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> &params) 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> &params) 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> &params) 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