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