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