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