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