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