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