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