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