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