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