xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision f5c9f8bda365b90c978a95738b66419ad21df27f)
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 "health.hpp"
19 #include "pcie.hpp"
20 #include "redfish_util.hpp"
21 
22 #include <boost/container/flat_map.hpp>
23 #include <node.hpp>
24 #include <utils/fw_utils.hpp>
25 #include <utils/json_utils.hpp>
26 #include <variant>
27 
28 namespace redfish
29 {
30 
31 /**
32  * @brief Retrieves computer system properties over dbus
33  *
34  * @param[in] aResp Shared pointer for completing asynchronous calls
35  * @param[in] name  Computer system name from request
36  *
37  * @return None.
38  */
39 void getComputerSystem(std::shared_ptr<AsyncResp> aResp)
40 {
41     BMCWEB_LOG_DEBUG << "Get available system components.";
42     crow::connections::systemBus->async_method_call(
43         [aResp](
44             const boost::system::error_code ec,
45             const std::vector<std::pair<
46                 std::string,
47                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
48                 &subtree) {
49             if (ec)
50             {
51                 BMCWEB_LOG_DEBUG << "DBUS response error";
52                 messages::internalError(aResp->res);
53                 return;
54             }
55             // Iterate over all retrieved ObjectPaths.
56             for (const std::pair<std::string,
57                                  std::vector<std::pair<
58                                      std::string, std::vector<std::string>>>>
59                      &object : subtree)
60             {
61                 const std::string &path = object.first;
62                 BMCWEB_LOG_DEBUG << "Got path: " << path;
63                 const std::vector<
64                     std::pair<std::string, std::vector<std::string>>>
65                     &connectionNames = object.second;
66                 if (connectionNames.size() < 1)
67                 {
68                     continue;
69                 }
70 
71                 // This is not system, so check if it's cpu, dimm, UUID or
72                 // BiosVer
73                 for (const auto &connection : connectionNames)
74                 {
75                     for (const auto &interfaceName : connection.second)
76                     {
77                         if (interfaceName ==
78                             "xyz.openbmc_project.Inventory.Item.Dimm")
79                         {
80                             BMCWEB_LOG_DEBUG
81                                 << "Found Dimm, now get its properties.";
82                             crow::connections::systemBus->async_method_call(
83                                 [aResp](const boost::system::error_code ec,
84                                         const std::vector<
85                                             std::pair<std::string, VariantType>>
86                                             &properties) {
87                                     if (ec)
88                                     {
89                                         BMCWEB_LOG_ERROR
90                                             << "DBUS response error " << ec;
91                                         messages::internalError(aResp->res);
92                                         return;
93                                     }
94                                     BMCWEB_LOG_DEBUG << "Got "
95                                                      << properties.size()
96                                                      << "Dimm properties.";
97                                     for (const std::pair<std::string,
98                                                          VariantType>
99                                              &property : properties)
100                                     {
101                                         if (property.first == "MemorySizeInKb")
102                                         {
103                                             const uint64_t *value =
104                                                 sdbusplus::message::variant_ns::
105                                                     get_if<uint64_t>(
106                                                         &property.second);
107                                             if (value != nullptr)
108                                             {
109                                                 aResp->res.jsonValue
110                                                     ["TotalSystemMemoryGi"
111                                                      "B"] +=
112                                                     *value / (1024 * 1024);
113                                                 aResp->res
114                                                     .jsonValue["MemorySummary"]
115                                                               ["Status"]
116                                                               ["State"] =
117                                                     "Enabled";
118                                             }
119                                         }
120                                     }
121                                 },
122                                 connection.first, path,
123                                 "org.freedesktop.DBus.Properties", "GetAll",
124                                 "xyz.openbmc_project.Inventory.Item.Dimm");
125                         }
126                         else if (interfaceName ==
127                                  "xyz.openbmc_project.Inventory.Item.Cpu")
128                         {
129                             BMCWEB_LOG_DEBUG
130                                 << "Found Cpu, now get its properties.";
131                             crow::connections::systemBus->async_method_call(
132                                 [aResp](const boost::system::error_code ec,
133                                         const std::vector<
134                                             std::pair<std::string, VariantType>>
135                                             &properties) {
136                                     if (ec)
137                                     {
138                                         BMCWEB_LOG_ERROR
139                                             << "DBUS response error " << ec;
140                                         messages::internalError(aResp->res);
141                                         return;
142                                     }
143                                     BMCWEB_LOG_DEBUG << "Got "
144                                                      << properties.size()
145                                                      << "Cpu properties.";
146                                     for (const auto &property : properties)
147                                     {
148                                         if (property.first == "ProcessorFamily")
149                                         {
150                                             const std::string *value =
151                                                 sdbusplus::message::variant_ns::
152                                                     get_if<std::string>(
153                                                         &property.second);
154                                             if (value != nullptr)
155                                             {
156                                                 nlohmann::json &procSummary =
157                                                     aResp->res.jsonValue
158                                                         ["ProcessorSumm"
159                                                          "ary"];
160                                                 nlohmann::json &procCount =
161                                                     procSummary["Count"];
162 
163                                                 procCount =
164                                                     procCount.get<int>() + 1;
165                                                 procSummary["Status"]["State"] =
166                                                     "Enabled";
167                                                 procSummary["Model"] = *value;
168                                             }
169                                         }
170                                     }
171                                 },
172                                 connection.first, path,
173                                 "org.freedesktop.DBus.Properties", "GetAll",
174                                 "xyz.openbmc_project.Inventory.Item.Cpu");
175                         }
176                         else if (interfaceName ==
177                                  "xyz.openbmc_project.Common.UUID")
178                         {
179                             BMCWEB_LOG_DEBUG
180                                 << "Found UUID, now get its properties.";
181                             crow::connections::systemBus->async_method_call(
182                                 [aResp](const boost::system::error_code ec,
183                                         const std::vector<
184                                             std::pair<std::string, VariantType>>
185                                             &properties) {
186                                     if (ec)
187                                     {
188                                         BMCWEB_LOG_DEBUG
189                                             << "DBUS response error " << ec;
190                                         messages::internalError(aResp->res);
191                                         return;
192                                     }
193                                     BMCWEB_LOG_DEBUG << "Got "
194                                                      << properties.size()
195                                                      << "UUID properties.";
196                                     for (const std::pair<std::string,
197                                                          VariantType>
198                                              &property : properties)
199                                     {
200                                         if (property.first == "UUID")
201                                         {
202                                             const std::string *value =
203                                                 sdbusplus::message::variant_ns::
204                                                     get_if<std::string>(
205                                                         &property.second);
206 
207                                             if (value != nullptr)
208                                             {
209                                                 std::string valueStr = *value;
210                                                 if (valueStr.size() == 32)
211                                                 {
212                                                     valueStr.insert(8, 1, '-');
213                                                     valueStr.insert(13, 1, '-');
214                                                     valueStr.insert(18, 1, '-');
215                                                     valueStr.insert(23, 1, '-');
216                                                 }
217                                                 BMCWEB_LOG_DEBUG << "UUID = "
218                                                                  << valueStr;
219                                                 aResp->res.jsonValue["UUID"] =
220                                                     valueStr;
221                                             }
222                                         }
223                                     }
224                                 },
225                                 connection.first, path,
226                                 "org.freedesktop.DBus.Properties", "GetAll",
227                                 "xyz.openbmc_project.Common.UUID");
228                         }
229                         else if (interfaceName ==
230                                  "xyz.openbmc_project.Inventory.Item.System")
231                         {
232                             crow::connections::systemBus->async_method_call(
233                                 [aResp](const boost::system::error_code ec,
234                                         const std::vector<
235                                             std::pair<std::string, VariantType>>
236                                             &propertiesList) {
237                                     if (ec)
238                                     {
239                                         // doesn't have to include this
240                                         // interface
241                                         return;
242                                     }
243                                     BMCWEB_LOG_DEBUG << "Got "
244                                                      << propertiesList.size()
245                                                      << "properties for system";
246                                     for (const std::pair<std::string,
247                                                          VariantType>
248                                              &property : propertiesList)
249                                     {
250                                         const std::string &propertyName =
251                                             property.first;
252                                         if ((propertyName == "PartNumber") ||
253                                             (propertyName == "SerialNumber") ||
254                                             (propertyName == "Manufacturer") ||
255                                             (propertyName == "Model"))
256                                         {
257                                             const std::string *value =
258                                                 std::get_if<std::string>(
259                                                     &property.second);
260                                             if (value != nullptr)
261                                             {
262                                                 aResp->res
263                                                     .jsonValue[propertyName] =
264                                                     *value;
265                                             }
266                                         }
267                                     }
268                                     aResp->res.jsonValue["Name"] = "system";
269                                     aResp->res.jsonValue["Id"] =
270                                         aResp->res.jsonValue["SerialNumber"];
271                                     // Grab the bios version
272                                     fw_util::getActiveFwVersion(
273                                         aResp, fw_util::biosPurpose,
274                                         "BiosVersion");
275                                 },
276                                 connection.first, path,
277                                 "org.freedesktop.DBus.Properties", "GetAll",
278                                 "xyz.openbmc_project.Inventory.Decorator."
279                                 "Asset");
280 
281                             crow::connections::systemBus->async_method_call(
282                                 [aResp](
283                                     const boost::system::error_code ec,
284                                     const std::variant<std::string> &property) {
285                                     if (ec)
286                                     {
287                                         // doesn't have to include this
288                                         // interface
289                                         return;
290                                     }
291 
292                                     const std::string *value =
293                                         std::get_if<std::string>(&property);
294                                     if (value != nullptr)
295                                     {
296                                         aResp->res.jsonValue["AssetTag"] =
297                                             *value;
298                                     }
299                                 },
300                                 connection.first, path,
301                                 "org.freedesktop.DBus.Properties", "Get",
302                                 "xyz.openbmc_project.Inventory.Decorator."
303                                 "AssetTag",
304                                 "AssetTag");
305                         }
306                     }
307                 }
308             }
309         },
310         "xyz.openbmc_project.ObjectMapper",
311         "/xyz/openbmc_project/object_mapper",
312         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
313         "/xyz/openbmc_project/inventory", int32_t(0),
314         std::array<const char *, 5>{
315             "xyz.openbmc_project.Inventory.Decorator.Asset",
316             "xyz.openbmc_project.Inventory.Item.Cpu",
317             "xyz.openbmc_project.Inventory.Item.Dimm",
318             "xyz.openbmc_project.Inventory.Item.System",
319             "xyz.openbmc_project.Common.UUID",
320         });
321 }
322 
323 /**
324  * @brief Retrieves identify led group properties over dbus
325  *
326  * @param[in] aResp     Shared pointer for generating response message.
327  * @param[in] callback  Callback for process retrieved data.
328  *
329  * @return None.
330  */
331 template <typename CallbackFunc>
332 void getLedGroupIdentify(std::shared_ptr<AsyncResp> aResp,
333                          CallbackFunc &&callback)
334 {
335     BMCWEB_LOG_DEBUG << "Get led groups";
336     crow::connections::systemBus->async_method_call(
337         [aResp,
338          callback{std::move(callback)}](const boost::system::error_code &ec,
339                                         const ManagedObjectsType &resp) {
340             if (ec)
341             {
342                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
343                 messages::internalError(aResp->res);
344                 return;
345             }
346             BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects.";
347             for (const auto &objPath : resp)
348             {
349                 const std::string &path = objPath.first;
350                 if (path.rfind("enclosure_identify") != std::string::npos)
351                 {
352                     for (const auto &interface : objPath.second)
353                     {
354                         if (interface.first == "xyz.openbmc_project.Led.Group")
355                         {
356                             for (const auto &property : interface.second)
357                             {
358                                 if (property.first == "Asserted")
359                                 {
360                                     const bool *asserted =
361                                         std::get_if<bool>(&property.second);
362                                     if (nullptr != asserted)
363                                     {
364                                         callback(*asserted, aResp);
365                                     }
366                                     else
367                                     {
368                                         callback(false, aResp);
369                                     }
370                                 }
371                             }
372                         }
373                     }
374                 }
375             }
376         },
377         "xyz.openbmc_project.LED.GroupManager",
378         "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager",
379         "GetManagedObjects");
380 }
381 
382 template <typename CallbackFunc>
383 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback)
384 {
385     BMCWEB_LOG_DEBUG << "Get identify led properties";
386     crow::connections::systemBus->async_method_call(
387         [aResp,
388          callback{std::move(callback)}](const boost::system::error_code ec,
389                                         const PropertiesType &properties) {
390             if (ec)
391             {
392                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
393                 messages::internalError(aResp->res);
394                 return;
395             }
396             BMCWEB_LOG_DEBUG << "Got " << properties.size()
397                              << "led properties.";
398             std::string output;
399             for (const auto &property : properties)
400             {
401                 if (property.first == "State")
402                 {
403                     const std::string *s =
404                         std::get_if<std::string>(&property.second);
405                     if (nullptr != s)
406                     {
407                         BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
408                         const auto pos = s->rfind('.');
409                         if (pos != std::string::npos)
410                         {
411                             auto led = s->substr(pos + 1);
412                             for (const std::pair<const char *, const char *>
413                                      &p :
414                                  std::array<
415                                      std::pair<const char *, const char *>, 3>{
416                                      {{"On", "Lit"},
417                                       {"Blink", "Blinking"},
418                                       {"Off", "Off"}}})
419                             {
420                                 if (led == p.first)
421                                 {
422                                     output = p.second;
423                                 }
424                             }
425                         }
426                     }
427                 }
428             }
429             callback(output, aResp);
430         },
431         "xyz.openbmc_project.LED.Controller.identify",
432         "/xyz/openbmc_project/led/physical/identify",
433         "org.freedesktop.DBus.Properties", "GetAll",
434         "xyz.openbmc_project.Led.Physical");
435 }
436 /**
437  * @brief Retrieves host state properties over dbus
438  *
439  * @param[in] aResp     Shared pointer for completing asynchronous calls.
440  *
441  * @return None.
442  */
443 void getHostState(std::shared_ptr<AsyncResp> aResp)
444 {
445     BMCWEB_LOG_DEBUG << "Get host information.";
446     crow::connections::systemBus->async_method_call(
447         [aResp](const boost::system::error_code ec,
448                 const std::variant<std::string> &hostState) {
449             if (ec)
450             {
451                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
452                 messages::internalError(aResp->res);
453                 return;
454             }
455 
456             const std::string *s = std::get_if<std::string>(&hostState);
457             BMCWEB_LOG_DEBUG << "Host state: " << *s;
458             if (s != nullptr)
459             {
460                 // Verify Host State
461                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
462                 {
463                     aResp->res.jsonValue["PowerState"] = "On";
464                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
465                 }
466                 else
467                 {
468                     aResp->res.jsonValue["PowerState"] = "Off";
469                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
470                 }
471             }
472         },
473         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
474         "org.freedesktop.DBus.Properties", "Get",
475         "xyz.openbmc_project.State.Host", "CurrentHostState");
476 }
477 
478 /**
479  * @brief Traslates boot source DBUS property value to redfish.
480  *
481  * @param[in] dbusSource    The boot source in DBUS speak.
482  *
483  * @return Returns as a string, the boot source in Redfish terms. If translation
484  * cannot be done, returns an empty string.
485  */
486 static std::string dbusToRfBootSource(const std::string &dbusSource)
487 {
488     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
489     {
490         return "None";
491     }
492     else if (dbusSource ==
493              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
494     {
495         return "Hdd";
496     }
497     else if (dbusSource ==
498              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
499     {
500         return "Cd";
501     }
502     else if (dbusSource ==
503              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
504     {
505         return "Pxe";
506     }
507     else if (dbusSource ==
508              "xyz.openbmc_project.Control.Boot.Source.Sources.Removable")
509     {
510         return "Usb";
511     }
512     else
513     {
514         return "";
515     }
516 }
517 
518 /**
519  * @brief Traslates boot mode DBUS property value to redfish.
520  *
521  * @param[in] dbusMode    The boot mode in DBUS speak.
522  *
523  * @return Returns as a string, the boot mode in Redfish terms. If translation
524  * cannot be done, returns an empty string.
525  */
526 static std::string dbusToRfBootMode(const std::string &dbusMode)
527 {
528     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
529     {
530         return "None";
531     }
532     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
533     {
534         return "Diags";
535     }
536     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
537     {
538         return "BiosSetup";
539     }
540     else
541     {
542         return "";
543     }
544 }
545 
546 /**
547  * @brief Traslates boot source from Redfish to DBUS property value.
548  *
549  * @param[in] rfSource    The boot source in Redfish.
550  *
551  * @return Returns as a string, the boot source as expected by DBUS.
552  * If translation cannot be done, returns an empty string.
553  */
554 static std::string rfToDbusBootSource(const std::string &rfSource)
555 {
556     if (rfSource == "None")
557     {
558         return "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
559     }
560     else if (rfSource == "Hdd")
561     {
562         return "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
563     }
564     else if (rfSource == "Cd")
565     {
566         return "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
567     }
568     else if (rfSource == "Pxe")
569     {
570         return "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
571     }
572     else if (rfSource == "Usb")
573     {
574         return "xyz.openbmc_project.Control.Boot.Source.Sources.Removable";
575     }
576     else
577     {
578         return "";
579     }
580 }
581 
582 /**
583  * @brief Traslates boot mode from Redfish to DBUS property value.
584  *
585  * @param[in] rfMode    The boot mode in Redfish.
586  *
587  * @return Returns as a string, the boot mode as expected by DBUS.
588  * If translation cannot be done, returns an empty string.
589  */
590 static std::string rfToDbusBootMode(const std::string &rfMode)
591 {
592     if (rfMode == "None")
593     {
594         return "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
595     }
596     else if (rfMode == "Diags")
597     {
598         return "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
599     }
600     else if (rfMode == "BiosSetup")
601     {
602         return "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
603     }
604     else
605     {
606         return "";
607     }
608 }
609 
610 /**
611  * @brief Retrieves boot mode over DBUS and fills out the response
612  *
613  * @param[in] aResp         Shared pointer for generating response message.
614  * @param[in] bootDbusObj   The dbus object to query for boot properties.
615  *
616  * @return None.
617  */
618 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
619                         std::string bootDbusObj)
620 {
621     crow::connections::systemBus->async_method_call(
622         [aResp](const boost::system::error_code ec,
623                 const std::variant<std::string> &bootMode) {
624             if (ec)
625             {
626                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
627                 messages::internalError(aResp->res);
628                 return;
629             }
630 
631             const std::string *bootModeStr =
632                 std::get_if<std::string>(&bootMode);
633 
634             if (!bootModeStr)
635             {
636                 messages::internalError(aResp->res);
637                 return;
638             }
639 
640             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
641 
642             // TODO (Santosh): Do we need to support override mode?
643             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
644             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
645                                          "AllowableValues"] = {
646                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup"};
647 
648             if (*bootModeStr !=
649                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
650             {
651                 auto rfMode = dbusToRfBootMode(*bootModeStr);
652                 if (!rfMode.empty())
653                 {
654                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
655                         rfMode;
656                 }
657             }
658 
659             // If the BootSourceOverrideTarget is still "None" at the end,
660             // reset the BootSourceOverrideEnabled to indicate that
661             // overrides are disabled
662             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
663                 "None")
664             {
665                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
666                     "Disabled";
667             }
668         },
669         "xyz.openbmc_project.Settings", bootDbusObj,
670         "org.freedesktop.DBus.Properties", "Get",
671         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
672 }
673 
674 /**
675  * @brief Retrieves boot source over DBUS
676  *
677  * @param[in] aResp         Shared pointer for generating response message.
678  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
679  *
680  * @return None.
681  */
682 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
683 {
684     std::string bootDbusObj =
685         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
686                        : "/xyz/openbmc_project/control/host0/boot";
687 
688     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
689     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
690         (oneTimeEnabled) ? "Once" : "Continuous";
691 
692     crow::connections::systemBus->async_method_call(
693         [aResp, bootDbusObj](const boost::system::error_code ec,
694                              const std::variant<std::string> &bootSource) {
695             if (ec)
696             {
697                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
698                 messages::internalError(aResp->res);
699                 return;
700             }
701 
702             const std::string *bootSourceStr =
703                 std::get_if<std::string>(&bootSource);
704 
705             if (!bootSourceStr)
706             {
707                 messages::internalError(aResp->res);
708                 return;
709             }
710             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
711 
712             auto rfSource = dbusToRfBootSource(*bootSourceStr);
713             if (!rfSource.empty())
714             {
715                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
716                     rfSource;
717             }
718         },
719         "xyz.openbmc_project.Settings", bootDbusObj,
720         "org.freedesktop.DBus.Properties", "Get",
721         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
722     getBootMode(std::move(aResp), std::move(bootDbusObj));
723 }
724 
725 /**
726  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
727  * get boot source and boot mode.
728  *
729  * @param[in] aResp     Shared pointer for generating response message.
730  *
731  * @return None.
732  */
733 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
734 {
735     BMCWEB_LOG_DEBUG << "Get boot information.";
736 
737     crow::connections::systemBus->async_method_call(
738         [aResp](const boost::system::error_code ec,
739                 const sdbusplus::message::variant<bool> &oneTime) {
740             if (ec)
741             {
742                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
743                 messages::internalError(aResp->res);
744                 return;
745             }
746 
747             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
748 
749             if (!oneTimePtr)
750             {
751                 messages::internalError(aResp->res);
752                 return;
753             }
754             getBootSource(aResp, *oneTimePtr);
755         },
756         "xyz.openbmc_project.Settings",
757         "/xyz/openbmc_project/control/host0/boot/one_time",
758         "org.freedesktop.DBus.Properties", "Get",
759         "xyz.openbmc_project.Object.Enable", "Enabled");
760 }
761 
762 /**
763  * @brief Sets boot properties into DBUS object(s).
764  *
765  * @param[in] aResp           Shared pointer for generating response message.
766  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
767  * @param[in] bootSource      The boot source to set.
768  * @param[in] bootEnable      The source override "enable" to set.
769  *
770  * @return None.
771  */
772 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
773                                 bool oneTimeEnabled,
774                                 std::optional<std::string> bootSource,
775                                 std::optional<std::string> bootEnable)
776 {
777     if (bootEnable && (bootEnable != "Once") && (bootEnable != "Continuous") &&
778         (bootEnable != "Disabled"))
779     {
780         BMCWEB_LOG_DEBUG << "Unsupported value for BootSourceOverrideEnabled: "
781                          << *bootEnable;
782         messages::propertyValueNotInList(aResp->res, *bootEnable,
783                                          "BootSourceOverrideEnabled");
784         return;
785     }
786 
787     bool oneTimeSetting = oneTimeEnabled;
788     // Validate incoming parameters
789     if (bootEnable)
790     {
791         if (*bootEnable == "Once")
792         {
793             oneTimeSetting = true;
794         }
795         else if (*bootEnable == "Continuous")
796         {
797             oneTimeSetting = false;
798         }
799         else if (*bootEnable == "Disabled")
800         {
801             oneTimeSetting = false;
802         }
803         else
804         {
805 
806             BMCWEB_LOG_DEBUG << "Unsupported value for "
807                                 "BootSourceOverrideEnabled: "
808                              << *bootEnable;
809             messages::propertyValueNotInList(aResp->res, *bootEnable,
810                                              "BootSourceOverrideEnabled");
811             return;
812         }
813     }
814     std::string bootSourceStr;
815     std::string bootModeStr;
816     if (bootSource)
817     {
818         bootSourceStr = rfToDbusBootSource(*bootSource);
819         bootModeStr = rfToDbusBootMode(*bootSource);
820 
821         BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
822         BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
823 
824         if (bootSourceStr.empty() && bootModeStr.empty())
825         {
826             BMCWEB_LOG_DEBUG << "Invalid property value for "
827                                 "BootSourceOverrideTarget: "
828                              << *bootSource;
829             messages::propertyValueNotInList(aResp->res, *bootSource,
830                                              "BootSourceTargetOverride");
831             return;
832         }
833     }
834     const char *bootObj =
835         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
836                        : "/xyz/openbmc_project/control/host0/boot";
837     // Figure out what properties to set
838     if (bootEnable && (*bootEnable == "Disabled"))
839     {
840         BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
841         // Request to only turn OFF/ON enabled, if turning enabled OFF, need
842         // to reset the source and mode too. If turning it ON, we only need
843         // to set the enabled property
844         bootSourceStr =
845             "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
846         bootModeStr = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
847     }
848     else if (bootSource)
849     {
850         // Source target specified
851         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
852         // Figure out which DBUS interface and property to use
853         bootSourceStr = rfToDbusBootSource(*bootSource);
854         bootModeStr = rfToDbusBootMode(*bootSource);
855 
856         BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
857         BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
858 
859         if (bootSourceStr.empty() && bootModeStr.empty())
860         {
861             BMCWEB_LOG_DEBUG << "Invalid property value for "
862                                 "BootSourceOverrideTarget: "
863                              << *bootSource;
864             messages::propertyValueNotInList(aResp->res, *bootSource,
865                                              "BootSourceTargetOverride");
866             return;
867         }
868 
869         if (!bootSourceStr.empty())
870         {
871             // If setting to anything other than default, also reset boot
872             // mode property
873             if (bootSourceStr !=
874                 "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
875             {
876                 bootModeStr =
877                     "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
878             }
879         }
880         else // if (!bootModeStr.empty())
881         {
882             // If setting to anything other than default, also reset boot
883             // source property
884             if (bootModeStr !=
885                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
886             {
887                 bootSourceStr =
888                     "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
889             }
890         }
891     }
892     if (!bootSourceStr.empty())
893     {
894         crow::connections::systemBus->async_method_call(
895             [aResp](const boost::system::error_code ec) {
896                 if (ec)
897                 {
898                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
899                     messages::internalError(aResp->res);
900                     return;
901                 }
902                 BMCWEB_LOG_DEBUG << "Boot source update done.";
903             },
904             "xyz.openbmc_project.Settings", bootObj,
905             "org.freedesktop.DBus.Properties", "Set",
906             "xyz.openbmc_project.Control.Boot.Source", "BootSource",
907             std::variant<std::string>(bootSourceStr));
908     }
909     if (!bootModeStr.empty())
910     {
911         crow::connections::systemBus->async_method_call(
912             [aResp](const boost::system::error_code ec) {
913                 if (ec)
914                 {
915                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
916                     messages::internalError(aResp->res);
917                     return;
918                 }
919                 BMCWEB_LOG_DEBUG << "Boot mode update done.";
920             },
921             "xyz.openbmc_project.Settings", bootObj,
922             "org.freedesktop.DBus.Properties", "Set",
923             "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
924             std::variant<std::string>(bootModeStr));
925     }
926     crow::connections::systemBus->async_method_call(
927         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
928             if (ec)
929             {
930                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
931                 messages::internalError(aResp->res);
932                 return;
933             }
934             BMCWEB_LOG_DEBUG << "Boot enable update done.";
935         },
936         "xyz.openbmc_project.Settings",
937         "/xyz/openbmc_project/control/host0/boot/one_time",
938         "org.freedesktop.DBus.Properties", "Set",
939         "xyz.openbmc_project.Object.Enable", "Enabled",
940         std::variant<bool>(oneTimeSetting));
941 }
942 
943 /**
944  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
945  * set boot source/boot mode properties.
946  *
947  * @param[in] aResp      Shared pointer for generating response message.
948  * @param[in] bootSource The boot source from incoming RF request.
949  * @param[in] bootEnable The boot override enable from incoming RF request.
950  *
951  * @return None.
952  */
953 static void setBootProperties(std::shared_ptr<AsyncResp> aResp,
954                               std::optional<std::string> bootSource,
955                               std::optional<std::string> bootEnable)
956 {
957     BMCWEB_LOG_DEBUG << "Set boot information.";
958 
959     crow::connections::systemBus->async_method_call(
960         [aResp{std::move(aResp)}, bootSource{std::move(bootSource)},
961          bootEnable{std::move(bootEnable)}](
962             const boost::system::error_code ec,
963             const sdbusplus::message::variant<bool> &oneTime) {
964             if (ec)
965             {
966                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
967                 messages::internalError(aResp->res);
968                 return;
969             }
970 
971             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
972 
973             if (!oneTimePtr)
974             {
975                 messages::internalError(aResp->res);
976                 return;
977             }
978 
979             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
980 
981             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
982                                 std::move(bootEnable));
983         },
984         "xyz.openbmc_project.Settings",
985         "/xyz/openbmc_project/control/host0/boot/one_time",
986         "org.freedesktop.DBus.Properties", "Get",
987         "xyz.openbmc_project.Object.Enable", "Enabled");
988 }
989 
990 /**
991  * SystemsCollection derived class for delivering ComputerSystems Collection
992  * Schema
993  */
994 class SystemsCollection : public Node
995 {
996   public:
997     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
998     {
999         entityPrivileges = {
1000             {boost::beast::http::verb::get, {{"Login"}}},
1001             {boost::beast::http::verb::head, {{"Login"}}},
1002             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1003             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1004             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1005             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1006     }
1007 
1008   private:
1009     void doGet(crow::Response &res, const crow::Request &req,
1010                const std::vector<std::string> &params) override
1011     {
1012         res.jsonValue["@odata.type"] =
1013             "#ComputerSystemCollection.ComputerSystemCollection";
1014         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1015         res.jsonValue["@odata.context"] =
1016             "/redfish/v1/"
1017             "$metadata#ComputerSystemCollection.ComputerSystemCollection";
1018         res.jsonValue["Name"] = "Computer System Collection";
1019         res.jsonValue["Members"] = {
1020             {{"@odata.id", "/redfish/v1/Systems/system"}}};
1021         res.jsonValue["Members@odata.count"] = 1;
1022         res.end();
1023     }
1024 };
1025 
1026 /**
1027  * SystemActionsReset class supports handle POST method for Reset action.
1028  * The class retrieves and sends data directly to D-Bus.
1029  */
1030 class SystemActionsReset : public Node
1031 {
1032   public:
1033     SystemActionsReset(CrowApp &app) :
1034         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1035     {
1036         entityPrivileges = {
1037             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1038     }
1039 
1040   private:
1041     /**
1042      * Function handles POST method request.
1043      * Analyzes POST body message before sends Reset request data to D-Bus.
1044      */
1045     void doPost(crow::Response &res, const crow::Request &req,
1046                 const std::vector<std::string> &params) override
1047     {
1048         auto asyncResp = std::make_shared<AsyncResp>(res);
1049 
1050         std::string resetType;
1051         if (!json_util::readJson(req, res, "ResetType", resetType))
1052         {
1053             return;
1054         }
1055 
1056         // Get the command and host vs. chassis
1057         std::string command;
1058         bool hostCommand;
1059         if (resetType == "On")
1060         {
1061             command = "xyz.openbmc_project.State.Host.Transition.On";
1062             hostCommand = true;
1063         }
1064         else if (resetType == "ForceOff")
1065         {
1066             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1067             hostCommand = false;
1068         }
1069         else if (resetType == "ForceOn")
1070         {
1071             command = "xyz.openbmc_project.State.Host.Transition.On";
1072             hostCommand = true;
1073         }
1074         else if (resetType == "ForceRestart")
1075         {
1076             command = "xyz.openbmc_project.State.Chassis.Transition.Reset";
1077             hostCommand = false;
1078         }
1079         else if (resetType == "GracefulShutdown")
1080         {
1081             command = "xyz.openbmc_project.State.Host.Transition.Off";
1082             hostCommand = true;
1083         }
1084         else if (resetType == "GracefulRestart")
1085         {
1086             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1087             hostCommand = true;
1088         }
1089         else if (resetType == "PowerCycle")
1090         {
1091             command = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
1092             hostCommand = false;
1093         }
1094         else if (resetType == "Nmi")
1095         {
1096             doNMI(asyncResp);
1097             return;
1098         }
1099         else
1100         {
1101             messages::actionParameterUnknown(res, "Reset", resetType);
1102             return;
1103         }
1104 
1105         if (hostCommand)
1106         {
1107             crow::connections::systemBus->async_method_call(
1108                 [asyncResp, resetType](const boost::system::error_code ec) {
1109                     if (ec)
1110                     {
1111                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1112                         if (ec.value() == boost::asio::error::invalid_argument)
1113                         {
1114                             messages::actionParameterNotSupported(
1115                                 asyncResp->res, resetType, "Reset");
1116                         }
1117                         else
1118                         {
1119                             messages::internalError(asyncResp->res);
1120                         }
1121                         return;
1122                     }
1123                     messages::success(asyncResp->res);
1124                 },
1125                 "xyz.openbmc_project.State.Host",
1126                 "/xyz/openbmc_project/state/host0",
1127                 "org.freedesktop.DBus.Properties", "Set",
1128                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1129                 std::variant<std::string>{command});
1130         }
1131         else
1132         {
1133             crow::connections::systemBus->async_method_call(
1134                 [asyncResp, resetType](const boost::system::error_code ec) {
1135                     if (ec)
1136                     {
1137                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1138                         if (ec.value() == boost::asio::error::invalid_argument)
1139                         {
1140                             messages::actionParameterNotSupported(
1141                                 asyncResp->res, resetType, "Reset");
1142                         }
1143                         else
1144                         {
1145                             messages::internalError(asyncResp->res);
1146                         }
1147                         return;
1148                     }
1149                     messages::success(asyncResp->res);
1150                 },
1151                 "xyz.openbmc_project.State.Chassis",
1152                 "/xyz/openbmc_project/state/chassis0",
1153                 "org.freedesktop.DBus.Properties", "Set",
1154                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1155                 std::variant<std::string>{command});
1156         }
1157     }
1158     /**
1159      * Function transceives data with dbus directly.
1160      */
1161     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1162     {
1163         constexpr char const *serviceName =
1164             "xyz.openbmc_project.Control.Host.NMI";
1165         constexpr char const *objectPath =
1166             "/xyz/openbmc_project/control/host0/nmi";
1167         constexpr char const *interfaceName =
1168             "xyz.openbmc_project.Control.Host.NMI";
1169         constexpr char const *method = "NMI";
1170 
1171         crow::connections::systemBus->async_method_call(
1172             [asyncResp](const boost::system::error_code ec) {
1173                 if (ec)
1174                 {
1175                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1176                     messages::internalError(asyncResp->res);
1177                     return;
1178                 }
1179                 messages::success(asyncResp->res);
1180             },
1181             serviceName, objectPath, interfaceName, method);
1182     }
1183 };
1184 
1185 /**
1186  * Systems derived class for delivering Computer Systems Schema.
1187  */
1188 class Systems : public Node
1189 {
1190   public:
1191     /*
1192      * Default Constructor
1193      */
1194     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1195     {
1196         entityPrivileges = {
1197             {boost::beast::http::verb::get, {{"Login"}}},
1198             {boost::beast::http::verb::head, {{"Login"}}},
1199             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1200             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1201             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1202             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1203     }
1204 
1205   private:
1206     /**
1207      * Functions triggers appropriate requests on DBus
1208      */
1209     void doGet(crow::Response &res, const crow::Request &req,
1210                const std::vector<std::string> &params) override
1211     {
1212         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1213         res.jsonValue["@odata.context"] =
1214             "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
1215         res.jsonValue["Name"] = "Computer System";
1216         res.jsonValue["Id"] = "system";
1217         res.jsonValue["SystemType"] = "Physical";
1218         res.jsonValue["Description"] = "Computer System";
1219         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1220         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1221         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
1222         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1223         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1224 
1225         res.jsonValue["Processors"] = {
1226             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1227         res.jsonValue["Memory"] = {
1228             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1229 
1230         // TODO Need to support ForceRestart.
1231         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1232             {"target",
1233              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1234             {"ResetType@Redfish.AllowableValues",
1235              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1236               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1237 
1238         res.jsonValue["LogServices"] = {
1239             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1240 
1241         res.jsonValue["Links"]["ManagedBy"] = {
1242             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1243 
1244         res.jsonValue["Status"] = {
1245             {"Health", "OK"},
1246             {"State", "Enabled"},
1247         };
1248         auto asyncResp = std::make_shared<AsyncResp>(res);
1249 
1250         constexpr const std::array<const char *, 2> inventoryForSystems = {
1251             "xyz.openbmc_project.Inventory.Item.Dimm",
1252             "xyz.openbmc_project.Inventory.Item.Cpu"};
1253 
1254         auto health = std::make_shared<HealthPopulate>(asyncResp);
1255         crow::connections::systemBus->async_method_call(
1256             [health](const boost::system::error_code ec,
1257                      std::vector<std::string> &resp) {
1258                 if (ec)
1259                 {
1260                     // no inventory
1261                     return;
1262                 }
1263 
1264                 health->inventory = std::move(resp);
1265             },
1266             "xyz.openbmc_project.ObjectMapper",
1267             "/xyz/openbmc_project/object_mapper",
1268             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1269             int32_t(0), inventoryForSystems);
1270 
1271         health->populate();
1272 
1273         getMainChassisId(asyncResp, [](const std::string &chassisId,
1274                                        std::shared_ptr<AsyncResp> aRsp) {
1275             aRsp->res.jsonValue["Links"]["Chassis"] = {
1276                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1277         });
1278         getLedGroupIdentify(
1279             asyncResp,
1280             [](const bool &asserted, const std::shared_ptr<AsyncResp> aRsp) {
1281                 if (asserted)
1282                 {
1283                     // If led group is asserted, then another call is needed to
1284                     // get led status
1285                     getLedIdentify(
1286                         aRsp, [](const std::string &ledStatus,
1287                                  const std::shared_ptr<AsyncResp> aRsp) {
1288                             if (!ledStatus.empty())
1289                             {
1290                                 aRsp->res.jsonValue["IndicatorLED"] = ledStatus;
1291                             }
1292                         });
1293                 }
1294                 else
1295                 {
1296                     aRsp->res.jsonValue["IndicatorLED"] = "Off";
1297                 }
1298             });
1299         getComputerSystem(asyncResp);
1300         getHostState(asyncResp);
1301         getBootProperties(asyncResp);
1302         getPCIeDeviceList(asyncResp);
1303     }
1304 
1305     void doPatch(crow::Response &res, const crow::Request &req,
1306                  const std::vector<std::string> &params) override
1307     {
1308         std::optional<std::string> indicatorLed;
1309         std::optional<nlohmann::json> bootProps;
1310         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1311                                  bootProps))
1312         {
1313             return;
1314         }
1315 
1316         auto asyncResp = std::make_shared<AsyncResp>(res);
1317         asyncResp->res.result(boost::beast::http::status::no_content);
1318 
1319         if (bootProps)
1320         {
1321             std::optional<std::string> bootSource;
1322             std::optional<std::string> bootEnable;
1323 
1324             if (!json_util::readJson(*bootProps, asyncResp->res,
1325                                      "BootSourceOverrideTarget", bootSource,
1326                                      "BootSourceOverrideEnabled", bootEnable))
1327             {
1328                 return;
1329             }
1330             setBootProperties(asyncResp, std::move(bootSource),
1331                               std::move(bootEnable));
1332         }
1333         if (indicatorLed)
1334         {
1335             std::string dbusLedState;
1336             if (*indicatorLed == "Lit")
1337             {
1338                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On";
1339             }
1340             else if (*indicatorLed == "Blinking")
1341             {
1342                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink";
1343             }
1344             else if (*indicatorLed == "Off")
1345             {
1346                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off";
1347             }
1348             else
1349             {
1350                 messages::propertyValueNotInList(res, *indicatorLed,
1351                                                  "IndicatorLED");
1352                 return;
1353             }
1354 
1355             // Update led group
1356             BMCWEB_LOG_DEBUG << "Update led group.";
1357             crow::connections::systemBus->async_method_call(
1358                 [asyncResp](const boost::system::error_code ec) {
1359                     if (ec)
1360                     {
1361                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1362                         messages::internalError(asyncResp->res);
1363                         return;
1364                     }
1365                     BMCWEB_LOG_DEBUG << "Led group update done.";
1366                 },
1367                 "xyz.openbmc_project.LED.GroupManager",
1368                 "/xyz/openbmc_project/led/groups/enclosure_identify",
1369                 "org.freedesktop.DBus.Properties", "Set",
1370                 "xyz.openbmc_project.Led.Group", "Asserted",
1371                 std::variant<bool>(
1372                     (dbusLedState ==
1373                              "xyz.openbmc_project.Led.Physical.Action.Off"
1374                          ? false
1375                          : true)));
1376             // Update identify led status
1377             BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
1378             crow::connections::systemBus->async_method_call(
1379                 [asyncResp{std::move(asyncResp)},
1380                  indicatorLed{std::move(*indicatorLed)}](
1381                     const boost::system::error_code ec) {
1382                     if (ec)
1383                     {
1384                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1385                         messages::internalError(asyncResp->res);
1386                         return;
1387                     }
1388                     BMCWEB_LOG_DEBUG << "Led state update done.";
1389                 },
1390                 "xyz.openbmc_project.LED.Controller.identify",
1391                 "/xyz/openbmc_project/led/physical/identify",
1392                 "org.freedesktop.DBus.Properties", "Set",
1393                 "xyz.openbmc_project.Led.Physical", "State",
1394                 std::variant<std::string>(dbusLedState));
1395         }
1396     }
1397 };
1398 } // namespace redfish
1399