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