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