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