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