xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 8d78b7a9f5fbca338a5867d5dd4fa83890d79bc7)
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 sdbusplus::message::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                 sdbusplus::message::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)}](
1115             const boost::system::error_code ec,
1116             const sdbusplus::message::variant<bool> &oneTime) {
1117             if (ec)
1118             {
1119                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1120                 messages::internalError(aResp->res);
1121                 return;
1122             }
1123 
1124             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1125 
1126             if (!oneTimePtr)
1127             {
1128                 messages::internalError(aResp->res);
1129                 return;
1130             }
1131 
1132             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1133 
1134             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1135                                 std::move(bootEnable));
1136         },
1137         "xyz.openbmc_project.Settings",
1138         "/xyz/openbmc_project/control/host0/boot/one_time",
1139         "org.freedesktop.DBus.Properties", "Get",
1140         "xyz.openbmc_project.Object.Enable", "Enabled");
1141 }
1142 
1143 /**
1144  * @brief Sets power restore policy properties.
1145  *
1146  * @param[in] aResp   Shared pointer for generating response message.
1147  * @param[in] policy  power restore policy properties from request.
1148  *
1149  * @return None.
1150  */
1151 static void setPowerRestorePolicy(std::shared_ptr<AsyncResp> aResp,
1152                                   std::optional<std::string> policy)
1153 {
1154     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1155 
1156     const boost::container::flat_map<std::string, std::string> policyMaps = {
1157         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1158                      "AlwaysOn"},
1159         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1160                       "AlwaysOff"},
1161         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1162                       "LastState"}};
1163 
1164     std::string powerRestorPolicy;
1165 
1166     auto policyMapsIt = policyMaps.find(*policy);
1167     if (policyMapsIt == policyMaps.end())
1168     {
1169         messages::internalError(aResp->res);
1170         return;
1171     }
1172 
1173     powerRestorPolicy = policyMapsIt->second;
1174 
1175     crow::connections::systemBus->async_method_call(
1176         [aResp](const boost::system::error_code ec) {
1177             if (ec)
1178             {
1179                 messages::internalError(aResp->res);
1180                 return;
1181             }
1182         },
1183         "xyz.openbmc_project.Settings",
1184         "/xyz/openbmc_project/control/host0/power_restore_policy",
1185         "org.freedesktop.DBus.Properties", "Set",
1186         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1187         std::variant<std::string>(powerRestorPolicy));
1188 }
1189 
1190 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1191 /**
1192  * @brief Retrieves provisioning status
1193  *
1194  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1195  *
1196  * @return None.
1197  */
1198 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1199 {
1200     BMCWEB_LOG_DEBUG << "Get OEM information.";
1201     crow::connections::systemBus->async_method_call(
1202         [aResp](const boost::system::error_code ec,
1203                 const std::vector<std::pair<std::string, VariantType>>
1204                     &propertiesList) {
1205             if (ec)
1206             {
1207                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1208                 messages::internalError(aResp->res);
1209                 return;
1210             }
1211 
1212             const bool *provState = nullptr;
1213             const bool *lockState = nullptr;
1214             for (const std::pair<std::string, VariantType> &property :
1215                  propertiesList)
1216             {
1217                 if (property.first == "UfmProvisioned")
1218                 {
1219                     provState = std::get_if<bool>(&property.second);
1220                 }
1221                 else if (property.first == "UfmLocked")
1222                 {
1223                     lockState = std::get_if<bool>(&property.second);
1224                 }
1225             }
1226 
1227             if ((provState == nullptr) || (lockState == nullptr))
1228             {
1229                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1230                 messages::internalError(aResp->res);
1231                 return;
1232             }
1233 
1234             nlohmann::json &oemPFR =
1235                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1236             if (*provState == true)
1237             {
1238                 if (*lockState == true)
1239                 {
1240                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1241                 }
1242                 else
1243                 {
1244                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1245                 }
1246             }
1247             else
1248             {
1249                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1250             }
1251         },
1252         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1253         "org.freedesktop.DBus.Properties", "GetAll",
1254         "xyz.openbmc_project.PFR.Attributes");
1255 }
1256 #endif
1257 
1258 /**
1259  * @brief Translates watchdog timeout action DBUS property value to redfish.
1260  *
1261  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1262  *
1263  * @return Returns as a string, the timeout action in Redfish terms. If
1264  * translation cannot be done, returns an empty string.
1265  */
1266 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1267 {
1268     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1269     {
1270         return "None";
1271     }
1272     else if (dbusAction ==
1273              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1274     {
1275         return "ResetSystem";
1276     }
1277     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1278     {
1279         return "PowerDown";
1280     }
1281     else if (dbusAction ==
1282              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1283     {
1284         return "PowerCycle";
1285     }
1286 
1287     return "";
1288 }
1289 
1290 /**
1291  *@brief Translates timeout action from Redfish to DBUS property value.
1292  *
1293  *@param[in] rfAction The timeout action in Redfish.
1294  *
1295  *@return Returns as a string, the time_out action as expected by DBUS.
1296  *If translation cannot be done, returns an empty string.
1297  */
1298 
1299 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction)
1300 {
1301     if (rfAction == "None")
1302     {
1303         return "xyz.openbmc_project.State.Watchdog.Action.None";
1304     }
1305     else if (rfAction == "PowerCycle")
1306     {
1307         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1308     }
1309     else if (rfAction == "PowerDown")
1310     {
1311         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1312     }
1313     else if (rfAction == "ResetSystem")
1314     {
1315         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1316     }
1317 
1318     return "";
1319 }
1320 
1321 /**
1322  * @brief Retrieves host watchdog timer properties over DBUS
1323  *
1324  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1325  *
1326  * @return None.
1327  */
1328 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1329 {
1330     BMCWEB_LOG_DEBUG << "Get host watchodg";
1331     crow::connections::systemBus->async_method_call(
1332         [aResp](const boost::system::error_code ec,
1333                 PropertiesType &properties) {
1334             if (ec)
1335             {
1336                 // watchdog service is stopped
1337                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1338                 return;
1339             }
1340 
1341             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1342 
1343             nlohmann::json &hostWatchdogTimer =
1344                 aResp->res.jsonValue["HostWatchdogTimer"];
1345 
1346             // watchdog service is running/enabled
1347             hostWatchdogTimer["Status"]["State"] = "Enabled";
1348 
1349             for (const auto &property : properties)
1350             {
1351                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1352                 if (property.first == "Enabled")
1353                 {
1354                     const bool *state = std::get_if<bool>(&property.second);
1355 
1356                     if (!state)
1357                     {
1358                         messages::internalError(aResp->res);
1359                         continue;
1360                     }
1361 
1362                     hostWatchdogTimer["FunctionEnabled"] = *state;
1363                 }
1364                 else if (property.first == "ExpireAction")
1365                 {
1366                     const std::string *s =
1367                         std::get_if<std::string>(&property.second);
1368                     if (!s)
1369                     {
1370                         messages::internalError(aResp->res);
1371                         continue;
1372                     }
1373 
1374                     std::string action = dbusToRfWatchdogAction(*s);
1375                     if (action.empty())
1376                     {
1377                         messages::internalError(aResp->res);
1378                         continue;
1379                     }
1380                     hostWatchdogTimer["TimeoutAction"] = action;
1381                 }
1382             }
1383         },
1384         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1385         "org.freedesktop.DBus.Properties", "GetAll",
1386         "xyz.openbmc_project.State.Watchdog");
1387 }
1388 
1389 /**
1390  * @brief Sets Host WatchDog Timer properties.
1391  *
1392  * @param[in] aResp      Shared pointer for generating response message.
1393  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1394  *                       RF request.
1395  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1396  *
1397  * @return None.
1398  */
1399 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1400                              const std::optional<bool> wdtEnable,
1401                              const std::optional<std::string> &wdtTimeOutAction)
1402 {
1403     BMCWEB_LOG_DEBUG << "Set host watchdog";
1404 
1405     if (wdtTimeOutAction)
1406     {
1407         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1408         // check if TimeOut Action is Valid
1409         if (wdtTimeOutActStr.empty())
1410         {
1411             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1412                              << *wdtTimeOutAction;
1413             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1414                                              "TimeoutAction");
1415             return;
1416         }
1417 
1418         crow::connections::systemBus->async_method_call(
1419             [aResp](const boost::system::error_code ec) {
1420                 if (ec)
1421                 {
1422                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1423                     messages::internalError(aResp->res);
1424                     return;
1425                 }
1426             },
1427             "xyz.openbmc_project.Watchdog",
1428             "/xyz/openbmc_project/watchdog/host0",
1429             "org.freedesktop.DBus.Properties", "Set",
1430             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1431             std::variant<std::string>(wdtTimeOutActStr));
1432     }
1433 
1434     if (wdtEnable)
1435     {
1436         crow::connections::systemBus->async_method_call(
1437             [aResp](const boost::system::error_code ec) {
1438                 if (ec)
1439                 {
1440                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1441                     messages::internalError(aResp->res);
1442                     return;
1443                 }
1444             },
1445             "xyz.openbmc_project.Watchdog",
1446             "/xyz/openbmc_project/watchdog/host0",
1447             "org.freedesktop.DBus.Properties", "Set",
1448             "xyz.openbmc_project.State.Watchdog", "Enabled",
1449             std::variant<bool>(*wdtEnable));
1450     }
1451 }
1452 
1453 /**
1454  * SystemsCollection derived class for delivering ComputerSystems Collection
1455  * Schema
1456  */
1457 class SystemsCollection : public Node
1458 {
1459   public:
1460     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1461     {
1462         entityPrivileges = {
1463             {boost::beast::http::verb::get, {{"Login"}}},
1464             {boost::beast::http::verb::head, {{"Login"}}},
1465             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1466             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1467             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1468             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1469     }
1470 
1471   private:
1472     void doGet(crow::Response &res, const crow::Request &req,
1473                const std::vector<std::string> &params) override
1474     {
1475         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1476         res.jsonValue["@odata.type"] =
1477             "#ComputerSystemCollection.ComputerSystemCollection";
1478         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1479         res.jsonValue["Name"] = "Computer System Collection";
1480 
1481         crow::connections::systemBus->async_method_call(
1482             [asyncResp](const boost::system::error_code ec,
1483                         const std::variant<std::string> &hostName) {
1484                 nlohmann::json &iface_array =
1485                     asyncResp->res.jsonValue["Members"];
1486                 iface_array = nlohmann::json::array();
1487                 auto &count = asyncResp->res.jsonValue["Members@odata.count"];
1488                 count = 0;
1489                 if (ec)
1490                 {
1491                     iface_array.push_back(
1492                         {{"@odata.id", "/redfish/v1/Systems/system"}});
1493                     count = iface_array.size();
1494                     return;
1495                 }
1496                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
1497                 iface_array.push_back(
1498                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1499                 iface_array.push_back(
1500                     {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1501                 count = iface_array.size();
1502             },
1503             "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
1504             "org.freedesktop.DBus.Properties", "Get",
1505             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1506     }
1507 };
1508 
1509 /**
1510  * SystemActionsReset class supports handle POST method for Reset action.
1511  * The class retrieves and sends data directly to D-Bus.
1512  */
1513 class SystemActionsReset : public Node
1514 {
1515   public:
1516     SystemActionsReset(CrowApp &app) :
1517         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1518     {
1519         entityPrivileges = {
1520             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1521     }
1522 
1523   private:
1524     /**
1525      * Function handles POST method request.
1526      * Analyzes POST body message before sends Reset request data to D-Bus.
1527      */
1528     void doPost(crow::Response &res, const crow::Request &req,
1529                 const std::vector<std::string> &params) override
1530     {
1531         auto asyncResp = std::make_shared<AsyncResp>(res);
1532 
1533         std::string resetType;
1534         if (!json_util::readJson(req, res, "ResetType", resetType))
1535         {
1536             return;
1537         }
1538 
1539         // Get the command and host vs. chassis
1540         std::string command;
1541         bool hostCommand;
1542         if (resetType == "On")
1543         {
1544             command = "xyz.openbmc_project.State.Host.Transition.On";
1545             hostCommand = true;
1546         }
1547         else if (resetType == "ForceOff")
1548         {
1549             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1550             hostCommand = false;
1551         }
1552         else if (resetType == "ForceOn")
1553         {
1554             command = "xyz.openbmc_project.State.Host.Transition.On";
1555             hostCommand = true;
1556         }
1557         else if (resetType == "ForceRestart")
1558         {
1559             command =
1560                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1561             hostCommand = true;
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 =
1571                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1572             hostCommand = true;
1573         }
1574         else if (resetType == "PowerCycle")
1575         {
1576             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1577             hostCommand = true;
1578         }
1579         else if (resetType == "Nmi")
1580         {
1581             doNMI(asyncResp);
1582             return;
1583         }
1584         else
1585         {
1586             messages::actionParameterUnknown(res, "Reset", resetType);
1587             return;
1588         }
1589 
1590         if (hostCommand)
1591         {
1592             crow::connections::systemBus->async_method_call(
1593                 [asyncResp, resetType](const boost::system::error_code ec) {
1594                     if (ec)
1595                     {
1596                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1597                         if (ec.value() == boost::asio::error::invalid_argument)
1598                         {
1599                             messages::actionParameterNotSupported(
1600                                 asyncResp->res, resetType, "Reset");
1601                         }
1602                         else
1603                         {
1604                             messages::internalError(asyncResp->res);
1605                         }
1606                         return;
1607                     }
1608                     messages::success(asyncResp->res);
1609                 },
1610                 "xyz.openbmc_project.State.Host",
1611                 "/xyz/openbmc_project/state/host0",
1612                 "org.freedesktop.DBus.Properties", "Set",
1613                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1614                 std::variant<std::string>{command});
1615         }
1616         else
1617         {
1618             crow::connections::systemBus->async_method_call(
1619                 [asyncResp, resetType](const boost::system::error_code ec) {
1620                     if (ec)
1621                     {
1622                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1623                         if (ec.value() == boost::asio::error::invalid_argument)
1624                         {
1625                             messages::actionParameterNotSupported(
1626                                 asyncResp->res, resetType, "Reset");
1627                         }
1628                         else
1629                         {
1630                             messages::internalError(asyncResp->res);
1631                         }
1632                         return;
1633                     }
1634                     messages::success(asyncResp->res);
1635                 },
1636                 "xyz.openbmc_project.State.Chassis",
1637                 "/xyz/openbmc_project/state/chassis0",
1638                 "org.freedesktop.DBus.Properties", "Set",
1639                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1640                 std::variant<std::string>{command});
1641         }
1642     }
1643     /**
1644      * Function transceives data with dbus directly.
1645      */
1646     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1647     {
1648         constexpr char const *serviceName =
1649             "xyz.openbmc_project.Control.Host.NMI";
1650         constexpr char const *objectPath =
1651             "/xyz/openbmc_project/control/host0/nmi";
1652         constexpr char const *interfaceName =
1653             "xyz.openbmc_project.Control.Host.NMI";
1654         constexpr char const *method = "NMI";
1655 
1656         crow::connections::systemBus->async_method_call(
1657             [asyncResp](const boost::system::error_code ec) {
1658                 if (ec)
1659                 {
1660                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1661                     messages::internalError(asyncResp->res);
1662                     return;
1663                 }
1664                 messages::success(asyncResp->res);
1665             },
1666             serviceName, objectPath, interfaceName, method);
1667     }
1668 };
1669 
1670 /**
1671  * Systems derived class for delivering Computer Systems Schema.
1672  */
1673 class Systems : public Node
1674 {
1675   public:
1676     /*
1677      * Default Constructor
1678      */
1679     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1680     {
1681         entityPrivileges = {
1682             {boost::beast::http::verb::get, {{"Login"}}},
1683             {boost::beast::http::verb::head, {{"Login"}}},
1684             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1685             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1686             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1687             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1688     }
1689 
1690   private:
1691     /**
1692      * Functions triggers appropriate requests on DBus
1693      */
1694     void doGet(crow::Response &res, const crow::Request &req,
1695                const std::vector<std::string> &params) override
1696     {
1697         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1698         res.jsonValue["Name"] = "system";
1699         res.jsonValue["Id"] = "system";
1700         res.jsonValue["SystemType"] = "Physical";
1701         res.jsonValue["Description"] = "Computer System";
1702         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1703         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1704         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
1705         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1706         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1707 
1708         res.jsonValue["Processors"] = {
1709             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1710         res.jsonValue["Memory"] = {
1711             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1712         res.jsonValue["Storage"] = {
1713             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1714 
1715         // TODO Need to support ForceRestart.
1716         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1717             {"target",
1718              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1719             {"ResetType@Redfish.AllowableValues",
1720              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1721               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1722 
1723         res.jsonValue["LogServices"] = {
1724             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1725 
1726         res.jsonValue["Bios"] = {
1727             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
1728 
1729         res.jsonValue["Links"]["ManagedBy"] = {
1730             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1731 
1732         res.jsonValue["Status"] = {
1733             {"Health", "OK"},
1734             {"State", "Enabled"},
1735         };
1736         auto asyncResp = std::make_shared<AsyncResp>(res);
1737 
1738         constexpr const std::array<const char *, 4> inventoryForSystems = {
1739             "xyz.openbmc_project.Inventory.Item.Dimm",
1740             "xyz.openbmc_project.Inventory.Item.Cpu",
1741             "xyz.openbmc_project.Inventory.Item.Drive",
1742             "xyz.openbmc_project.Inventory.Item.StorageController"};
1743 
1744         auto health = std::make_shared<HealthPopulate>(asyncResp);
1745         crow::connections::systemBus->async_method_call(
1746             [health](const boost::system::error_code ec,
1747                      std::vector<std::string> &resp) {
1748                 if (ec)
1749                 {
1750                     // no inventory
1751                     return;
1752                 }
1753 
1754                 health->inventory = std::move(resp);
1755             },
1756             "xyz.openbmc_project.ObjectMapper",
1757             "/xyz/openbmc_project/object_mapper",
1758             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1759             int32_t(0), inventoryForSystems);
1760 
1761         health->populate();
1762 
1763         getMainChassisId(asyncResp, [](const std::string &chassisId,
1764                                        std::shared_ptr<AsyncResp> aRsp) {
1765             aRsp->res.jsonValue["Links"]["Chassis"] = {
1766                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1767         });
1768 
1769         getIndicatorLedState(asyncResp);
1770         getComputerSystem(asyncResp, health);
1771         getHostState(asyncResp);
1772         getBootProperties(asyncResp);
1773         getPCIeDeviceList(asyncResp, "PCIeDevices");
1774         getHostWatchdogTimer(asyncResp);
1775         getPowerRestorePolicy(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         std::optional<std::string> powerRestorePolicy;
1788         auto asyncResp = std::make_shared<AsyncResp>(res);
1789 
1790         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1791                                  bootProps, "WatchdogTimer", wdtTimerProps,
1792                                  "PowerRestorePolicy", powerRestorePolicy))
1793         {
1794             return;
1795         }
1796 
1797         res.result(boost::beast::http::status::no_content);
1798 
1799         if (wdtTimerProps)
1800         {
1801             std::optional<bool> wdtEnable;
1802             std::optional<std::string> wdtTimeOutAction;
1803 
1804             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1805                                      "FunctionEnabled", wdtEnable,
1806                                      "TimeoutAction", wdtTimeOutAction))
1807             {
1808                 return;
1809             }
1810             setWDTProperties(asyncResp, std::move(wdtEnable),
1811                              std::move(wdtTimeOutAction));
1812         }
1813 
1814         if (bootProps)
1815         {
1816             std::optional<std::string> bootSource;
1817             std::optional<std::string> bootEnable;
1818 
1819             if (!json_util::readJson(*bootProps, asyncResp->res,
1820                                      "BootSourceOverrideTarget", bootSource,
1821                                      "BootSourceOverrideEnabled", bootEnable))
1822             {
1823                 return;
1824             }
1825             setBootProperties(asyncResp, std::move(bootSource),
1826                               std::move(bootEnable));
1827         }
1828 
1829         if (indicatorLed)
1830         {
1831             setIndicatorLedState(asyncResp, std::move(*indicatorLed));
1832         }
1833 
1834         if (powerRestorePolicy)
1835         {
1836             setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy));
1837         }
1838     }
1839 };
1840 } // namespace redfish
1841