xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision cb103130)
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.RemovableMedia")
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 the DBus boot paths.
767  *
768  * @param[in] rfSource    The boot source in Redfish.
769  * @param[out] bootSource The DBus source
770  * @param[out] bootMode   the DBus boot mode
771  *
772  * @return Integer error code.
773  */
774 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
775                                 const std::string &rfSource,
776                                 std::string &bootSource, std::string &bootMode)
777 {
778     // The caller has initialized the bootSource and bootMode to:
779     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
780     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
781     // Only modify the bootSource/bootMode variable needed to achieve the
782     // desired boot action.
783 
784     if (rfSource == "None")
785     {
786         return 0;
787     }
788     else if (rfSource == "Pxe")
789     {
790         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
791     }
792     else if (rfSource == "Hdd")
793     {
794         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
795     }
796     else if (rfSource == "Diags")
797     {
798         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
799     }
800     else if (rfSource == "Cd")
801     {
802         bootSource =
803             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
804     }
805     else if (rfSource == "BiosSetup")
806     {
807         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
808     }
809     else if (rfSource == "Usb")
810     {
811         bootSource =
812             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
813     }
814     else
815     {
816         BMCWEB_LOG_DEBUG << "Invalid property value for "
817                             "BootSourceOverrideTarget: "
818                          << bootSource;
819         messages::propertyValueNotInList(aResp->res, rfSource,
820                                          "BootSourceTargetOverride");
821         return -1;
822     }
823     return 0;
824 }
825 
826 /**
827  * @brief Retrieves boot mode over DBUS and fills out the response
828  *
829  * @param[in] aResp         Shared pointer for generating response message.
830  * @param[in] bootDbusObj   The dbus object to query for boot properties.
831  *
832  * @return None.
833  */
834 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
835                         std::string bootDbusObj)
836 {
837     crow::connections::systemBus->async_method_call(
838         [aResp](const boost::system::error_code ec,
839                 const std::variant<std::string> &bootMode) {
840             if (ec)
841             {
842                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
843                 messages::internalError(aResp->res);
844                 return;
845             }
846 
847             const std::string *bootModeStr =
848                 std::get_if<std::string>(&bootMode);
849 
850             if (!bootModeStr)
851             {
852                 messages::internalError(aResp->res);
853                 return;
854             }
855 
856             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
857 
858             // TODO (Santosh): Do we need to support override mode?
859             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
860             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
861                                          "AllowableValues"] = {
862                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
863 
864             if (*bootModeStr !=
865                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
866             {
867                 auto rfMode = dbusToRfBootMode(*bootModeStr);
868                 if (!rfMode.empty())
869                 {
870                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
871                         rfMode;
872                 }
873             }
874 
875             // If the BootSourceOverrideTarget is still "None" at the end,
876             // reset the BootSourceOverrideEnabled to indicate that
877             // overrides are disabled
878             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
879                 "None")
880             {
881                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
882                     "Disabled";
883             }
884         },
885         "xyz.openbmc_project.Settings", bootDbusObj,
886         "org.freedesktop.DBus.Properties", "Get",
887         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
888 }
889 
890 /**
891  * @brief Retrieves boot source over DBUS
892  *
893  * @param[in] aResp         Shared pointer for generating response message.
894  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
895  *
896  * @return None.
897  */
898 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
899 {
900     std::string bootDbusObj =
901         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
902                        : "/xyz/openbmc_project/control/host0/boot";
903 
904     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
905     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
906         (oneTimeEnabled) ? "Once" : "Continuous";
907 
908     crow::connections::systemBus->async_method_call(
909         [aResp, bootDbusObj](const boost::system::error_code ec,
910                              const std::variant<std::string> &bootSource) {
911             if (ec)
912             {
913                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
914                 messages::internalError(aResp->res);
915                 return;
916             }
917 
918             const std::string *bootSourceStr =
919                 std::get_if<std::string>(&bootSource);
920 
921             if (!bootSourceStr)
922             {
923                 messages::internalError(aResp->res);
924                 return;
925             }
926             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
927 
928             auto rfSource = dbusToRfBootSource(*bootSourceStr);
929             if (!rfSource.empty())
930             {
931                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
932                     rfSource;
933             }
934         },
935         "xyz.openbmc_project.Settings", bootDbusObj,
936         "org.freedesktop.DBus.Properties", "Get",
937         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
938     getBootMode(std::move(aResp), std::move(bootDbusObj));
939 }
940 
941 /**
942  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
943  * get boot source and boot mode.
944  *
945  * @param[in] aResp     Shared pointer for generating response message.
946  *
947  * @return None.
948  */
949 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
950 {
951     BMCWEB_LOG_DEBUG << "Get boot information.";
952 
953     crow::connections::systemBus->async_method_call(
954         [aResp](const boost::system::error_code ec,
955                 const sdbusplus::message::variant<bool> &oneTime) {
956             if (ec)
957             {
958                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
959                 // not an error, don't have to have the interface
960                 return;
961             }
962 
963             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
964 
965             if (!oneTimePtr)
966             {
967                 messages::internalError(aResp->res);
968                 return;
969             }
970             getBootSource(aResp, *oneTimePtr);
971         },
972         "xyz.openbmc_project.Settings",
973         "/xyz/openbmc_project/control/host0/boot/one_time",
974         "org.freedesktop.DBus.Properties", "Get",
975         "xyz.openbmc_project.Object.Enable", "Enabled");
976 }
977 
978 /**
979  * @brief Sets boot properties into DBUS object(s).
980  *
981  * @param[in] aResp           Shared pointer for generating response message.
982  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
983  * @param[in] bootSource      The boot source to set.
984  * @param[in] bootEnable      The source override "enable" to set.
985  *
986  * @return Integer error code.
987  */
988 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
989                                 bool oneTimeEnabled,
990                                 std::optional<std::string> bootSource,
991                                 std::optional<std::string> bootEnable)
992 {
993     std::string bootSourceStr =
994         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
995     std::string bootModeStr =
996         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
997     bool oneTimeSetting = oneTimeEnabled;
998     bool useBootSource = true;
999 
1000     // Validate incoming parameters
1001     if (bootEnable)
1002     {
1003         if (*bootEnable == "Once")
1004         {
1005             oneTimeSetting = true;
1006         }
1007         else if (*bootEnable == "Continuous")
1008         {
1009             oneTimeSetting = false;
1010         }
1011         else if (*bootEnable == "Disabled")
1012         {
1013             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1014             oneTimeSetting = false;
1015             useBootSource = false;
1016         }
1017         else
1018         {
1019             BMCWEB_LOG_DEBUG << "Unsupported value for "
1020                                 "BootSourceOverrideEnabled: "
1021                              << *bootEnable;
1022             messages::propertyValueNotInList(aResp->res, *bootEnable,
1023                                              "BootSourceOverrideEnabled");
1024             return;
1025         }
1026     }
1027 
1028     if (bootSource && useBootSource)
1029     {
1030         // Source target specified
1031         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1032         // Figure out which DBUS interface and property to use
1033         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1034                                  bootModeStr))
1035         {
1036             BMCWEB_LOG_DEBUG
1037                 << "Invalid property value for BootSourceOverrideTarget: "
1038                 << *bootSource;
1039             messages::propertyValueNotInList(aResp->res, *bootSource,
1040                                              "BootSourceTargetOverride");
1041             return;
1042         }
1043     }
1044 
1045     // Act on validated parameters
1046     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1047     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1048     const char *bootObj =
1049         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1050                        : "/xyz/openbmc_project/control/host0/boot";
1051 
1052     crow::connections::systemBus->async_method_call(
1053         [aResp](const boost::system::error_code ec) {
1054             if (ec)
1055             {
1056                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1057                 messages::internalError(aResp->res);
1058                 return;
1059             }
1060             BMCWEB_LOG_DEBUG << "Boot source update done.";
1061         },
1062         "xyz.openbmc_project.Settings", bootObj,
1063         "org.freedesktop.DBus.Properties", "Set",
1064         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1065         std::variant<std::string>(bootSourceStr));
1066 
1067     crow::connections::systemBus->async_method_call(
1068         [aResp](const boost::system::error_code ec) {
1069             if (ec)
1070             {
1071                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1072                 messages::internalError(aResp->res);
1073                 return;
1074             }
1075             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1076         },
1077         "xyz.openbmc_project.Settings", bootObj,
1078         "org.freedesktop.DBus.Properties", "Set",
1079         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1080         std::variant<std::string>(bootModeStr));
1081 
1082     crow::connections::systemBus->async_method_call(
1083         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1084             if (ec)
1085             {
1086                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1087                 messages::internalError(aResp->res);
1088                 return;
1089             }
1090             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1091         },
1092         "xyz.openbmc_project.Settings",
1093         "/xyz/openbmc_project/control/host0/boot/one_time",
1094         "org.freedesktop.DBus.Properties", "Set",
1095         "xyz.openbmc_project.Object.Enable", "Enabled",
1096         std::variant<bool>(oneTimeSetting));
1097 }
1098 
1099 /**
1100  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1101  * set boot source/boot mode properties.
1102  *
1103  * @param[in] aResp      Shared pointer for generating response message.
1104  * @param[in] bootSource The boot source from incoming RF request.
1105  * @param[in] bootEnable The boot override enable from incoming RF request.
1106  *
1107  * @return Integer error code.
1108  */
1109 static void setBootProperties(std::shared_ptr<AsyncResp> aResp,
1110                               std::optional<std::string> bootSource,
1111                               std::optional<std::string> bootEnable)
1112 {
1113     BMCWEB_LOG_DEBUG << "Set boot information.";
1114 
1115     crow::connections::systemBus->async_method_call(
1116         [aResp, bootSource{std::move(bootSource)},
1117          bootEnable{std::move(bootEnable)}](
1118             const boost::system::error_code ec,
1119             const sdbusplus::message::variant<bool> &oneTime) {
1120             if (ec)
1121             {
1122                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1123                 messages::internalError(aResp->res);
1124                 return;
1125             }
1126 
1127             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1128 
1129             if (!oneTimePtr)
1130             {
1131                 messages::internalError(aResp->res);
1132                 return;
1133             }
1134 
1135             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1136 
1137             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1138                                 std::move(bootEnable));
1139         },
1140         "xyz.openbmc_project.Settings",
1141         "/xyz/openbmc_project/control/host0/boot/one_time",
1142         "org.freedesktop.DBus.Properties", "Get",
1143         "xyz.openbmc_project.Object.Enable", "Enabled");
1144 }
1145 
1146 /**
1147  * SystemsCollection derived class for delivering ComputerSystems Collection
1148  * Schema
1149  */
1150 class SystemsCollection : public Node
1151 {
1152   public:
1153     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1154     {
1155         entityPrivileges = {
1156             {boost::beast::http::verb::get, {{"Login"}}},
1157             {boost::beast::http::verb::head, {{"Login"}}},
1158             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1159             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1160             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1161             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1162     }
1163 
1164   private:
1165     void doGet(crow::Response &res, const crow::Request &req,
1166                const std::vector<std::string> &params) override
1167     {
1168         res.jsonValue["@odata.type"] =
1169             "#ComputerSystemCollection.ComputerSystemCollection";
1170         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1171         res.jsonValue["@odata.context"] =
1172             "/redfish/v1/"
1173             "$metadata#ComputerSystemCollection.ComputerSystemCollection";
1174         res.jsonValue["Name"] = "Computer System Collection";
1175         res.jsonValue["Members"] = {
1176             {{"@odata.id", "/redfish/v1/Systems/system"}}};
1177         res.jsonValue["Members@odata.count"] = 1;
1178         res.end();
1179     }
1180 };
1181 
1182 /**
1183  * SystemActionsReset class supports handle POST method for Reset action.
1184  * The class retrieves and sends data directly to D-Bus.
1185  */
1186 class SystemActionsReset : public Node
1187 {
1188   public:
1189     SystemActionsReset(CrowApp &app) :
1190         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1191     {
1192         entityPrivileges = {
1193             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1194     }
1195 
1196   private:
1197     /**
1198      * Function handles POST method request.
1199      * Analyzes POST body message before sends Reset request data to D-Bus.
1200      */
1201     void doPost(crow::Response &res, const crow::Request &req,
1202                 const std::vector<std::string> &params) override
1203     {
1204         auto asyncResp = std::make_shared<AsyncResp>(res);
1205 
1206         std::string resetType;
1207         if (!json_util::readJson(req, res, "ResetType", resetType))
1208         {
1209             return;
1210         }
1211 
1212         // Get the command and host vs. chassis
1213         std::string command;
1214         bool hostCommand;
1215         if (resetType == "On")
1216         {
1217             command = "xyz.openbmc_project.State.Host.Transition.On";
1218             hostCommand = true;
1219         }
1220         else if (resetType == "ForceOff")
1221         {
1222             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1223             hostCommand = false;
1224         }
1225         else if (resetType == "ForceOn")
1226         {
1227             command = "xyz.openbmc_project.State.Host.Transition.On";
1228             hostCommand = true;
1229         }
1230         else if (resetType == "ForceRestart")
1231         {
1232             command = "xyz.openbmc_project.State.Chassis.Transition.Reset";
1233             hostCommand = false;
1234         }
1235         else if (resetType == "GracefulShutdown")
1236         {
1237             command = "xyz.openbmc_project.State.Host.Transition.Off";
1238             hostCommand = true;
1239         }
1240         else if (resetType == "GracefulRestart")
1241         {
1242             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1243             hostCommand = true;
1244         }
1245         else if (resetType == "PowerCycle")
1246         {
1247             command = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
1248             hostCommand = false;
1249         }
1250         else if (resetType == "Nmi")
1251         {
1252             doNMI(asyncResp);
1253             return;
1254         }
1255         else
1256         {
1257             messages::actionParameterUnknown(res, "Reset", resetType);
1258             return;
1259         }
1260 
1261         if (hostCommand)
1262         {
1263             crow::connections::systemBus->async_method_call(
1264                 [asyncResp, resetType](const boost::system::error_code ec) {
1265                     if (ec)
1266                     {
1267                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1268                         if (ec.value() == boost::asio::error::invalid_argument)
1269                         {
1270                             messages::actionParameterNotSupported(
1271                                 asyncResp->res, resetType, "Reset");
1272                         }
1273                         else
1274                         {
1275                             messages::internalError(asyncResp->res);
1276                         }
1277                         return;
1278                     }
1279                     messages::success(asyncResp->res);
1280                 },
1281                 "xyz.openbmc_project.State.Host",
1282                 "/xyz/openbmc_project/state/host0",
1283                 "org.freedesktop.DBus.Properties", "Set",
1284                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1285                 std::variant<std::string>{command});
1286         }
1287         else
1288         {
1289             crow::connections::systemBus->async_method_call(
1290                 [asyncResp, resetType](const boost::system::error_code ec) {
1291                     if (ec)
1292                     {
1293                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1294                         if (ec.value() == boost::asio::error::invalid_argument)
1295                         {
1296                             messages::actionParameterNotSupported(
1297                                 asyncResp->res, resetType, "Reset");
1298                         }
1299                         else
1300                         {
1301                             messages::internalError(asyncResp->res);
1302                         }
1303                         return;
1304                     }
1305                     messages::success(asyncResp->res);
1306                 },
1307                 "xyz.openbmc_project.State.Chassis",
1308                 "/xyz/openbmc_project/state/chassis0",
1309                 "org.freedesktop.DBus.Properties", "Set",
1310                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1311                 std::variant<std::string>{command});
1312         }
1313     }
1314     /**
1315      * Function transceives data with dbus directly.
1316      */
1317     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1318     {
1319         constexpr char const *serviceName =
1320             "xyz.openbmc_project.Control.Host.NMI";
1321         constexpr char const *objectPath =
1322             "/xyz/openbmc_project/control/host0/nmi";
1323         constexpr char const *interfaceName =
1324             "xyz.openbmc_project.Control.Host.NMI";
1325         constexpr char const *method = "NMI";
1326 
1327         crow::connections::systemBus->async_method_call(
1328             [asyncResp](const boost::system::error_code ec) {
1329                 if (ec)
1330                 {
1331                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1332                     messages::internalError(asyncResp->res);
1333                     return;
1334                 }
1335                 messages::success(asyncResp->res);
1336             },
1337             serviceName, objectPath, interfaceName, method);
1338     }
1339 };
1340 
1341 /**
1342  * Systems derived class for delivering Computer Systems Schema.
1343  */
1344 class Systems : public Node
1345 {
1346   public:
1347     /*
1348      * Default Constructor
1349      */
1350     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1351     {
1352         entityPrivileges = {
1353             {boost::beast::http::verb::get, {{"Login"}}},
1354             {boost::beast::http::verb::head, {{"Login"}}},
1355             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1356             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1357             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1358             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1359     }
1360 
1361   private:
1362     /**
1363      * Functions triggers appropriate requests on DBus
1364      */
1365     void doGet(crow::Response &res, const crow::Request &req,
1366                const std::vector<std::string> &params) override
1367     {
1368         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1369         res.jsonValue["@odata.context"] =
1370             "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
1371         res.jsonValue["Name"] = "Computer System";
1372         res.jsonValue["Id"] = "system";
1373         res.jsonValue["SystemType"] = "Physical";
1374         res.jsonValue["Description"] = "Computer System";
1375         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1376         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1377         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
1378         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1379         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1380 
1381         res.jsonValue["Processors"] = {
1382             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1383         res.jsonValue["Memory"] = {
1384             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1385 
1386         // TODO Need to support ForceRestart.
1387         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1388             {"target",
1389              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1390             {"ResetType@Redfish.AllowableValues",
1391              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1392               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1393 
1394         res.jsonValue["LogServices"] = {
1395             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1396 
1397         res.jsonValue["Links"]["ManagedBy"] = {
1398             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1399 
1400         res.jsonValue["Status"] = {
1401             {"Health", "OK"},
1402             {"State", "Enabled"},
1403         };
1404         auto asyncResp = std::make_shared<AsyncResp>(res);
1405 
1406         constexpr const std::array<const char *, 2> inventoryForSystems = {
1407             "xyz.openbmc_project.Inventory.Item.Dimm",
1408             "xyz.openbmc_project.Inventory.Item.Cpu"};
1409 
1410         auto health = std::make_shared<HealthPopulate>(asyncResp);
1411         crow::connections::systemBus->async_method_call(
1412             [health](const boost::system::error_code ec,
1413                      std::vector<std::string> &resp) {
1414                 if (ec)
1415                 {
1416                     // no inventory
1417                     return;
1418                 }
1419 
1420                 health->inventory = std::move(resp);
1421             },
1422             "xyz.openbmc_project.ObjectMapper",
1423             "/xyz/openbmc_project/object_mapper",
1424             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1425             int32_t(0), inventoryForSystems);
1426 
1427         health->populate();
1428 
1429         getMainChassisId(asyncResp, [](const std::string &chassisId,
1430                                        std::shared_ptr<AsyncResp> aRsp) {
1431             aRsp->res.jsonValue["Links"]["Chassis"] = {
1432                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1433         });
1434         getLedGroupIdentify(
1435             asyncResp,
1436             [](const bool &asserted, const std::shared_ptr<AsyncResp> aRsp) {
1437                 if (asserted)
1438                 {
1439                     // If led group is asserted, then another call is needed to
1440                     // get led status
1441                     getLedIdentify(
1442                         aRsp, [](const std::string &ledStatus,
1443                                  const std::shared_ptr<AsyncResp> aRsp) {
1444                             if (!ledStatus.empty())
1445                             {
1446                                 aRsp->res.jsonValue["IndicatorLED"] = ledStatus;
1447                             }
1448                         });
1449                 }
1450                 else
1451                 {
1452                     aRsp->res.jsonValue["IndicatorLED"] = "Off";
1453                 }
1454             });
1455         getComputerSystem(asyncResp);
1456         getHostState(asyncResp);
1457         getBootProperties(asyncResp);
1458         getPCIeDeviceList(asyncResp);
1459     }
1460 
1461     void doPatch(crow::Response &res, const crow::Request &req,
1462                  const std::vector<std::string> &params) override
1463     {
1464         std::optional<std::string> indicatorLed;
1465         std::optional<nlohmann::json> bootProps;
1466         auto asyncResp = std::make_shared<AsyncResp>(res);
1467 
1468         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1469                                  bootProps))
1470         {
1471             return;
1472         }
1473 
1474         res.result(boost::beast::http::status::no_content);
1475         if (bootProps)
1476         {
1477             std::optional<std::string> bootSource;
1478             std::optional<std::string> bootEnable;
1479 
1480             if (!json_util::readJson(*bootProps, asyncResp->res,
1481                                      "BootSourceOverrideTarget", bootSource,
1482                                      "BootSourceOverrideEnabled", bootEnable))
1483             {
1484                 return;
1485             }
1486             setBootProperties(asyncResp, std::move(bootSource),
1487                               std::move(bootEnable));
1488         }
1489 
1490         if (indicatorLed)
1491         {
1492             std::string dbusLedState;
1493             if (*indicatorLed == "Lit")
1494             {
1495                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On";
1496             }
1497             else if (*indicatorLed == "Blinking")
1498             {
1499                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink";
1500             }
1501             else if (*indicatorLed == "Off")
1502             {
1503                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off";
1504             }
1505             else
1506             {
1507                 messages::propertyValueNotInList(res, *indicatorLed,
1508                                                  "IndicatorLED");
1509                 return;
1510             }
1511 
1512             // Update led group
1513             BMCWEB_LOG_DEBUG << "Update led group.";
1514             crow::connections::systemBus->async_method_call(
1515                 [asyncResp](const boost::system::error_code ec) {
1516                     if (ec)
1517                     {
1518                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1519                         messages::internalError(asyncResp->res);
1520                         return;
1521                     }
1522                     BMCWEB_LOG_DEBUG << "Led group update done.";
1523                 },
1524                 "xyz.openbmc_project.LED.GroupManager",
1525                 "/xyz/openbmc_project/led/groups/enclosure_identify",
1526                 "org.freedesktop.DBus.Properties", "Set",
1527                 "xyz.openbmc_project.Led.Group", "Asserted",
1528                 std::variant<bool>(
1529                     (dbusLedState !=
1530                      "xyz.openbmc_project.Led.Physical.Action.Off")));
1531 
1532             // Update identify led status
1533             BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
1534             crow::connections::systemBus->async_method_call(
1535                 [asyncResp](const boost::system::error_code ec) {
1536                     if (ec)
1537                     {
1538                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1539                         messages::internalError(asyncResp->res);
1540                         return;
1541                     }
1542                     BMCWEB_LOG_DEBUG << "Led state update done.";
1543                 },
1544                 "xyz.openbmc_project.LED.Controller.identify",
1545                 "/xyz/openbmc_project/led/physical/identify",
1546                 "org.freedesktop.DBus.Properties", "Set",
1547                 "xyz.openbmc_project.Led.Physical", "State",
1548                 std::variant<std::string>(dbusLedState));
1549         }
1550     }
1551 };
1552 } // namespace redfish
1553