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