xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision c45f00821add8cd29cbd148d4b4b9f6e988665cf)
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 template <typename CallbackFunc>
616 void getLedIdentify(std::shared_ptr<AsyncResp> aResp, CallbackFunc &&callback)
617 {
618     BMCWEB_LOG_DEBUG << "Get identify led properties";
619     crow::connections::systemBus->async_method_call(
620         [aResp,
621          callback{std::move(callback)}](const boost::system::error_code ec,
622                                         const PropertiesType &properties) {
623             if (ec)
624             {
625                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
626                 messages::internalError(aResp->res);
627                 return;
628             }
629             BMCWEB_LOG_DEBUG << "Got " << properties.size()
630                              << " led properties.";
631             std::string output;
632             for (const auto &property : properties)
633             {
634                 if (property.first == "State")
635                 {
636                     const std::string *s =
637                         std::get_if<std::string>(&property.second);
638                     if (nullptr != s)
639                     {
640                         BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
641                         const auto pos = s->rfind('.');
642                         if (pos != std::string::npos)
643                         {
644                             auto led = s->substr(pos + 1);
645                             for (const std::pair<const char *, const char *>
646                                      &p :
647                                  std::array<
648                                      std::pair<const char *, const char *>, 3>{
649                                      {{"On", "Lit"},
650                                       {"Blink", "Blinking"},
651                                       {"Off", "Off"}}})
652                             {
653                                 if (led == p.first)
654                                 {
655                                     output = p.second;
656                                 }
657                             }
658                         }
659                     }
660                 }
661             }
662             callback(output, aResp);
663         },
664         "xyz.openbmc_project.LED.Controller.identify",
665         "/xyz/openbmc_project/led/physical/identify",
666         "org.freedesktop.DBus.Properties", "GetAll",
667         "xyz.openbmc_project.Led.Physical");
668 }
669 /**
670  * @brief Retrieves host state properties over dbus
671  *
672  * @param[in] aResp     Shared pointer for completing asynchronous calls.
673  *
674  * @return None.
675  */
676 void getHostState(std::shared_ptr<AsyncResp> aResp)
677 {
678     BMCWEB_LOG_DEBUG << "Get host information.";
679     crow::connections::systemBus->async_method_call(
680         [aResp](const boost::system::error_code ec,
681                 const std::variant<std::string> &hostState) {
682             if (ec)
683             {
684                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
685                 messages::internalError(aResp->res);
686                 return;
687             }
688 
689             const std::string *s = std::get_if<std::string>(&hostState);
690             BMCWEB_LOG_DEBUG << "Host state: " << *s;
691             if (s != nullptr)
692             {
693                 // Verify Host State
694                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
695                 {
696                     aResp->res.jsonValue["PowerState"] = "On";
697                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
698                 }
699                 else
700                 {
701                     aResp->res.jsonValue["PowerState"] = "Off";
702                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
703                 }
704             }
705         },
706         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
707         "org.freedesktop.DBus.Properties", "Get",
708         "xyz.openbmc_project.State.Host", "CurrentHostState");
709 }
710 
711 /**
712  * @brief Traslates boot source DBUS property value to redfish.
713  *
714  * @param[in] dbusSource    The boot source in DBUS speak.
715  *
716  * @return Returns as a string, the boot source in Redfish terms. If translation
717  * cannot be done, returns an empty string.
718  */
719 static std::string dbusToRfBootSource(const std::string &dbusSource)
720 {
721     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
722     {
723         return "None";
724     }
725     else if (dbusSource ==
726              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
727     {
728         return "Hdd";
729     }
730     else if (dbusSource ==
731              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
732     {
733         return "Cd";
734     }
735     else if (dbusSource ==
736              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
737     {
738         return "Pxe";
739     }
740     else if (dbusSource ==
741              "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
742     {
743         return "Usb";
744     }
745     else
746     {
747         return "";
748     }
749 }
750 
751 /**
752  * @brief Traslates boot mode DBUS property value to redfish.
753  *
754  * @param[in] dbusMode    The boot mode in DBUS speak.
755  *
756  * @return Returns as a string, the boot mode in Redfish terms. If translation
757  * cannot be done, returns an empty string.
758  */
759 static std::string dbusToRfBootMode(const std::string &dbusMode)
760 {
761     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
762     {
763         return "None";
764     }
765     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
766     {
767         return "Diags";
768     }
769     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
770     {
771         return "BiosSetup";
772     }
773     else
774     {
775         return "";
776     }
777 }
778 
779 /**
780  * @brief Traslates boot source from Redfish to the DBus boot paths.
781  *
782  * @param[in] rfSource    The boot source in Redfish.
783  * @param[out] bootSource The DBus source
784  * @param[out] bootMode   the DBus boot mode
785  *
786  * @return Integer error code.
787  */
788 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
789                                 const std::string &rfSource,
790                                 std::string &bootSource, std::string &bootMode)
791 {
792     // The caller has initialized the bootSource and bootMode to:
793     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
794     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
795     // Only modify the bootSource/bootMode variable needed to achieve the
796     // desired boot action.
797 
798     if (rfSource == "None")
799     {
800         return 0;
801     }
802     else if (rfSource == "Pxe")
803     {
804         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
805     }
806     else if (rfSource == "Hdd")
807     {
808         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
809     }
810     else if (rfSource == "Diags")
811     {
812         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
813     }
814     else if (rfSource == "Cd")
815     {
816         bootSource =
817             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
818     }
819     else if (rfSource == "BiosSetup")
820     {
821         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
822     }
823     else if (rfSource == "Usb")
824     {
825         bootSource =
826             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
827     }
828     else
829     {
830         BMCWEB_LOG_DEBUG << "Invalid property value for "
831                             "BootSourceOverrideTarget: "
832                          << bootSource;
833         messages::propertyValueNotInList(aResp->res, rfSource,
834                                          "BootSourceTargetOverride");
835         return -1;
836     }
837     return 0;
838 }
839 
840 /**
841  * @brief Retrieves boot mode over DBUS and fills out the response
842  *
843  * @param[in] aResp         Shared pointer for generating response message.
844  * @param[in] bootDbusObj   The dbus object to query for boot properties.
845  *
846  * @return None.
847  */
848 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
849                         std::string bootDbusObj)
850 {
851     crow::connections::systemBus->async_method_call(
852         [aResp](const boost::system::error_code ec,
853                 const std::variant<std::string> &bootMode) {
854             if (ec)
855             {
856                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
857                 messages::internalError(aResp->res);
858                 return;
859             }
860 
861             const std::string *bootModeStr =
862                 std::get_if<std::string>(&bootMode);
863 
864             if (!bootModeStr)
865             {
866                 messages::internalError(aResp->res);
867                 return;
868             }
869 
870             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
871 
872             // TODO (Santosh): Do we need to support override mode?
873             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
874             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
875                                          "AllowableValues"] = {
876                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
877 
878             if (*bootModeStr !=
879                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
880             {
881                 auto rfMode = dbusToRfBootMode(*bootModeStr);
882                 if (!rfMode.empty())
883                 {
884                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
885                         rfMode;
886                 }
887             }
888 
889             // If the BootSourceOverrideTarget is still "None" at the end,
890             // reset the BootSourceOverrideEnabled to indicate that
891             // overrides are disabled
892             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
893                 "None")
894             {
895                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
896                     "Disabled";
897             }
898         },
899         "xyz.openbmc_project.Settings", bootDbusObj,
900         "org.freedesktop.DBus.Properties", "Get",
901         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
902 }
903 
904 /**
905  * @brief Retrieves boot source over DBUS
906  *
907  * @param[in] aResp         Shared pointer for generating response message.
908  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
909  *
910  * @return None.
911  */
912 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
913 {
914     std::string bootDbusObj =
915         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
916                        : "/xyz/openbmc_project/control/host0/boot";
917 
918     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
919     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
920         (oneTimeEnabled) ? "Once" : "Continuous";
921 
922     crow::connections::systemBus->async_method_call(
923         [aResp, bootDbusObj](const boost::system::error_code ec,
924                              const std::variant<std::string> &bootSource) {
925             if (ec)
926             {
927                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
928                 messages::internalError(aResp->res);
929                 return;
930             }
931 
932             const std::string *bootSourceStr =
933                 std::get_if<std::string>(&bootSource);
934 
935             if (!bootSourceStr)
936             {
937                 messages::internalError(aResp->res);
938                 return;
939             }
940             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
941 
942             auto rfSource = dbusToRfBootSource(*bootSourceStr);
943             if (!rfSource.empty())
944             {
945                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
946                     rfSource;
947             }
948         },
949         "xyz.openbmc_project.Settings", bootDbusObj,
950         "org.freedesktop.DBus.Properties", "Get",
951         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
952     getBootMode(std::move(aResp), std::move(bootDbusObj));
953 }
954 
955 /**
956  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
957  * get boot source and boot mode.
958  *
959  * @param[in] aResp     Shared pointer for generating response message.
960  *
961  * @return None.
962  */
963 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
964 {
965     BMCWEB_LOG_DEBUG << "Get boot information.";
966 
967     crow::connections::systemBus->async_method_call(
968         [aResp](const boost::system::error_code ec,
969                 const sdbusplus::message::variant<bool> &oneTime) {
970             if (ec)
971             {
972                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
973                 // not an error, don't have to have the interface
974                 return;
975             }
976 
977             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
978 
979             if (!oneTimePtr)
980             {
981                 messages::internalError(aResp->res);
982                 return;
983             }
984             getBootSource(aResp, *oneTimePtr);
985         },
986         "xyz.openbmc_project.Settings",
987         "/xyz/openbmc_project/control/host0/boot/one_time",
988         "org.freedesktop.DBus.Properties", "Get",
989         "xyz.openbmc_project.Object.Enable", "Enabled");
990 }
991 
992 /**
993  * @brief Sets boot properties into DBUS object(s).
994  *
995  * @param[in] aResp           Shared pointer for generating response message.
996  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
997  * @param[in] bootSource      The boot source to set.
998  * @param[in] bootEnable      The source override "enable" to set.
999  *
1000  * @return Integer error code.
1001  */
1002 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
1003                                 bool oneTimeEnabled,
1004                                 std::optional<std::string> bootSource,
1005                                 std::optional<std::string> bootEnable)
1006 {
1007     std::string bootSourceStr =
1008         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1009     std::string bootModeStr =
1010         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1011     bool oneTimeSetting = oneTimeEnabled;
1012     bool useBootSource = true;
1013 
1014     // Validate incoming parameters
1015     if (bootEnable)
1016     {
1017         if (*bootEnable == "Once")
1018         {
1019             oneTimeSetting = true;
1020         }
1021         else if (*bootEnable == "Continuous")
1022         {
1023             oneTimeSetting = false;
1024         }
1025         else if (*bootEnable == "Disabled")
1026         {
1027             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1028             oneTimeSetting = false;
1029             useBootSource = false;
1030         }
1031         else
1032         {
1033             BMCWEB_LOG_DEBUG << "Unsupported value for "
1034                                 "BootSourceOverrideEnabled: "
1035                              << *bootEnable;
1036             messages::propertyValueNotInList(aResp->res, *bootEnable,
1037                                              "BootSourceOverrideEnabled");
1038             return;
1039         }
1040     }
1041 
1042     if (bootSource && useBootSource)
1043     {
1044         // Source target specified
1045         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1046         // Figure out which DBUS interface and property to use
1047         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1048                                  bootModeStr))
1049         {
1050             BMCWEB_LOG_DEBUG
1051                 << "Invalid property value for BootSourceOverrideTarget: "
1052                 << *bootSource;
1053             messages::propertyValueNotInList(aResp->res, *bootSource,
1054                                              "BootSourceTargetOverride");
1055             return;
1056         }
1057     }
1058 
1059     // Act on validated parameters
1060     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1061     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1062     const char *bootObj =
1063         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1064                        : "/xyz/openbmc_project/control/host0/boot";
1065 
1066     crow::connections::systemBus->async_method_call(
1067         [aResp](const boost::system::error_code ec) {
1068             if (ec)
1069             {
1070                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1071                 messages::internalError(aResp->res);
1072                 return;
1073             }
1074             BMCWEB_LOG_DEBUG << "Boot source update done.";
1075         },
1076         "xyz.openbmc_project.Settings", bootObj,
1077         "org.freedesktop.DBus.Properties", "Set",
1078         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1079         std::variant<std::string>(bootSourceStr));
1080 
1081     crow::connections::systemBus->async_method_call(
1082         [aResp](const boost::system::error_code ec) {
1083             if (ec)
1084             {
1085                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1086                 messages::internalError(aResp->res);
1087                 return;
1088             }
1089             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1090         },
1091         "xyz.openbmc_project.Settings", bootObj,
1092         "org.freedesktop.DBus.Properties", "Set",
1093         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1094         std::variant<std::string>(bootModeStr));
1095 
1096     crow::connections::systemBus->async_method_call(
1097         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1098             if (ec)
1099             {
1100                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1101                 messages::internalError(aResp->res);
1102                 return;
1103             }
1104             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1105         },
1106         "xyz.openbmc_project.Settings",
1107         "/xyz/openbmc_project/control/host0/boot/one_time",
1108         "org.freedesktop.DBus.Properties", "Set",
1109         "xyz.openbmc_project.Object.Enable", "Enabled",
1110         std::variant<bool>(oneTimeSetting));
1111 }
1112 
1113 /**
1114  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1115  * set boot source/boot mode properties.
1116  *
1117  * @param[in] aResp      Shared pointer for generating response message.
1118  * @param[in] bootSource The boot source from incoming RF request.
1119  * @param[in] bootEnable The boot override enable from incoming RF request.
1120  *
1121  * @return Integer error code.
1122  */
1123 static void setBootProperties(std::shared_ptr<AsyncResp> aResp,
1124                               std::optional<std::string> bootSource,
1125                               std::optional<std::string> bootEnable)
1126 {
1127     BMCWEB_LOG_DEBUG << "Set boot information.";
1128 
1129     crow::connections::systemBus->async_method_call(
1130         [aResp, bootSource{std::move(bootSource)},
1131          bootEnable{std::move(bootEnable)}](
1132             const boost::system::error_code ec,
1133             const sdbusplus::message::variant<bool> &oneTime) {
1134             if (ec)
1135             {
1136                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1137                 messages::internalError(aResp->res);
1138                 return;
1139             }
1140 
1141             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1142 
1143             if (!oneTimePtr)
1144             {
1145                 messages::internalError(aResp->res);
1146                 return;
1147             }
1148 
1149             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1150 
1151             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1152                                 std::move(bootEnable));
1153         },
1154         "xyz.openbmc_project.Settings",
1155         "/xyz/openbmc_project/control/host0/boot/one_time",
1156         "org.freedesktop.DBus.Properties", "Get",
1157         "xyz.openbmc_project.Object.Enable", "Enabled");
1158 }
1159 
1160 /**
1161  * @brief Translates watchdog timeout action DBUS property value to redfish.
1162  *
1163  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1164  *
1165  * @return Returns as a string, the timeout action in Redfish terms. If
1166  * translation cannot be done, returns an empty string.
1167  */
1168 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1169 {
1170     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1171     {
1172         return "None";
1173     }
1174     else if (dbusAction ==
1175              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1176     {
1177         return "ResetSystem";
1178     }
1179     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1180     {
1181         return "PowerDown";
1182     }
1183     else if (dbusAction ==
1184              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1185     {
1186         return "PowerCycle";
1187     }
1188 
1189     return "";
1190 }
1191 
1192 /**
1193  *@brief Translates timeout action from Redfish to DBUS property value.
1194  *
1195  *@param[in] rfAction The timeout action in Redfish.
1196  *
1197  *@return Returns as a string, the time_out action as expected by DBUS.
1198  *If translation cannot be done, returns an empty string.
1199  */
1200 
1201 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction)
1202 {
1203     if (rfAction == "None")
1204     {
1205         return "xyz.openbmc_project.State.Watchdog.Action.None";
1206     }
1207     else if (rfAction == "PowerCycle")
1208     {
1209         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1210     }
1211     else if (rfAction == "PowerDown")
1212     {
1213         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1214     }
1215     else if (rfAction == "ResetSystem")
1216     {
1217         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1218     }
1219 
1220     return "";
1221 }
1222 
1223 /**
1224  * @brief Retrieves host watchdog timer properties over DBUS
1225  *
1226  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1227  *
1228  * @return None.
1229  */
1230 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1231 {
1232     BMCWEB_LOG_DEBUG << "Get host watchodg";
1233     crow::connections::systemBus->async_method_call(
1234         [aResp](const boost::system::error_code ec,
1235                 PropertiesType &properties) {
1236             if (ec)
1237             {
1238                 // watchdog service is stopped
1239                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1240                 return;
1241             }
1242 
1243             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1244 
1245             nlohmann::json &hostWatchdogTimer =
1246                 aResp->res.jsonValue["HostWatchdogTimer"];
1247 
1248             // watchdog service is running/enabled
1249             hostWatchdogTimer["Status"]["State"] = "Enabled";
1250 
1251             for (const auto &property : properties)
1252             {
1253                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1254                 if (property.first == "Enabled")
1255                 {
1256                     const bool *state = std::get_if<bool>(&property.second);
1257 
1258                     if (!state)
1259                     {
1260                         messages::internalError(aResp->res);
1261                         continue;
1262                     }
1263 
1264                     hostWatchdogTimer["FunctionEnabled"] = *state;
1265                 }
1266                 else if (property.first == "ExpireAction")
1267                 {
1268                     const std::string *s =
1269                         std::get_if<std::string>(&property.second);
1270                     if (!s)
1271                     {
1272                         messages::internalError(aResp->res);
1273                         continue;
1274                     }
1275 
1276                     std::string action = dbusToRfWatchdogAction(*s);
1277                     if (action.empty())
1278                     {
1279                         messages::internalError(aResp->res);
1280                         continue;
1281                     }
1282                     hostWatchdogTimer["TimeoutAction"] = action;
1283                 }
1284             }
1285         },
1286         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1287         "org.freedesktop.DBus.Properties", "GetAll",
1288         "xyz.openbmc_project.State.Watchdog");
1289 }
1290 
1291 /**
1292  * @brief Sets Host WatchDog Timer properties.
1293  *
1294  * @param[in] aResp      Shared pointer for generating response message.
1295  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1296  *                       RF request.
1297  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1298  *
1299  * @return None.
1300  */
1301 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1302                              const std::optional<bool> wdtEnable,
1303                              const std::optional<std::string> &wdtTimeOutAction)
1304 {
1305     BMCWEB_LOG_DEBUG << "Set host watchdog";
1306 
1307     if (wdtTimeOutAction)
1308     {
1309         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1310         // check if TimeOut Action is Valid
1311         if (wdtTimeOutActStr.empty())
1312         {
1313             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1314                              << *wdtTimeOutAction;
1315             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1316                                              "TimeoutAction");
1317             return;
1318         }
1319 
1320         crow::connections::systemBus->async_method_call(
1321             [aResp](const boost::system::error_code ec) {
1322                 if (ec)
1323                 {
1324                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1325                     messages::internalError(aResp->res);
1326                     return;
1327                 }
1328             },
1329             "xyz.openbmc_project.Watchdog",
1330             "/xyz/openbmc_project/watchdog/host0",
1331             "org.freedesktop.DBus.Properties", "Set",
1332             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1333             std::variant<std::string>(wdtTimeOutActStr));
1334     }
1335 
1336     if (wdtEnable)
1337     {
1338         crow::connections::systemBus->async_method_call(
1339             [aResp](const boost::system::error_code ec) {
1340                 if (ec)
1341                 {
1342                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1343                     messages::internalError(aResp->res);
1344                     return;
1345                 }
1346             },
1347             "xyz.openbmc_project.Watchdog",
1348             "/xyz/openbmc_project/watchdog/host0",
1349             "org.freedesktop.DBus.Properties", "Set",
1350             "xyz.openbmc_project.State.Watchdog", "Enabled",
1351             std::variant<bool>(*wdtEnable));
1352     }
1353 }
1354 
1355 /**
1356  * SystemsCollection derived class for delivering ComputerSystems Collection
1357  * Schema
1358  */
1359 class SystemsCollection : public Node
1360 {
1361   public:
1362     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1363     {
1364         entityPrivileges = {
1365             {boost::beast::http::verb::get, {{"Login"}}},
1366             {boost::beast::http::verb::head, {{"Login"}}},
1367             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1368             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1369             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1370             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1371     }
1372 
1373   private:
1374     void doGet(crow::Response &res, const crow::Request &req,
1375                const std::vector<std::string> &params) override
1376     {
1377         res.jsonValue["@odata.type"] =
1378             "#ComputerSystemCollection.ComputerSystemCollection";
1379         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1380         res.jsonValue["@odata.context"] =
1381             "/redfish/v1/"
1382             "$metadata#ComputerSystemCollection.ComputerSystemCollection";
1383         res.jsonValue["Name"] = "Computer System Collection";
1384         res.jsonValue["Members"] = {
1385             {{"@odata.id", "/redfish/v1/Systems/system"}}};
1386         res.jsonValue["Members@odata.count"] = 1;
1387         res.end();
1388     }
1389 };
1390 
1391 /**
1392  * SystemActionsReset class supports handle POST method for Reset action.
1393  * The class retrieves and sends data directly to D-Bus.
1394  */
1395 class SystemActionsReset : public Node
1396 {
1397   public:
1398     SystemActionsReset(CrowApp &app) :
1399         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1400     {
1401         entityPrivileges = {
1402             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1403     }
1404 
1405   private:
1406     /**
1407      * Function handles POST method request.
1408      * Analyzes POST body message before sends Reset request data to D-Bus.
1409      */
1410     void doPost(crow::Response &res, const crow::Request &req,
1411                 const std::vector<std::string> &params) override
1412     {
1413         auto asyncResp = std::make_shared<AsyncResp>(res);
1414 
1415         std::string resetType;
1416         if (!json_util::readJson(req, res, "ResetType", resetType))
1417         {
1418             return;
1419         }
1420 
1421         // Get the command and host vs. chassis
1422         std::string command;
1423         bool hostCommand;
1424         if (resetType == "On")
1425         {
1426             command = "xyz.openbmc_project.State.Host.Transition.On";
1427             hostCommand = true;
1428         }
1429         else if (resetType == "ForceOff")
1430         {
1431             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1432             hostCommand = false;
1433         }
1434         else if (resetType == "ForceOn")
1435         {
1436             command = "xyz.openbmc_project.State.Host.Transition.On";
1437             hostCommand = true;
1438         }
1439         else if (resetType == "ForceRestart")
1440         {
1441             command = "xyz.openbmc_project.State.Chassis.Transition.Reset";
1442             hostCommand = false;
1443         }
1444         else if (resetType == "GracefulShutdown")
1445         {
1446             command = "xyz.openbmc_project.State.Host.Transition.Off";
1447             hostCommand = true;
1448         }
1449         else if (resetType == "GracefulRestart")
1450         {
1451             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1452             hostCommand = true;
1453         }
1454         else if (resetType == "PowerCycle")
1455         {
1456             command = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
1457             hostCommand = false;
1458         }
1459         else if (resetType == "Nmi")
1460         {
1461             doNMI(asyncResp);
1462             return;
1463         }
1464         else
1465         {
1466             messages::actionParameterUnknown(res, "Reset", resetType);
1467             return;
1468         }
1469 
1470         if (hostCommand)
1471         {
1472             crow::connections::systemBus->async_method_call(
1473                 [asyncResp, resetType](const boost::system::error_code ec) {
1474                     if (ec)
1475                     {
1476                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1477                         if (ec.value() == boost::asio::error::invalid_argument)
1478                         {
1479                             messages::actionParameterNotSupported(
1480                                 asyncResp->res, resetType, "Reset");
1481                         }
1482                         else
1483                         {
1484                             messages::internalError(asyncResp->res);
1485                         }
1486                         return;
1487                     }
1488                     messages::success(asyncResp->res);
1489                 },
1490                 "xyz.openbmc_project.State.Host",
1491                 "/xyz/openbmc_project/state/host0",
1492                 "org.freedesktop.DBus.Properties", "Set",
1493                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1494                 std::variant<std::string>{command});
1495         }
1496         else
1497         {
1498             crow::connections::systemBus->async_method_call(
1499                 [asyncResp, resetType](const boost::system::error_code ec) {
1500                     if (ec)
1501                     {
1502                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1503                         if (ec.value() == boost::asio::error::invalid_argument)
1504                         {
1505                             messages::actionParameterNotSupported(
1506                                 asyncResp->res, resetType, "Reset");
1507                         }
1508                         else
1509                         {
1510                             messages::internalError(asyncResp->res);
1511                         }
1512                         return;
1513                     }
1514                     messages::success(asyncResp->res);
1515                 },
1516                 "xyz.openbmc_project.State.Chassis",
1517                 "/xyz/openbmc_project/state/chassis0",
1518                 "org.freedesktop.DBus.Properties", "Set",
1519                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1520                 std::variant<std::string>{command});
1521         }
1522     }
1523     /**
1524      * Function transceives data with dbus directly.
1525      */
1526     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1527     {
1528         constexpr char const *serviceName =
1529             "xyz.openbmc_project.Control.Host.NMI";
1530         constexpr char const *objectPath =
1531             "/xyz/openbmc_project/control/host0/nmi";
1532         constexpr char const *interfaceName =
1533             "xyz.openbmc_project.Control.Host.NMI";
1534         constexpr char const *method = "NMI";
1535 
1536         crow::connections::systemBus->async_method_call(
1537             [asyncResp](const boost::system::error_code ec) {
1538                 if (ec)
1539                 {
1540                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1541                     messages::internalError(asyncResp->res);
1542                     return;
1543                 }
1544                 messages::success(asyncResp->res);
1545             },
1546             serviceName, objectPath, interfaceName, method);
1547     }
1548 };
1549 
1550 /**
1551  * Systems derived class for delivering Computer Systems Schema.
1552  */
1553 class Systems : public Node
1554 {
1555   public:
1556     /*
1557      * Default Constructor
1558      */
1559     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1560     {
1561         entityPrivileges = {
1562             {boost::beast::http::verb::get, {{"Login"}}},
1563             {boost::beast::http::verb::head, {{"Login"}}},
1564             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1565             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1566             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1567             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1568     }
1569 
1570   private:
1571     /**
1572      * Functions triggers appropriate requests on DBus
1573      */
1574     void doGet(crow::Response &res, const crow::Request &req,
1575                const std::vector<std::string> &params) override
1576     {
1577         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1578         res.jsonValue["@odata.context"] =
1579             "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
1580         res.jsonValue["Name"] = "Computer System";
1581         res.jsonValue["Id"] = "system";
1582         res.jsonValue["SystemType"] = "Physical";
1583         res.jsonValue["Description"] = "Computer System";
1584         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1585         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1586         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
1587         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1588         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1589 
1590         res.jsonValue["Processors"] = {
1591             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1592         res.jsonValue["Memory"] = {
1593             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1594         res.jsonValue["Storage"] = {
1595             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1596 
1597         // TODO Need to support ForceRestart.
1598         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1599             {"target",
1600              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1601             {"ResetType@Redfish.AllowableValues",
1602              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1603               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1604 
1605         res.jsonValue["LogServices"] = {
1606             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1607 
1608         res.jsonValue["Links"]["ManagedBy"] = {
1609             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1610 
1611         res.jsonValue["Status"] = {
1612             {"Health", "OK"},
1613             {"State", "Enabled"},
1614         };
1615         auto asyncResp = std::make_shared<AsyncResp>(res);
1616 
1617         constexpr const std::array<const char *, 2> inventoryForSystems = {
1618             "xyz.openbmc_project.Inventory.Item.Dimm",
1619             "xyz.openbmc_project.Inventory.Item.Cpu"};
1620 
1621         auto health = std::make_shared<HealthPopulate>(asyncResp);
1622         crow::connections::systemBus->async_method_call(
1623             [health](const boost::system::error_code ec,
1624                      std::vector<std::string> &resp) {
1625                 if (ec)
1626                 {
1627                     // no inventory
1628                     return;
1629                 }
1630 
1631                 health->inventory = std::move(resp);
1632             },
1633             "xyz.openbmc_project.ObjectMapper",
1634             "/xyz/openbmc_project/object_mapper",
1635             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1636             int32_t(0), inventoryForSystems);
1637 
1638         health->populate();
1639 
1640         getMainChassisId(asyncResp, [](const std::string &chassisId,
1641                                        std::shared_ptr<AsyncResp> aRsp) {
1642             aRsp->res.jsonValue["Links"]["Chassis"] = {
1643                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1644         });
1645         getLedGroupIdentify(
1646             asyncResp,
1647             [](const bool &asserted, const std::shared_ptr<AsyncResp> aRsp) {
1648                 if (asserted)
1649                 {
1650                     // If led group is asserted, then another call is needed to
1651                     // get led status
1652                     getLedIdentify(
1653                         aRsp, [](const std::string &ledStatus,
1654                                  const std::shared_ptr<AsyncResp> aRsp) {
1655                             if (!ledStatus.empty())
1656                             {
1657                                 aRsp->res.jsonValue["IndicatorLED"] = ledStatus;
1658                             }
1659                         });
1660                 }
1661                 else
1662                 {
1663                     aRsp->res.jsonValue["IndicatorLED"] = "Off";
1664                 }
1665             });
1666         getComputerSystem(asyncResp, health);
1667         getHostState(asyncResp);
1668         getBootProperties(asyncResp);
1669         getPCIeDeviceList(asyncResp);
1670         getHostWatchdogTimer(asyncResp);
1671     }
1672 
1673     void doPatch(crow::Response &res, const crow::Request &req,
1674                  const std::vector<std::string> &params) override
1675     {
1676         std::optional<std::string> indicatorLed;
1677         std::optional<nlohmann::json> bootProps;
1678         std::optional<nlohmann::json> wdtTimerProps;
1679         auto asyncResp = std::make_shared<AsyncResp>(res);
1680 
1681         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1682                                  bootProps, "WatchdogTimer", wdtTimerProps))
1683         {
1684             return;
1685         }
1686 
1687         res.result(boost::beast::http::status::no_content);
1688 
1689         if (wdtTimerProps)
1690         {
1691             std::optional<bool> wdtEnable;
1692             std::optional<std::string> wdtTimeOutAction;
1693 
1694             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1695                                      "FunctionEnabled", wdtEnable,
1696                                      "TimeoutAction", wdtTimeOutAction))
1697             {
1698                 return;
1699             }
1700             setWDTProperties(asyncResp, std::move(wdtEnable),
1701                              std::move(wdtTimeOutAction));
1702         }
1703 
1704         if (bootProps)
1705         {
1706             std::optional<std::string> bootSource;
1707             std::optional<std::string> bootEnable;
1708 
1709             if (!json_util::readJson(*bootProps, asyncResp->res,
1710                                      "BootSourceOverrideTarget", bootSource,
1711                                      "BootSourceOverrideEnabled", bootEnable))
1712             {
1713                 return;
1714             }
1715             setBootProperties(asyncResp, std::move(bootSource),
1716                               std::move(bootEnable));
1717         }
1718 
1719         if (indicatorLed)
1720         {
1721             std::string dbusLedState;
1722             if (*indicatorLed == "Lit")
1723             {
1724                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On";
1725             }
1726             else if (*indicatorLed == "Blinking")
1727             {
1728                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink";
1729             }
1730             else if (*indicatorLed == "Off")
1731             {
1732                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off";
1733             }
1734             else
1735             {
1736                 messages::propertyValueNotInList(res, *indicatorLed,
1737                                                  "IndicatorLED");
1738                 return;
1739             }
1740 
1741             // Update led group
1742             BMCWEB_LOG_DEBUG << "Update led group.";
1743             crow::connections::systemBus->async_method_call(
1744                 [asyncResp](const boost::system::error_code ec) {
1745                     if (ec)
1746                     {
1747                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1748                         messages::internalError(asyncResp->res);
1749                         return;
1750                     }
1751                     BMCWEB_LOG_DEBUG << "Led group update done.";
1752                 },
1753                 "xyz.openbmc_project.LED.GroupManager",
1754                 "/xyz/openbmc_project/led/groups/enclosure_identify",
1755                 "org.freedesktop.DBus.Properties", "Set",
1756                 "xyz.openbmc_project.Led.Group", "Asserted",
1757                 std::variant<bool>(
1758                     (dbusLedState !=
1759                      "xyz.openbmc_project.Led.Physical.Action.Off")));
1760 
1761             // Update identify led status
1762             BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
1763             crow::connections::systemBus->async_method_call(
1764                 [asyncResp](const boost::system::error_code ec) {
1765                     if (ec)
1766                     {
1767                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1768                         messages::internalError(asyncResp->res);
1769                         return;
1770                     }
1771                     BMCWEB_LOG_DEBUG << "Led state update done.";
1772                 },
1773                 "xyz.openbmc_project.LED.Controller.identify",
1774                 "/xyz/openbmc_project/led/physical/identify",
1775                 "org.freedesktop.DBus.Properties", "Set",
1776                 "xyz.openbmc_project.Led.Physical", "State",
1777                 std::variant<std::string>(dbusLedState));
1778         }
1779     }
1780 };
1781 } // namespace redfish
1782