xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 60c922df)
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 <app.hpp>
24 #include <boost/container/flat_map.hpp>
25 #include <registries/privilege_registry.hpp>
26 #include <utils/fw_utils.hpp>
27 #include <utils/json_utils.hpp>
28 
29 #include <variant>
30 
31 namespace redfish
32 {
33 
34 /**
35  * @brief Updates the Functional State of DIMMs
36  *
37  * @param[in] aResp Shared pointer for completing asynchronous calls
38  * @param[in] dimmState Dimm's Functional state, true/false
39  *
40  * @return None.
41  */
42 inline void
43     updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
44                          const std::variant<bool>& dimmState)
45 {
46     const bool* isDimmFunctional = std::get_if<bool>(&dimmState);
47     if (isDimmFunctional == nullptr)
48     {
49         messages::internalError(aResp->res);
50         return;
51     }
52     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
53 
54     // Set it as Enabled if at least one DIMM is functional
55     // Update STATE only if previous State was DISABLED and current Dimm is
56     // ENABLED.
57     nlohmann::json& prevMemSummary =
58         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
59     if (prevMemSummary == "Disabled")
60     {
61         if (*isDimmFunctional == true)
62         {
63             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
64                 "Enabled";
65         }
66     }
67 }
68 
69 /*
70  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
71  *
72  * @param[in] aResp Shared pointer for completing asynchronous calls
73  * @param[in] cpuPresenceState CPU present or not
74  *
75  * @return None.
76  */
77 inline void
78     modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
79                            const std::variant<bool>& cpuPresenceState)
80 {
81     const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState);
82 
83     if (isCpuPresent == nullptr)
84     {
85         messages::internalError(aResp->res);
86         return;
87     }
88     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
89 
90     if (*isCpuPresent == true)
91     {
92         nlohmann::json& procCount =
93             aResp->res.jsonValue["ProcessorSummary"]["Count"];
94         auto procCountPtr =
95             procCount.get_ptr<nlohmann::json::number_integer_t*>();
96         if (procCountPtr != nullptr)
97         {
98             // shouldn't be possible to be nullptr
99             *procCountPtr += 1;
100         }
101     }
102 }
103 
104 /*
105  * @brief Update "ProcessorSummary" "Status" "State" based on
106  *        CPU Functional State
107  *
108  * @param[in] aResp Shared pointer for completing asynchronous calls
109  * @param[in] cpuFunctionalState is CPU functional true/false
110  *
111  * @return None.
112  */
113 inline void
114     modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
115                              const std::variant<bool>& cpuFunctionalState)
116 {
117     const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
118 
119     if (isCpuFunctional == nullptr)
120     {
121         messages::internalError(aResp->res);
122         return;
123     }
124     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
125 
126     nlohmann::json& prevProcState =
127         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
128 
129     // Set it as Enabled if at least one CPU is functional
130     // Update STATE only if previous State was Non_Functional and current CPU is
131     // Functional.
132     if (prevProcState == "Disabled")
133     {
134         if (*isCpuFunctional == true)
135         {
136             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
137                 "Enabled";
138         }
139     }
140 }
141 
142 inline void getProcessorProperties(
143     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const std::string& service,
144     const std::string& path,
145     const std::vector<std::pair<
146         std::string, std::variant<std::string, uint64_t, uint32_t, uint16_t>>>&
147         properties)
148 {
149 
150     BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties.";
151 
152     auto getCpuPresenceState =
153         [aResp](const boost::system::error_code ec3,
154                 const std::variant<bool>& cpuPresenceCheck) {
155             if (ec3)
156             {
157                 BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
158                 return;
159             }
160             modifyCpuPresenceState(aResp, cpuPresenceCheck);
161         };
162 
163     auto getCpuFunctionalState =
164         [aResp](const boost::system::error_code ec3,
165                 const std::variant<bool>& cpuFunctionalCheck) {
166             if (ec3)
167             {
168                 BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
169                 return;
170             }
171             modifyCpuFunctionalState(aResp, cpuFunctionalCheck);
172         };
173 
174     // Get the Presence of CPU
175     crow::connections::systemBus->async_method_call(
176         std::move(getCpuPresenceState), service, path,
177         "org.freedesktop.DBus.Properties", "Get",
178         "xyz.openbmc_project.Inventory.Item", "Present");
179 
180     // Get the Functional State
181     crow::connections::systemBus->async_method_call(
182         std::move(getCpuFunctionalState), service, path,
183         "org.freedesktop.DBus.Properties", "Get",
184         "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional");
185 
186     for (const auto& property : properties)
187     {
188 
189         // TODO: Get Model
190 
191         // Get CoreCount
192         if (property.first == "CoreCount")
193         {
194 
195             // Get CPU CoreCount and add it to the total
196             const uint16_t* coreCountVal =
197                 std::get_if<uint16_t>(&property.second);
198 
199             if (!coreCountVal)
200             {
201                 messages::internalError(aResp->res);
202                 return;
203             }
204 
205             nlohmann::json& coreCount =
206                 aResp->res.jsonValue["ProcessorSummary"]["CoreCount"];
207             uint64_t* coreCountPtr = coreCount.get_ptr<uint64_t*>();
208 
209             if (coreCountPtr == nullptr)
210             {
211                 coreCount = 0;
212             }
213             else
214             {
215                 *coreCountPtr += *coreCountVal;
216             }
217         }
218     }
219 }
220 
221 /*
222  * @brief Get ProcessorSummary fields
223  *
224  * @param[in] aResp Shared pointer for completing asynchronous calls
225  * @param[in] service dbus service for Cpu Information
226  * @param[in] path dbus path for Cpu
227  *
228  * @return None.
229  */
230 inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
231                                 const std::string& service,
232                                 const std::string& path)
233 {
234 
235     crow::connections::systemBus->async_method_call(
236         [aResp, service,
237          path](const boost::system::error_code ec2,
238                const std::vector<std::pair<
239                    std::string, std::variant<std::string, uint64_t, uint32_t,
240                                              uint16_t>>>& properties) {
241             if (ec2)
242             {
243                 BMCWEB_LOG_ERROR << "DBUS response error " << ec2;
244                 messages::internalError(aResp->res);
245                 return;
246             }
247             getProcessorProperties(aResp, service, path, properties);
248         },
249         service, path, "org.freedesktop.DBus.Properties", "GetAll",
250         "xyz.openbmc_project.Inventory.Item.Cpu");
251 }
252 
253 /*
254  * @brief Retrieves computer system properties over dbus
255  *
256  * @param[in] aResp Shared pointer for completing asynchronous calls
257  * @param[in] systemHealth  Shared HealthPopulate pointer
258  *
259  * @return None.
260  */
261 inline void
262     getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
263                       const std::shared_ptr<HealthPopulate>& systemHealth)
264 {
265     BMCWEB_LOG_DEBUG << "Get available system components.";
266 
267     crow::connections::systemBus->async_method_call(
268         [aResp, systemHealth](
269             const boost::system::error_code ec,
270             const std::vector<std::pair<
271                 std::string,
272                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
273                 subtree) {
274             if (ec)
275             {
276                 BMCWEB_LOG_DEBUG << "DBUS response error";
277                 messages::internalError(aResp->res);
278                 return;
279             }
280             // Iterate over all retrieved ObjectPaths.
281             for (const std::pair<std::string,
282                                  std::vector<std::pair<
283                                      std::string, std::vector<std::string>>>>&
284                      object : subtree)
285             {
286                 const std::string& path = object.first;
287                 BMCWEB_LOG_DEBUG << "Got path: " << path;
288                 const std::vector<
289                     std::pair<std::string, std::vector<std::string>>>&
290                     connectionNames = object.second;
291                 if (connectionNames.size() < 1)
292                 {
293                     continue;
294                 }
295 
296                 auto memoryHealth = std::make_shared<HealthPopulate>(
297                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
298 
299                 auto cpuHealth = std::make_shared<HealthPopulate>(
300                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
301 
302                 systemHealth->children.emplace_back(memoryHealth);
303                 systemHealth->children.emplace_back(cpuHealth);
304 
305                 // This is not system, so check if it's cpu, dimm, UUID or
306                 // BiosVer
307                 for (const auto& connection : connectionNames)
308                 {
309                     for (const auto& interfaceName : connection.second)
310                     {
311                         if (interfaceName ==
312                             "xyz.openbmc_project.Inventory.Item.Dimm")
313                         {
314                             BMCWEB_LOG_DEBUG
315                                 << "Found Dimm, now get its properties.";
316 
317                             crow::connections::systemBus->async_method_call(
318                                 [aResp, service{connection.first},
319                                  path](const boost::system::error_code ec2,
320                                        const std::vector<
321                                            std::pair<std::string, VariantType>>&
322                                            properties) {
323                                     if (ec2)
324                                     {
325                                         BMCWEB_LOG_ERROR
326                                             << "DBUS response error " << ec2;
327                                         messages::internalError(aResp->res);
328                                         return;
329                                     }
330                                     BMCWEB_LOG_DEBUG << "Got "
331                                                      << properties.size()
332                                                      << " Dimm properties.";
333 
334                                     if (properties.size() > 0)
335                                     {
336                                         for (const std::pair<std::string,
337                                                              VariantType>&
338                                                  property : properties)
339                                         {
340                                             if (property.first !=
341                                                 "MemorySizeInKB")
342                                             {
343                                                 continue;
344                                             }
345                                             const uint32_t* value =
346                                                 std::get_if<uint32_t>(
347                                                     &property.second);
348                                             if (value == nullptr)
349                                             {
350                                                 BMCWEB_LOG_DEBUG
351                                                     << "Find incorrect type of MemorySize";
352                                                 continue;
353                                             }
354                                             nlohmann::json& totalMemory =
355                                                 aResp->res.jsonValue
356                                                     ["MemorySummary"]
357                                                     ["TotalSystemMemoryGiB"];
358                                             uint64_t* preValue =
359                                                 totalMemory
360                                                     .get_ptr<uint64_t*>();
361                                             if (preValue == nullptr)
362                                             {
363                                                 continue;
364                                             }
365                                             aResp->res.jsonValue
366                                                 ["MemorySummary"]
367                                                 ["TotalSystemMemoryGiB"] =
368                                                 *value / (1024 * 1024) +
369                                                 *preValue;
370                                             aResp->res
371                                                 .jsonValue["MemorySummary"]
372                                                           ["Status"]["State"] =
373                                                 "Enabled";
374                                         }
375                                     }
376                                     else
377                                     {
378                                         auto getDimmProperties =
379                                             [aResp](
380                                                 const boost::system::error_code
381                                                     ec3,
382                                                 const std::variant<bool>&
383                                                     dimmState) {
384                                                 if (ec3)
385                                                 {
386                                                     BMCWEB_LOG_ERROR
387                                                         << "DBUS response error "
388                                                         << ec3;
389                                                     return;
390                                                 }
391                                                 updateDimmProperties(aResp,
392                                                                      dimmState);
393                                             };
394                                         crow::connections::systemBus
395                                             ->async_method_call(
396                                                 std::move(getDimmProperties),
397                                                 service, path,
398                                                 "org.freedesktop.DBus.Properties",
399                                                 "Get",
400                                                 "xyz.openbmc_project.State.Decorator.OperationalStatus",
401                                                 "Functional");
402                                     }
403                                 },
404                                 connection.first, path,
405                                 "org.freedesktop.DBus.Properties", "GetAll",
406                                 "xyz.openbmc_project.Inventory.Item.Dimm");
407 
408                             memoryHealth->inventory.emplace_back(path);
409                         }
410                         else if (interfaceName ==
411                                  "xyz.openbmc_project.Inventory.Item.Cpu")
412                         {
413                             BMCWEB_LOG_DEBUG
414                                 << "Found Cpu, now get its properties.";
415 
416                             getProcessorSummary(aResp, connection.first, path);
417 
418                             cpuHealth->inventory.emplace_back(path);
419                         }
420                         else if (interfaceName ==
421                                  "xyz.openbmc_project.Common.UUID")
422                         {
423                             BMCWEB_LOG_DEBUG
424                                 << "Found UUID, now get its properties.";
425                             crow::connections::systemBus->async_method_call(
426                                 [aResp](
427                                     const boost::system::error_code ec3,
428                                     const std::vector<
429                                         std::pair<std::string, VariantType>>&
430                                         properties) {
431                                     if (ec3)
432                                     {
433                                         BMCWEB_LOG_DEBUG
434                                             << "DBUS response error " << ec3;
435                                         messages::internalError(aResp->res);
436                                         return;
437                                     }
438                                     BMCWEB_LOG_DEBUG << "Got "
439                                                      << properties.size()
440                                                      << " UUID properties.";
441                                     for (const std::pair<std::string,
442                                                          VariantType>&
443                                              property : properties)
444                                     {
445                                         if (property.first == "UUID")
446                                         {
447                                             const std::string* value =
448                                                 std::get_if<std::string>(
449                                                     &property.second);
450 
451                                             if (value != nullptr)
452                                             {
453                                                 std::string valueStr = *value;
454                                                 if (valueStr.size() == 32)
455                                                 {
456                                                     valueStr.insert(8, 1, '-');
457                                                     valueStr.insert(13, 1, '-');
458                                                     valueStr.insert(18, 1, '-');
459                                                     valueStr.insert(23, 1, '-');
460                                                 }
461                                                 BMCWEB_LOG_DEBUG << "UUID = "
462                                                                  << valueStr;
463                                                 aResp->res.jsonValue["UUID"] =
464                                                     valueStr;
465                                             }
466                                         }
467                                     }
468                                 },
469                                 connection.first, path,
470                                 "org.freedesktop.DBus.Properties", "GetAll",
471                                 "xyz.openbmc_project.Common.UUID");
472                         }
473                         else if (interfaceName ==
474                                  "xyz.openbmc_project.Inventory.Item.System")
475                         {
476                             crow::connections::systemBus->async_method_call(
477                                 [aResp](
478                                     const boost::system::error_code ec2,
479                                     const std::vector<
480                                         std::pair<std::string, VariantType>>&
481                                         propertiesList) {
482                                     if (ec2)
483                                     {
484                                         // doesn't have to include this
485                                         // interface
486                                         return;
487                                     }
488                                     BMCWEB_LOG_DEBUG
489                                         << "Got " << propertiesList.size()
490                                         << " properties for system";
491                                     for (const std::pair<std::string,
492                                                          VariantType>&
493                                              property : propertiesList)
494                                     {
495                                         const std::string& propertyName =
496                                             property.first;
497                                         if ((propertyName == "PartNumber") ||
498                                             (propertyName == "SerialNumber") ||
499                                             (propertyName == "Manufacturer") ||
500                                             (propertyName == "Model") ||
501                                             (propertyName == "SubModel"))
502                                         {
503                                             const std::string* value =
504                                                 std::get_if<std::string>(
505                                                     &property.second);
506                                             if (value != nullptr)
507                                             {
508                                                 aResp->res
509                                                     .jsonValue[propertyName] =
510                                                     *value;
511                                             }
512                                         }
513                                     }
514 
515                                     // Grab the bios version
516                                     fw_util::populateFirmwareInformation(
517                                         aResp, fw_util::biosPurpose,
518                                         "BiosVersion", false);
519                                 },
520                                 connection.first, path,
521                                 "org.freedesktop.DBus.Properties", "GetAll",
522                                 "xyz.openbmc_project.Inventory.Decorator.Asset");
523 
524                             crow::connections::systemBus->async_method_call(
525                                 [aResp](
526                                     const boost::system::error_code ec2,
527                                     const std::variant<std::string>& property) {
528                                     if (ec2)
529                                     {
530                                         // doesn't have to include this
531                                         // interface
532                                         return;
533                                     }
534 
535                                     const std::string* value =
536                                         std::get_if<std::string>(&property);
537                                     if (value != nullptr)
538                                     {
539                                         aResp->res.jsonValue["AssetTag"] =
540                                             *value;
541                                     }
542                                 },
543                                 connection.first, path,
544                                 "org.freedesktop.DBus.Properties", "Get",
545                                 "xyz.openbmc_project.Inventory.Decorator.AssetTag",
546                                 "AssetTag");
547                         }
548                     }
549                 }
550             }
551         },
552         "xyz.openbmc_project.ObjectMapper",
553         "/xyz/openbmc_project/object_mapper",
554         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
555         "/xyz/openbmc_project/inventory", int32_t(0),
556         std::array<const char*, 5>{
557             "xyz.openbmc_project.Inventory.Decorator.Asset",
558             "xyz.openbmc_project.Inventory.Item.Cpu",
559             "xyz.openbmc_project.Inventory.Item.Dimm",
560             "xyz.openbmc_project.Inventory.Item.System",
561             "xyz.openbmc_project.Common.UUID",
562         });
563 }
564 
565 /**
566  * @brief Retrieves host state properties over dbus
567  *
568  * @param[in] aResp     Shared pointer for completing asynchronous calls.
569  *
570  * @return None.
571  */
572 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
573 {
574     BMCWEB_LOG_DEBUG << "Get host information.";
575     crow::connections::systemBus->async_method_call(
576         [aResp](const boost::system::error_code ec,
577                 const std::variant<std::string>& hostState) {
578             if (ec)
579             {
580                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
581                 messages::internalError(aResp->res);
582                 return;
583             }
584 
585             const std::string* s = std::get_if<std::string>(&hostState);
586             BMCWEB_LOG_DEBUG << "Host state: " << *s;
587             if (s != nullptr)
588             {
589                 // Verify Host State
590                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
591                 {
592                     aResp->res.jsonValue["PowerState"] = "On";
593                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
594                 }
595                 else if (*s ==
596                          "xyz.openbmc_project.State.Host.HostState.Quiesced")
597                 {
598                     aResp->res.jsonValue["PowerState"] = "On";
599                     aResp->res.jsonValue["Status"]["State"] = "Quiesced";
600                 }
601                 else if (
602                     *s ==
603                     "xyz.openbmc_project.State.Host.HostState.DiagnosticMode")
604                 {
605                     aResp->res.jsonValue["PowerState"] = "On";
606                     aResp->res.jsonValue["Status"]["State"] = "InTest";
607                 }
608                 else if (
609                     *s ==
610                     "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning")
611                 {
612                     aResp->res.jsonValue["PowerState"] = "PoweringOn";
613                     aResp->res.jsonValue["Status"]["State"] = "Starting";
614                 }
615                 else if (
616                     *s ==
617                     "xyz.openbmc_project.State.Host.HostState.TransitioningToOff")
618                 {
619                     aResp->res.jsonValue["PowerState"] = "PoweringOff";
620                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
621                 }
622                 else
623                 {
624                     aResp->res.jsonValue["PowerState"] = "Off";
625                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
626                 }
627             }
628         },
629         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
630         "org.freedesktop.DBus.Properties", "Get",
631         "xyz.openbmc_project.State.Host", "CurrentHostState");
632 }
633 
634 /**
635  * @brief Translates boot source DBUS property value to redfish.
636  *
637  * @param[in] dbusSource    The boot source in DBUS speak.
638  *
639  * @return Returns as a string, the boot source in Redfish terms. If translation
640  * cannot be done, returns an empty string.
641  */
642 inline std::string dbusToRfBootSource(const std::string& dbusSource)
643 {
644     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
645     {
646         return "None";
647     }
648     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
649     {
650         return "Hdd";
651     }
652     if (dbusSource ==
653         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
654     {
655         return "Cd";
656     }
657     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
658     {
659         return "Pxe";
660     }
661     if (dbusSource ==
662         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
663     {
664         return "Usb";
665     }
666     return "";
667 }
668 
669 /**
670  * @brief Translates boot type DBUS property value to redfish.
671  *
672  * @param[in] dbusType    The boot type in DBUS speak.
673  *
674  * @return Returns as a string, the boot type in Redfish terms. If translation
675  * cannot be done, returns an empty string.
676  */
677 inline std::string dbusToRfBootType(const std::string& dbusType)
678 {
679     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy")
680     {
681         return "Legacy";
682     }
683     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI")
684     {
685         return "UEFI";
686     }
687     return "";
688 }
689 
690 /**
691  * @brief Translates boot mode DBUS property value to redfish.
692  *
693  * @param[in] dbusMode    The boot mode in DBUS speak.
694  *
695  * @return Returns as a string, the boot mode in Redfish terms. If translation
696  * cannot be done, returns an empty string.
697  */
698 inline std::string dbusToRfBootMode(const std::string& dbusMode)
699 {
700     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
701     {
702         return "None";
703     }
704     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
705     {
706         return "Diags";
707     }
708     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
709     {
710         return "BiosSetup";
711     }
712     return "";
713 }
714 
715 /**
716  * @brief Translates boot source from Redfish to the DBus boot paths.
717  *
718  * @param[in] rfSource    The boot source in Redfish.
719  * @param[out] bootSource The DBus source
720  * @param[out] bootMode   the DBus boot mode
721  *
722  * @return Integer error code.
723  */
724 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
725                                 const std::string& rfSource,
726                                 std::string& bootSource, std::string& bootMode)
727 {
728     bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
729     bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
730 
731     if (rfSource == "None")
732     {
733         return 0;
734     }
735     if (rfSource == "Pxe")
736     {
737         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
738     }
739     else if (rfSource == "Hdd")
740     {
741         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
742     }
743     else if (rfSource == "Diags")
744     {
745         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
746     }
747     else if (rfSource == "Cd")
748     {
749         bootSource =
750             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
751     }
752     else if (rfSource == "BiosSetup")
753     {
754         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
755     }
756     else if (rfSource == "Usb")
757     {
758         bootSource =
759             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
760     }
761     else
762     {
763         BMCWEB_LOG_DEBUG
764             << "Invalid property value for BootSourceOverrideTarget: "
765             << bootSource;
766         messages::propertyValueNotInList(aResp->res, rfSource,
767                                          "BootSourceTargetOverride");
768         return -1;
769     }
770     return 0;
771 }
772 
773 /**
774  * @brief Retrieves boot progress of the system
775  *
776  * @param[in] aResp  Shared pointer for generating response message.
777  *
778  * @return None.
779  */
780 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
781 {
782     crow::connections::systemBus->async_method_call(
783         [aResp](const boost::system::error_code ec,
784                 const std::variant<std::string>& bootProgress) {
785             if (ec)
786             {
787                 // BootProgress is an optional object so just do nothing if
788                 // not found
789                 return;
790             }
791 
792             const std::string* bootProgressStr =
793                 std::get_if<std::string>(&bootProgress);
794 
795             if (!bootProgressStr)
796             {
797                 // Interface implemented but property not found, return error
798                 // for that
799                 messages::internalError(aResp->res);
800                 return;
801             }
802 
803             BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
804 
805             // Now convert the D-Bus BootProgress to the appropriate Redfish
806             // enum
807             std::string rfBpLastState = "None";
808             if (*bootProgressStr ==
809                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.Unspecified")
810             {
811                 rfBpLastState = "None";
812             }
813             else if (
814                 *bootProgressStr ==
815                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.PrimaryProcInit")
816             {
817                 rfBpLastState = "PrimaryProcessorInitializationStarted";
818             }
819             else if (
820                 *bootProgressStr ==
821                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.BusInit")
822             {
823                 rfBpLastState = "BusInitializationStarted";
824             }
825             else if (
826                 *bootProgressStr ==
827                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.MemoryInit")
828             {
829                 rfBpLastState = "MemoryInitializationStarted";
830             }
831             else if (
832                 *bootProgressStr ==
833                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.SecondaryProcInit")
834             {
835                 rfBpLastState = "SecondaryProcessorInitializationStarted";
836             }
837             else if (
838                 *bootProgressStr ==
839                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.PCIInit")
840             {
841                 rfBpLastState = "PCIResourceConfigStarted";
842             }
843             else if (
844                 *bootProgressStr ==
845                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.SystemInitComplete")
846             {
847                 rfBpLastState = "SystemHardwareInitializationComplete";
848             }
849             else if (
850                 *bootProgressStr ==
851                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.OSStart")
852             {
853                 rfBpLastState = "OSBootStarted";
854             }
855             else if (
856                 *bootProgressStr ==
857                 "xyz.openbmc_project.State.Boot.Progress.ProgressStages.OSRunning")
858             {
859                 rfBpLastState = "OSRunning";
860             }
861             else
862             {
863                 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
864                                  << *bootProgressStr;
865                 // Just return the default
866             }
867 
868             aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
869         },
870         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
871         "org.freedesktop.DBus.Properties", "Get",
872         "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
873 }
874 
875 /**
876  * @brief Retrieves boot override type over DBUS and fills out the response
877  *
878  * @param[in] aResp         Shared pointer for generating response message.
879  *
880  * @return None.
881  */
882 
883 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
884 {
885     crow::connections::systemBus->async_method_call(
886         [aResp](const boost::system::error_code ec,
887                 const std::variant<std::string>& bootType) {
888             if (ec)
889             {
890                 // not an error, don't have to have the interface
891                 return;
892             }
893 
894             const std::string* bootTypeStr =
895                 std::get_if<std::string>(&bootType);
896 
897             if (!bootTypeStr)
898             {
899                 messages::internalError(aResp->res);
900                 return;
901             }
902 
903             BMCWEB_LOG_DEBUG << "Boot type: " << *bootTypeStr;
904 
905             aResp->res
906                 .jsonValue["Boot"]
907                           ["BootSourceOverrideMode@Redfish.AllowableValues"] = {
908                 "Legacy", "UEFI"};
909 
910             auto rfType = dbusToRfBootType(*bootTypeStr);
911             if (rfType.empty())
912             {
913                 messages::internalError(aResp->res);
914                 return;
915             }
916 
917             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType;
918         },
919         "xyz.openbmc_project.Settings",
920         "/xyz/openbmc_project/control/host0/boot",
921         "org.freedesktop.DBus.Properties", "Get",
922         "xyz.openbmc_project.Control.Boot.Type", "BootType");
923 }
924 
925 /**
926  * @brief Retrieves boot override mode over DBUS and fills out the response
927  *
928  * @param[in] aResp         Shared pointer for generating response message.
929  *
930  * @return None.
931  */
932 
933 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
934 {
935     crow::connections::systemBus->async_method_call(
936         [aResp](const boost::system::error_code ec,
937                 const std::variant<std::string>& bootMode) {
938             if (ec)
939             {
940                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
941                 messages::internalError(aResp->res);
942                 return;
943             }
944 
945             const std::string* bootModeStr =
946                 std::get_if<std::string>(&bootMode);
947 
948             if (!bootModeStr)
949             {
950                 messages::internalError(aResp->res);
951                 return;
952             }
953 
954             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
955 
956             aResp->res
957                 .jsonValue["Boot"]
958                           ["BootSourceOverrideTarget@Redfish.AllowableValues"] =
959                 {"None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
960 
961             if (*bootModeStr !=
962                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
963             {
964                 auto rfMode = dbusToRfBootMode(*bootModeStr);
965                 if (!rfMode.empty())
966                 {
967                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
968                         rfMode;
969                 }
970             }
971         },
972         "xyz.openbmc_project.Settings",
973         "/xyz/openbmc_project/control/host0/boot",
974         "org.freedesktop.DBus.Properties", "Get",
975         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
976 }
977 
978 /**
979  * @brief Retrieves boot override source over DBUS
980  *
981  * @param[in] aResp         Shared pointer for generating response message.
982  *
983  * @return None.
984  */
985 
986 inline void
987     getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
988 {
989     crow::connections::systemBus->async_method_call(
990         [aResp](const boost::system::error_code ec,
991                 const std::variant<std::string>& bootSource) {
992             if (ec)
993             {
994                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
995                 messages::internalError(aResp->res);
996                 return;
997             }
998 
999             const std::string* bootSourceStr =
1000                 std::get_if<std::string>(&bootSource);
1001 
1002             if (!bootSourceStr)
1003             {
1004                 messages::internalError(aResp->res);
1005                 return;
1006             }
1007             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
1008 
1009             auto rfSource = dbusToRfBootSource(*bootSourceStr);
1010             if (!rfSource.empty())
1011             {
1012                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1013                     rfSource;
1014             }
1015 
1016             // Get BootMode as BootSourceOverrideTarget is constructed
1017             // from both BootSource and BootMode
1018             getBootOverrideMode(aResp);
1019         },
1020         "xyz.openbmc_project.Settings",
1021         "/xyz/openbmc_project/control/host0/boot",
1022         "org.freedesktop.DBus.Properties", "Get",
1023         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
1024 }
1025 
1026 /**
1027  * @brief This functions abstracts all the logic behind getting a
1028  * "BootSourceOverrideEnabled" property from an overall boot override enable
1029  * state
1030  *
1031  * @param[in] aResp     Shared pointer for generating response message.
1032  *
1033  * @return None.
1034  */
1035 
1036 inline void
1037     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1038                               const bool bootOverrideEnableSetting)
1039 {
1040     if (!bootOverrideEnableSetting)
1041     {
1042         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled";
1043         return;
1044     }
1045 
1046     // If boot source override is enabled, we need to check 'one_time'
1047     // property to set a correct value for the "BootSourceOverrideEnabled"
1048     crow::connections::systemBus->async_method_call(
1049         [aResp](const boost::system::error_code ec,
1050                 const std::variant<bool>& oneTime) {
1051             if (ec)
1052             {
1053                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1054                 messages::internalError(aResp->res);
1055                 return;
1056             }
1057 
1058             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1059 
1060             if (!oneTimePtr)
1061             {
1062                 messages::internalError(aResp->res);
1063                 return;
1064             }
1065 
1066             bool oneTimeSetting = *oneTimePtr;
1067 
1068             if (oneTimeSetting)
1069             {
1070                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1071                     "Once";
1072             }
1073             else
1074             {
1075                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1076                     "Continuous";
1077             }
1078         },
1079         "xyz.openbmc_project.Settings",
1080         "/xyz/openbmc_project/control/host0/boot/one_time",
1081         "org.freedesktop.DBus.Properties", "Get",
1082         "xyz.openbmc_project.Object.Enable", "Enabled");
1083 }
1084 
1085 /**
1086  * @brief Retrieves boot override enable over DBUS
1087  *
1088  * @param[in] aResp     Shared pointer for generating response message.
1089  *
1090  * @return None.
1091  */
1092 
1093 inline void
1094     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1095 {
1096     crow::connections::systemBus->async_method_call(
1097         [aResp](const boost::system::error_code ec,
1098                 const std::variant<bool>& bootOverrideEnable) {
1099             if (ec)
1100             {
1101                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1102                 messages::internalError(aResp->res);
1103                 return;
1104             }
1105 
1106             const bool* bootOverrideEnablePtr =
1107                 std::get_if<bool>(&bootOverrideEnable);
1108 
1109             if (!bootOverrideEnablePtr)
1110             {
1111                 messages::internalError(aResp->res);
1112                 return;
1113             }
1114 
1115             processBootOverrideEnable(aResp, *bootOverrideEnablePtr);
1116         },
1117         "xyz.openbmc_project.Settings",
1118         "/xyz/openbmc_project/control/host0/boot",
1119         "org.freedesktop.DBus.Properties", "Get",
1120         "xyz.openbmc_project.Object.Enable", "Enabled");
1121 }
1122 
1123 /**
1124  * @brief Retrieves boot source override properties
1125  *
1126  * @param[in] aResp     Shared pointer for generating response message.
1127  *
1128  * @return None.
1129  */
1130 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1131 {
1132     BMCWEB_LOG_DEBUG << "Get boot information.";
1133 
1134     getBootOverrideSource(aResp);
1135     getBootOverrideType(aResp);
1136     getBootOverrideEnable(aResp);
1137 }
1138 
1139 /**
1140  * @brief Retrieves the Last Reset Time
1141  *
1142  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1143  * and power off. Even though this is the "system" Redfish object look at the
1144  * chassis D-Bus interface for the LastStateChangeTime since this has the
1145  * last power operation time.
1146  *
1147  * @param[in] aResp     Shared pointer for generating response message.
1148  *
1149  * @return None.
1150  */
1151 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1152 {
1153     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1154 
1155     crow::connections::systemBus->async_method_call(
1156         [aResp](const boost::system::error_code ec,
1157                 std::variant<uint64_t>& lastResetTime) {
1158             if (ec)
1159             {
1160                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1161                 return;
1162             }
1163 
1164             const uint64_t* lastResetTimePtr =
1165                 std::get_if<uint64_t>(&lastResetTime);
1166 
1167             if (!lastResetTimePtr)
1168             {
1169                 messages::internalError(aResp->res);
1170                 return;
1171             }
1172             // LastStateChangeTime is epoch time, in milliseconds
1173             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1174             time_t lastResetTimeStamp =
1175                 static_cast<time_t>(*lastResetTimePtr / 1000);
1176 
1177             // Convert to ISO 8601 standard
1178             aResp->res.jsonValue["LastResetTime"] =
1179                 crow::utility::getDateTime(lastResetTimeStamp);
1180         },
1181         "xyz.openbmc_project.State.Chassis",
1182         "/xyz/openbmc_project/state/chassis0",
1183         "org.freedesktop.DBus.Properties", "Get",
1184         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1185 }
1186 
1187 /**
1188  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1189  *
1190  * @param[in] aResp     Shared pointer for generating response message.
1191  *
1192  * @return None.
1193  */
1194 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1195 {
1196     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1197 
1198     crow::connections::systemBus->async_method_call(
1199         [aResp](const boost::system::error_code ec,
1200                 std::variant<bool>& autoRebootEnabled) {
1201             if (ec)
1202             {
1203                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1204                 return;
1205             }
1206 
1207             const bool* autoRebootEnabledPtr =
1208                 std::get_if<bool>(&autoRebootEnabled);
1209 
1210             if (!autoRebootEnabledPtr)
1211             {
1212                 messages::internalError(aResp->res);
1213                 return;
1214             }
1215 
1216             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1217             if (*autoRebootEnabledPtr == true)
1218             {
1219                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1220                     "RetryAttempts";
1221                 // If AutomaticRetry (AutoReboot) is enabled see how many
1222                 // attempts are left
1223                 crow::connections::systemBus->async_method_call(
1224                     [aResp](const boost::system::error_code ec2,
1225                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1226                         if (ec2)
1227                         {
1228                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1229                             return;
1230                         }
1231 
1232                         const uint32_t* autoRebootAttemptsLeftPtr =
1233                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1234 
1235                         if (!autoRebootAttemptsLeftPtr)
1236                         {
1237                             messages::internalError(aResp->res);
1238                             return;
1239                         }
1240 
1241                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1242                                          << *autoRebootAttemptsLeftPtr;
1243 
1244                         aResp->res
1245                             .jsonValue["Boot"]
1246                                       ["RemainingAutomaticRetryAttempts"] =
1247                             *autoRebootAttemptsLeftPtr;
1248                     },
1249                     "xyz.openbmc_project.State.Host",
1250                     "/xyz/openbmc_project/state/host0",
1251                     "org.freedesktop.DBus.Properties", "Get",
1252                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1253                     "AttemptsLeft");
1254             }
1255             else
1256             {
1257                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1258                     "Disabled";
1259             }
1260 
1261             // Not on D-Bus. Hardcoded here:
1262             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1263             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1264 
1265             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1266             // and RetryAttempts. OpenBMC only supports Disabled and
1267             // RetryAttempts.
1268             aResp->res
1269                 .jsonValue["Boot"]
1270                           ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1271                 "Disabled", "RetryAttempts"};
1272         },
1273         "xyz.openbmc_project.Settings",
1274         "/xyz/openbmc_project/control/host0/auto_reboot",
1275         "org.freedesktop.DBus.Properties", "Get",
1276         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1277 }
1278 
1279 /**
1280  * @brief Retrieves power restore policy over DBUS.
1281  *
1282  * @param[in] aResp     Shared pointer for generating response message.
1283  *
1284  * @return None.
1285  */
1286 inline void
1287     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1288 {
1289     BMCWEB_LOG_DEBUG << "Get power restore policy";
1290 
1291     crow::connections::systemBus->async_method_call(
1292         [aResp](const boost::system::error_code ec,
1293                 std::variant<std::string>& policy) {
1294             if (ec)
1295             {
1296                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1297                 return;
1298             }
1299 
1300             const boost::container::flat_map<std::string, std::string> policyMaps = {
1301                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1302                  "AlwaysOn"},
1303                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1304                  "AlwaysOff"},
1305                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1306                  "LastState"}};
1307 
1308             const std::string* policyPtr = std::get_if<std::string>(&policy);
1309 
1310             if (!policyPtr)
1311             {
1312                 messages::internalError(aResp->res);
1313                 return;
1314             }
1315 
1316             auto policyMapsIt = policyMaps.find(*policyPtr);
1317             if (policyMapsIt == policyMaps.end())
1318             {
1319                 messages::internalError(aResp->res);
1320                 return;
1321             }
1322 
1323             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1324         },
1325         "xyz.openbmc_project.Settings",
1326         "/xyz/openbmc_project/control/host0/power_restore_policy",
1327         "org.freedesktop.DBus.Properties", "Get",
1328         "xyz.openbmc_project.Control.Power.RestorePolicy",
1329         "PowerRestorePolicy");
1330 }
1331 
1332 /**
1333  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1334  * TPM is required for booting the host.
1335  *
1336  * @param[in] aResp     Shared pointer for generating response message.
1337  *
1338  * @return None.
1339  */
1340 inline void getTrustedModuleRequiredToBoot(
1341     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1342 {
1343     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1344 
1345     crow::connections::systemBus->async_method_call(
1346         [aResp](
1347             const boost::system::error_code ec,
1348             std::vector<std::pair<
1349                 std::string,
1350                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1351                 subtree) {
1352             if (ec)
1353             {
1354                 BMCWEB_LOG_DEBUG
1355                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1356                 // This is an optional D-Bus object so just return if
1357                 // error occurs
1358                 return;
1359             }
1360             if (subtree.size() == 0)
1361             {
1362                 // As noted above, this is an optional interface so just return
1363                 // if there is no instance found
1364                 return;
1365             }
1366 
1367             /* When there is more than one TPMEnable object... */
1368             if (subtree.size() > 1)
1369             {
1370                 BMCWEB_LOG_DEBUG
1371                     << "DBUS response has more than 1 TPM Enable object:"
1372                     << subtree.size();
1373                 // Throw an internal Error and return
1374                 messages::internalError(aResp->res);
1375                 return;
1376             }
1377 
1378             // Make sure the Dbus response map has a service and objectPath
1379             // field
1380             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1381             {
1382                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1383                 messages::internalError(aResp->res);
1384                 return;
1385             }
1386 
1387             const std::string& path = subtree[0].first;
1388             const std::string& serv = subtree[0].second.begin()->first;
1389 
1390             // Valid TPM Enable object found, now reading the current value
1391             crow::connections::systemBus->async_method_call(
1392                 [aResp](const boost::system::error_code ec,
1393                         std::variant<bool>& tpmRequired) {
1394                     if (ec)
1395                     {
1396                         BMCWEB_LOG_DEBUG
1397                             << "D-BUS response error on TPM.Policy Get" << ec;
1398                         messages::internalError(aResp->res);
1399                         return;
1400                     }
1401 
1402                     const bool* tpmRequiredVal =
1403                         std::get_if<bool>(&tpmRequired);
1404 
1405                     if (!tpmRequiredVal)
1406                     {
1407                         messages::internalError(aResp->res);
1408                         return;
1409                     }
1410 
1411                     if (*tpmRequiredVal == true)
1412                     {
1413                         aResp->res
1414                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1415                             "Required";
1416                     }
1417                     else
1418                     {
1419                         aResp->res
1420                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1421                             "Disabled";
1422                     }
1423                 },
1424                 serv, path, "org.freedesktop.DBus.Properties", "Get",
1425                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable");
1426         },
1427         "xyz.openbmc_project.ObjectMapper",
1428         "/xyz/openbmc_project/object_mapper",
1429         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1430         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1431 }
1432 
1433 /**
1434  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1435  * TPM is required for booting the host.
1436  *
1437  * @param[in] aResp         Shared pointer for generating response message.
1438  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1439  *
1440  * @return None.
1441  */
1442 inline void setTrustedModuleRequiredToBoot(
1443     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1444 {
1445     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1446 
1447     crow::connections::systemBus->async_method_call(
1448         [aResp, tpmRequired](
1449             const boost::system::error_code ec,
1450             std::vector<std::pair<
1451                 std::string,
1452                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1453                 subtree) {
1454             if (ec)
1455             {
1456                 BMCWEB_LOG_DEBUG
1457                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1458                 messages::internalError(aResp->res);
1459                 return;
1460             }
1461             if (subtree.size() == 0)
1462             {
1463                 messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1464                                                  "TrustedModuleRequiredToBoot");
1465                 return;
1466             }
1467 
1468             /* When there is more than one TPMEnable object... */
1469             if (subtree.size() > 1)
1470             {
1471                 BMCWEB_LOG_DEBUG
1472                     << "DBUS response has more than 1 TPM Enable object:"
1473                     << subtree.size();
1474                 // Throw an internal Error and return
1475                 messages::internalError(aResp->res);
1476                 return;
1477             }
1478 
1479             // Make sure the Dbus response map has a service and objectPath
1480             // field
1481             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1482             {
1483                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1484                 messages::internalError(aResp->res);
1485                 return;
1486             }
1487 
1488             const std::string& path = subtree[0].first;
1489             const std::string& serv = subtree[0].second.begin()->first;
1490 
1491             if (serv.empty())
1492             {
1493                 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1494                 messages::internalError(aResp->res);
1495                 return;
1496             }
1497 
1498             // Valid TPM Enable object found, now setting the value
1499             crow::connections::systemBus->async_method_call(
1500                 [aResp](const boost::system::error_code ec) {
1501                     if (ec)
1502                     {
1503                         BMCWEB_LOG_DEBUG
1504                             << "DBUS response error: Set TrustedModuleRequiredToBoot"
1505                             << ec;
1506                         messages::internalError(aResp->res);
1507                         return;
1508                     }
1509                     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1510                 },
1511                 serv, path, "org.freedesktop.DBus.Properties", "Set",
1512                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1513                 std::variant<bool>(tpmRequired));
1514         },
1515         "xyz.openbmc_project.ObjectMapper",
1516         "/xyz/openbmc_project/object_mapper",
1517         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1518         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1519 }
1520 
1521 /**
1522  * @brief Sets boot properties into DBUS object(s).
1523  *
1524  * @param[in] aResp           Shared pointer for generating response message.
1525  * @param[in] bootType        The boot type to set.
1526  * @return Integer error code.
1527  */
1528 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1529                         const std::optional<std::string>& bootType)
1530 {
1531     std::string bootTypeStr;
1532 
1533     if (!bootType)
1534     {
1535         return;
1536     }
1537 
1538     // Source target specified
1539     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1540     // Figure out which DBUS interface and property to use
1541     if (*bootType == "Legacy")
1542     {
1543         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1544     }
1545     else if (*bootType == "UEFI")
1546     {
1547         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1548     }
1549     else
1550     {
1551         BMCWEB_LOG_DEBUG << "Invalid property value for "
1552                             "BootSourceOverrideMode: "
1553                          << *bootType;
1554         messages::propertyValueNotInList(aResp->res, *bootType,
1555                                          "BootSourceOverrideMode");
1556         return;
1557     }
1558 
1559     // Act on validated parameters
1560     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1561 
1562     crow::connections::systemBus->async_method_call(
1563         [aResp](const boost::system::error_code ec) {
1564             if (ec)
1565             {
1566                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1567                 if (ec.value() == boost::asio::error::host_unreachable)
1568                 {
1569                     messages::resourceNotFound(aResp->res, "Set", "BootType");
1570                     return;
1571                 }
1572                 messages::internalError(aResp->res);
1573                 return;
1574             }
1575             BMCWEB_LOG_DEBUG << "Boot type update done.";
1576         },
1577         "xyz.openbmc_project.Settings",
1578         "/xyz/openbmc_project/control/host0/boot",
1579         "org.freedesktop.DBus.Properties", "Set",
1580         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1581         std::variant<std::string>(bootTypeStr));
1582 }
1583 
1584 /**
1585  * @brief Sets boot properties into DBUS object(s).
1586  *
1587  * @param[in] aResp           Shared pointer for generating response message.
1588  * @param[in] bootType        The boot type to set.
1589  * @return Integer error code.
1590  */
1591 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1592                           const std::optional<std::string>& bootEnable)
1593 {
1594     if (!bootEnable)
1595     {
1596         return;
1597     }
1598     // Source target specified
1599     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1600 
1601     bool bootOverrideEnable = false;
1602     bool bootOverridePersistent = false;
1603     // Figure out which DBUS interface and property to use
1604     if (*bootEnable == "Disabled")
1605     {
1606         bootOverrideEnable = false;
1607     }
1608     else if (*bootEnable == "Once")
1609     {
1610         bootOverrideEnable = true;
1611         bootOverridePersistent = false;
1612     }
1613     else if (*bootEnable == "Continuous")
1614     {
1615         bootOverrideEnable = true;
1616         bootOverridePersistent = true;
1617     }
1618     else
1619     {
1620         BMCWEB_LOG_DEBUG
1621             << "Invalid property value for BootSourceOverrideEnabled: "
1622             << *bootEnable;
1623         messages::propertyValueNotInList(aResp->res, *bootEnable,
1624                                          "BootSourceOverrideEnabled");
1625         return;
1626     }
1627 
1628     // Act on validated parameters
1629     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1630 
1631     crow::connections::systemBus->async_method_call(
1632         [aResp](const boost::system::error_code ec) {
1633             if (ec)
1634             {
1635                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1636                 messages::internalError(aResp->res);
1637                 return;
1638             }
1639             BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1640         },
1641         "xyz.openbmc_project.Settings",
1642         "/xyz/openbmc_project/control/host0/boot",
1643         "org.freedesktop.DBus.Properties", "Set",
1644         "xyz.openbmc_project.Object.Enable", "Enabled",
1645         std::variant<bool>(bootOverrideEnable));
1646 
1647     if (!bootOverrideEnable)
1648     {
1649         return;
1650     }
1651 
1652     // In case boot override is enabled we need to set correct value for the
1653     // 'one_time' enable DBus interface
1654     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1655                      << bootOverridePersistent;
1656 
1657     crow::connections::systemBus->async_method_call(
1658         [aResp](const boost::system::error_code ec) {
1659             if (ec)
1660             {
1661                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1662                 messages::internalError(aResp->res);
1663                 return;
1664             }
1665             BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1666         },
1667         "xyz.openbmc_project.Settings",
1668         "/xyz/openbmc_project/control/host0/boot/one_time",
1669         "org.freedesktop.DBus.Properties", "Set",
1670         "xyz.openbmc_project.Object.Enable", "Enabled",
1671         std::variant<bool>(!bootOverridePersistent));
1672 }
1673 
1674 /**
1675  * @brief Sets boot properties into DBUS object(s).
1676  *
1677  * @param[in] aResp           Shared pointer for generating response message.
1678  * @param[in] bootSource      The boot source to set.
1679  *
1680  * @return Integer error code.
1681  */
1682 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1683                                 const std::optional<std::string>& bootSource)
1684 {
1685     std::string bootSourceStr;
1686     std::string bootModeStr;
1687 
1688     if (!bootSource)
1689     {
1690         return;
1691     }
1692 
1693     // Source target specified
1694     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1695     // Figure out which DBUS interface and property to use
1696     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr))
1697     {
1698         BMCWEB_LOG_DEBUG
1699             << "Invalid property value for BootSourceOverrideTarget: "
1700             << *bootSource;
1701         messages::propertyValueNotInList(aResp->res, *bootSource,
1702                                          "BootSourceTargetOverride");
1703         return;
1704     }
1705 
1706     // Act on validated parameters
1707     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1708     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1709 
1710     crow::connections::systemBus->async_method_call(
1711         [aResp](const boost::system::error_code ec) {
1712             if (ec)
1713             {
1714                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1715                 messages::internalError(aResp->res);
1716                 return;
1717             }
1718             BMCWEB_LOG_DEBUG << "Boot source update done.";
1719         },
1720         "xyz.openbmc_project.Settings",
1721         "/xyz/openbmc_project/control/host0/boot",
1722         "org.freedesktop.DBus.Properties", "Set",
1723         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1724         std::variant<std::string>(bootSourceStr));
1725 
1726     crow::connections::systemBus->async_method_call(
1727         [aResp](const boost::system::error_code ec) {
1728             if (ec)
1729             {
1730                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1731                 messages::internalError(aResp->res);
1732                 return;
1733             }
1734             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1735         },
1736         "xyz.openbmc_project.Settings",
1737         "/xyz/openbmc_project/control/host0/boot",
1738         "org.freedesktop.DBus.Properties", "Set",
1739         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1740         std::variant<std::string>(bootModeStr));
1741 }
1742 
1743 /**
1744  * @brief Sets Boot source override properties.
1745  *
1746  * @param[in] aResp      Shared pointer for generating response message.
1747  * @param[in] bootSource The boot source from incoming RF request.
1748  * @param[in] bootType   The boot type from incoming RF request.
1749  * @param[in] bootEnable The boot override enable from incoming RF request.
1750  *
1751  * @return Integer error code.
1752  */
1753 
1754 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1755                               const std::optional<std::string>& bootSource,
1756                               const std::optional<std::string>& bootType,
1757                               const std::optional<std::string>& bootEnable)
1758 {
1759     BMCWEB_LOG_DEBUG << "Set boot information.";
1760 
1761     setBootModeOrSource(aResp, bootSource);
1762     setBootType(aResp, bootType);
1763     setBootEnable(aResp, bootEnable);
1764 }
1765 
1766 /**
1767  * @brief Sets AssetTag
1768  *
1769  * @param[in] aResp   Shared pointer for generating response message.
1770  * @param[in] assetTag  "AssetTag" from request.
1771  *
1772  * @return None.
1773  */
1774 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1775                         const std::string& assetTag)
1776 {
1777     crow::connections::systemBus->async_method_call(
1778         [aResp, assetTag](
1779             const boost::system::error_code ec,
1780             const std::vector<std::pair<
1781                 std::string,
1782                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1783                 subtree) {
1784             if (ec)
1785             {
1786                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1787                 messages::internalError(aResp->res);
1788                 return;
1789             }
1790             if (subtree.size() == 0)
1791             {
1792                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1793                 messages::internalError(aResp->res);
1794                 return;
1795             }
1796             // Assume only 1 system D-Bus object
1797             // Throw an error if there is more than 1
1798             if (subtree.size() > 1)
1799             {
1800                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1801                 messages::internalError(aResp->res);
1802                 return;
1803             }
1804             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1805             {
1806                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1807                 messages::internalError(aResp->res);
1808                 return;
1809             }
1810 
1811             const std::string& path = subtree[0].first;
1812             const std::string& service = subtree[0].second.begin()->first;
1813 
1814             if (service.empty())
1815             {
1816                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1817                 messages::internalError(aResp->res);
1818                 return;
1819             }
1820 
1821             crow::connections::systemBus->async_method_call(
1822                 [aResp](const boost::system::error_code ec2) {
1823                     if (ec2)
1824                     {
1825                         BMCWEB_LOG_DEBUG
1826                             << "D-Bus response error on AssetTag Set " << ec2;
1827                         messages::internalError(aResp->res);
1828                         return;
1829                     }
1830                 },
1831                 service, path, "org.freedesktop.DBus.Properties", "Set",
1832                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1833                 std::variant<std::string>(assetTag));
1834         },
1835         "xyz.openbmc_project.ObjectMapper",
1836         "/xyz/openbmc_project/object_mapper",
1837         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1838         "/xyz/openbmc_project/inventory", int32_t(0),
1839         std::array<const char*, 1>{
1840             "xyz.openbmc_project.Inventory.Item.System"});
1841 }
1842 
1843 /**
1844  * @brief Sets automaticRetry (Auto Reboot)
1845  *
1846  * @param[in] aResp   Shared pointer for generating response message.
1847  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1848  *
1849  * @return None.
1850  */
1851 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1852                               const std::string& automaticRetryConfig)
1853 {
1854     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1855 
1856     // OpenBMC only supports "Disabled" and "RetryAttempts".
1857     bool autoRebootEnabled;
1858 
1859     if (automaticRetryConfig == "Disabled")
1860     {
1861         autoRebootEnabled = false;
1862     }
1863     else if (automaticRetryConfig == "RetryAttempts")
1864     {
1865         autoRebootEnabled = true;
1866     }
1867     else
1868     {
1869         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1870                          << automaticRetryConfig;
1871         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1872                                          "AutomaticRetryConfig");
1873         return;
1874     }
1875 
1876     crow::connections::systemBus->async_method_call(
1877         [aResp](const boost::system::error_code ec) {
1878             if (ec)
1879             {
1880                 messages::internalError(aResp->res);
1881                 return;
1882             }
1883         },
1884         "xyz.openbmc_project.Settings",
1885         "/xyz/openbmc_project/control/host0/auto_reboot",
1886         "org.freedesktop.DBus.Properties", "Set",
1887         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1888         std::variant<bool>(autoRebootEnabled));
1889 }
1890 
1891 /**
1892  * @brief Sets power restore policy properties.
1893  *
1894  * @param[in] aResp   Shared pointer for generating response message.
1895  * @param[in] policy  power restore policy properties from request.
1896  *
1897  * @return None.
1898  */
1899 inline void
1900     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1901                           const std::string& policy)
1902 {
1903     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1904 
1905     const boost::container::flat_map<std::string, std::string> policyMaps = {
1906         {"AlwaysOn",
1907          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1908         {"AlwaysOff",
1909          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1910         {"LastState",
1911          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1912 
1913     std::string powerRestorPolicy;
1914 
1915     auto policyMapsIt = policyMaps.find(policy);
1916     if (policyMapsIt == policyMaps.end())
1917     {
1918         messages::propertyValueNotInList(aResp->res, policy,
1919                                          "PowerRestorePolicy");
1920         return;
1921     }
1922 
1923     powerRestorPolicy = policyMapsIt->second;
1924 
1925     crow::connections::systemBus->async_method_call(
1926         [aResp](const boost::system::error_code ec) {
1927             if (ec)
1928             {
1929                 messages::internalError(aResp->res);
1930                 return;
1931             }
1932         },
1933         "xyz.openbmc_project.Settings",
1934         "/xyz/openbmc_project/control/host0/power_restore_policy",
1935         "org.freedesktop.DBus.Properties", "Set",
1936         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1937         std::variant<std::string>(powerRestorPolicy));
1938 }
1939 
1940 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1941 /**
1942  * @brief Retrieves provisioning status
1943  *
1944  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1945  *
1946  * @return None.
1947  */
1948 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1949 {
1950     BMCWEB_LOG_DEBUG << "Get OEM information.";
1951     crow::connections::systemBus->async_method_call(
1952         [aResp](const boost::system::error_code ec,
1953                 const std::vector<std::pair<std::string, VariantType>>&
1954                     propertiesList) {
1955             nlohmann::json& oemPFR =
1956                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1957             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1958                 "#OemComputerSystem.OpenBmc";
1959             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1960 
1961             if (ec)
1962             {
1963                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1964                 // not an error, don't have to have the interface
1965                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1966                 return;
1967             }
1968 
1969             const bool* provState = nullptr;
1970             const bool* lockState = nullptr;
1971             for (const std::pair<std::string, VariantType>& property :
1972                  propertiesList)
1973             {
1974                 if (property.first == "UfmProvisioned")
1975                 {
1976                     provState = std::get_if<bool>(&property.second);
1977                 }
1978                 else if (property.first == "UfmLocked")
1979                 {
1980                     lockState = std::get_if<bool>(&property.second);
1981                 }
1982             }
1983 
1984             if ((provState == nullptr) || (lockState == nullptr))
1985             {
1986                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1987                 messages::internalError(aResp->res);
1988                 return;
1989             }
1990 
1991             if (*provState == true)
1992             {
1993                 if (*lockState == true)
1994                 {
1995                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1996                 }
1997                 else
1998                 {
1999                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
2000                 }
2001             }
2002             else
2003             {
2004                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
2005             }
2006         },
2007         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
2008         "org.freedesktop.DBus.Properties", "GetAll",
2009         "xyz.openbmc_project.PFR.Attributes");
2010 }
2011 #endif
2012 
2013 /**
2014  * @brief Translate the PowerMode to a response message.
2015  *
2016  * @param[in] aResp  Shared pointer for generating response message.
2017  * @param[in] modeValue  PowerMode value to be translated
2018  *
2019  * @return None.
2020  */
2021 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2022                                const std::string& modeValue)
2023 {
2024     std::string modeString;
2025 
2026     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
2027     {
2028         aResp->res.jsonValue["PowerMode"] = "Static";
2029     }
2030     else if (
2031         modeValue ==
2032         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
2033     {
2034         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
2035     }
2036     else if (modeValue ==
2037              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
2038     {
2039         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
2040     }
2041     else if (modeValue ==
2042              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
2043     {
2044         aResp->res.jsonValue["PowerMode"] = "OEM";
2045     }
2046     else
2047     {
2048         // Any other values would be invalid
2049         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
2050         messages::internalError(aResp->res);
2051     }
2052 }
2053 
2054 /**
2055  * @brief Retrieves system power mode
2056  *
2057  * @param[in] aResp  Shared pointer for generating response message.
2058  *
2059  * @return None.
2060  */
2061 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2062 {
2063     BMCWEB_LOG_DEBUG << "Get power mode.";
2064 
2065     // Get Power Mode object path:
2066     crow::connections::systemBus->async_method_call(
2067         [aResp](
2068             const boost::system::error_code ec,
2069             const std::vector<std::pair<
2070                 std::string,
2071                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2072                 subtree) {
2073             if (ec)
2074             {
2075                 BMCWEB_LOG_DEBUG
2076                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2077                 // This is an optional D-Bus object so just return if
2078                 // error occurs
2079                 return;
2080             }
2081             if (subtree.empty())
2082             {
2083                 // As noted above, this is an optional interface so just return
2084                 // if there is no instance found
2085                 return;
2086             }
2087             if (subtree.size() > 1)
2088             {
2089                 // More then one PowerMode object is not supported and is an
2090                 // error
2091                 BMCWEB_LOG_DEBUG
2092                     << "Found more than 1 system D-Bus Power.Mode objects: "
2093                     << subtree.size();
2094                 messages::internalError(aResp->res);
2095                 return;
2096             }
2097             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2098             {
2099                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2100                 messages::internalError(aResp->res);
2101                 return;
2102             }
2103             const std::string& path = subtree[0].first;
2104             const std::string& service = subtree[0].second.begin()->first;
2105             if (service.empty())
2106             {
2107                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2108                 messages::internalError(aResp->res);
2109                 return;
2110             }
2111             // Valid Power Mode object found, now read the current value
2112             crow::connections::systemBus->async_method_call(
2113                 [aResp](const boost::system::error_code ec,
2114                         const std::variant<std::string>& pmode) {
2115                     if (ec)
2116                     {
2117                         BMCWEB_LOG_DEBUG
2118                             << "DBUS response error on PowerMode Get: " << ec;
2119                         messages::internalError(aResp->res);
2120                         return;
2121                     }
2122 
2123                     const std::string* s = std::get_if<std::string>(&pmode);
2124                     if (s == nullptr)
2125                     {
2126                         BMCWEB_LOG_DEBUG << "Unable to get PowerMode value";
2127                         messages::internalError(aResp->res);
2128                         return;
2129                     }
2130 
2131                     aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] =
2132                         {"Static", "MaximumPerformance", "PowerSaving"};
2133 
2134                     BMCWEB_LOG_DEBUG << "Current power mode: " << *s;
2135                     translatePowerMode(aResp, *s);
2136                 },
2137                 service, path, "org.freedesktop.DBus.Properties", "Get",
2138                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode");
2139         },
2140         "xyz.openbmc_project.ObjectMapper",
2141         "/xyz/openbmc_project/object_mapper",
2142         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2143         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2144 }
2145 
2146 /**
2147  * @brief Validate the specified mode is valid and return the PowerMode
2148  * name associated with that string
2149  *
2150  * @param[in] aResp   Shared pointer for generating response message.
2151  * @param[in] modeString  String representing the desired PowerMode
2152  *
2153  * @return PowerMode value or empty string if mode is not valid
2154  */
2155 inline std::string
2156     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2157                       const std::string& modeString)
2158 {
2159     std::string mode;
2160 
2161     if (modeString == "Static")
2162     {
2163         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2164     }
2165     else if (modeString == "MaximumPerformance")
2166     {
2167         mode =
2168             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2169     }
2170     else if (modeString == "PowerSaving")
2171     {
2172         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2173     }
2174     else
2175     {
2176         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2177     }
2178     return mode;
2179 }
2180 
2181 /**
2182  * @brief Sets system power mode.
2183  *
2184  * @param[in] aResp   Shared pointer for generating response message.
2185  * @param[in] pmode   System power mode from request.
2186  *
2187  * @return None.
2188  */
2189 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2190                          const std::string& pmode)
2191 {
2192     BMCWEB_LOG_DEBUG << "Set power mode.";
2193 
2194     std::string powerMode = validatePowerMode(aResp, pmode);
2195     if (powerMode.empty())
2196     {
2197         return;
2198     }
2199 
2200     // Get Power Mode object path:
2201     crow::connections::systemBus->async_method_call(
2202         [aResp, powerMode](
2203             const boost::system::error_code ec,
2204             const std::vector<std::pair<
2205                 std::string,
2206                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2207                 subtree) {
2208             if (ec)
2209             {
2210                 BMCWEB_LOG_DEBUG
2211                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2212                 // This is an optional D-Bus object, but user attempted to patch
2213                 messages::internalError(aResp->res);
2214                 return;
2215             }
2216             if (subtree.empty())
2217             {
2218                 // This is an optional D-Bus object, but user attempted to patch
2219                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2220                                            "PowerMode");
2221                 return;
2222             }
2223             if (subtree.size() > 1)
2224             {
2225                 // More then one PowerMode object is not supported and is an
2226                 // error
2227                 BMCWEB_LOG_DEBUG
2228                     << "Found more than 1 system D-Bus Power.Mode objects: "
2229                     << subtree.size();
2230                 messages::internalError(aResp->res);
2231                 return;
2232             }
2233             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2234             {
2235                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2236                 messages::internalError(aResp->res);
2237                 return;
2238             }
2239             const std::string& path = subtree[0].first;
2240             const std::string& service = subtree[0].second.begin()->first;
2241             if (service.empty())
2242             {
2243                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2244                 messages::internalError(aResp->res);
2245                 return;
2246             }
2247 
2248             BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2249                              << path;
2250 
2251             // Set the Power Mode property
2252             crow::connections::systemBus->async_method_call(
2253                 [aResp](const boost::system::error_code ec) {
2254                     if (ec)
2255                     {
2256                         messages::internalError(aResp->res);
2257                         return;
2258                     }
2259                 },
2260                 service, path, "org.freedesktop.DBus.Properties", "Set",
2261                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2262                 std::variant<std::string>(powerMode));
2263         },
2264         "xyz.openbmc_project.ObjectMapper",
2265         "/xyz/openbmc_project/object_mapper",
2266         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2267         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2268 }
2269 
2270 /**
2271  * @brief Translates watchdog timeout action DBUS property value to redfish.
2272  *
2273  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2274  *
2275  * @return Returns as a string, the timeout action in Redfish terms. If
2276  * translation cannot be done, returns an empty string.
2277  */
2278 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2279 {
2280     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2281     {
2282         return "None";
2283     }
2284     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2285     {
2286         return "ResetSystem";
2287     }
2288     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2289     {
2290         return "PowerDown";
2291     }
2292     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2293     {
2294         return "PowerCycle";
2295     }
2296 
2297     return "";
2298 }
2299 
2300 /**
2301  *@brief Translates timeout action from Redfish to DBUS property value.
2302  *
2303  *@param[in] rfAction The timeout action in Redfish.
2304  *
2305  *@return Returns as a string, the time_out action as expected by DBUS.
2306  *If translation cannot be done, returns an empty string.
2307  */
2308 
2309 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2310 {
2311     if (rfAction == "None")
2312     {
2313         return "xyz.openbmc_project.State.Watchdog.Action.None";
2314     }
2315     if (rfAction == "PowerCycle")
2316     {
2317         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2318     }
2319     if (rfAction == "PowerDown")
2320     {
2321         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2322     }
2323     if (rfAction == "ResetSystem")
2324     {
2325         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2326     }
2327 
2328     return "";
2329 }
2330 
2331 /**
2332  * @brief Retrieves host watchdog timer properties over DBUS
2333  *
2334  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2335  *
2336  * @return None.
2337  */
2338 inline void
2339     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2340 {
2341     BMCWEB_LOG_DEBUG << "Get host watchodg";
2342     crow::connections::systemBus->async_method_call(
2343         [aResp](const boost::system::error_code ec,
2344                 PropertiesType& properties) {
2345             if (ec)
2346             {
2347                 // watchdog service is stopped
2348                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2349                 return;
2350             }
2351 
2352             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2353 
2354             nlohmann::json& hostWatchdogTimer =
2355                 aResp->res.jsonValue["HostWatchdogTimer"];
2356 
2357             // watchdog service is running/enabled
2358             hostWatchdogTimer["Status"]["State"] = "Enabled";
2359 
2360             for (const auto& property : properties)
2361             {
2362                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
2363                 if (property.first == "Enabled")
2364                 {
2365                     const bool* state = std::get_if<bool>(&property.second);
2366 
2367                     if (!state)
2368                     {
2369                         messages::internalError(aResp->res);
2370                         return;
2371                     }
2372 
2373                     hostWatchdogTimer["FunctionEnabled"] = *state;
2374                 }
2375                 else if (property.first == "ExpireAction")
2376                 {
2377                     const std::string* s =
2378                         std::get_if<std::string>(&property.second);
2379                     if (!s)
2380                     {
2381                         messages::internalError(aResp->res);
2382                         return;
2383                     }
2384 
2385                     std::string action = dbusToRfWatchdogAction(*s);
2386                     if (action.empty())
2387                     {
2388                         messages::internalError(aResp->res);
2389                         return;
2390                     }
2391                     hostWatchdogTimer["TimeoutAction"] = action;
2392                 }
2393             }
2394         },
2395         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2396         "org.freedesktop.DBus.Properties", "GetAll",
2397         "xyz.openbmc_project.State.Watchdog");
2398 }
2399 
2400 /**
2401  * @brief Sets Host WatchDog Timer properties.
2402  *
2403  * @param[in] aResp      Shared pointer for generating response message.
2404  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2405  *                       RF request.
2406  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2407  *
2408  * @return None.
2409  */
2410 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2411                              const std::optional<bool> wdtEnable,
2412                              const std::optional<std::string>& wdtTimeOutAction)
2413 {
2414     BMCWEB_LOG_DEBUG << "Set host watchdog";
2415 
2416     if (wdtTimeOutAction)
2417     {
2418         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2419         // check if TimeOut Action is Valid
2420         if (wdtTimeOutActStr.empty())
2421         {
2422             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2423                              << *wdtTimeOutAction;
2424             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2425                                              "TimeoutAction");
2426             return;
2427         }
2428 
2429         crow::connections::systemBus->async_method_call(
2430             [aResp](const boost::system::error_code ec) {
2431                 if (ec)
2432                 {
2433                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2434                     messages::internalError(aResp->res);
2435                     return;
2436                 }
2437             },
2438             "xyz.openbmc_project.Watchdog",
2439             "/xyz/openbmc_project/watchdog/host0",
2440             "org.freedesktop.DBus.Properties", "Set",
2441             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2442             std::variant<std::string>(wdtTimeOutActStr));
2443     }
2444 
2445     if (wdtEnable)
2446     {
2447         crow::connections::systemBus->async_method_call(
2448             [aResp](const boost::system::error_code ec) {
2449                 if (ec)
2450                 {
2451                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2452                     messages::internalError(aResp->res);
2453                     return;
2454                 }
2455             },
2456             "xyz.openbmc_project.Watchdog",
2457             "/xyz/openbmc_project/watchdog/host0",
2458             "org.freedesktop.DBus.Properties", "Set",
2459             "xyz.openbmc_project.State.Watchdog", "Enabled",
2460             std::variant<bool>(*wdtEnable));
2461     }
2462 }
2463 
2464 using ipsPropertiesType =
2465     std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
2466 /**
2467  * @brief Parse the Idle Power Saver properties into json
2468  *
2469  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2470  * @param[in] properties  IPS property data from DBus.
2471  *
2472  * @return true if successful
2473  */
2474 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2475                                ipsPropertiesType& properties)
2476 {
2477     for (const auto& property : properties)
2478     {
2479         if (property.first == "Enabled")
2480         {
2481             const bool* state = std::get_if<bool>(&property.second);
2482             if (!state)
2483             {
2484                 return false;
2485             }
2486             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state;
2487         }
2488         else if (property.first == "EnterUtilizationPercent")
2489         {
2490             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2491             if (!util)
2492             {
2493                 return false;
2494             }
2495             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2496         }
2497         else if (property.first == "EnterDwellTime")
2498         {
2499             // Convert Dbus time from milliseconds to seconds
2500             const uint64_t* timeMilliseconds =
2501                 std::get_if<uint64_t>(&property.second);
2502             if (!timeMilliseconds)
2503             {
2504                 return false;
2505             }
2506             const std::chrono::duration<uint64_t, std::milli> ms(
2507                 *timeMilliseconds);
2508             aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2509                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2510                     .count();
2511         }
2512         else if (property.first == "ExitUtilizationPercent")
2513         {
2514             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2515             if (!util)
2516             {
2517                 return false;
2518             }
2519             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2520         }
2521         else if (property.first == "ExitDwellTime")
2522         {
2523             // Convert Dbus time from milliseconds to seconds
2524             const uint64_t* timeMilliseconds =
2525                 std::get_if<uint64_t>(&property.second);
2526             if (!timeMilliseconds)
2527             {
2528                 return false;
2529             }
2530             const std::chrono::duration<uint64_t, std::milli> ms(
2531                 *timeMilliseconds);
2532             aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2533                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2534                     .count();
2535         }
2536         else
2537         {
2538             BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: "
2539                                << property.first;
2540         }
2541     }
2542 
2543     return true;
2544 }
2545 
2546 /**
2547  * @brief Retrieves host watchdog timer properties over DBUS
2548  *
2549  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2550  *
2551  * @return None.
2552  */
2553 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2554 {
2555     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2556 
2557     // Get IdlePowerSaver object path:
2558     crow::connections::systemBus->async_method_call(
2559         [aResp](
2560             const boost::system::error_code ec,
2561             const std::vector<std::pair<
2562                 std::string,
2563                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2564                 subtree) {
2565             if (ec)
2566             {
2567                 BMCWEB_LOG_DEBUG
2568                     << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2569                     << ec;
2570                 messages::internalError(aResp->res);
2571                 return;
2572             }
2573             if (subtree.empty())
2574             {
2575                 // This is an optional interface so just return
2576                 // if there is no instance found
2577                 BMCWEB_LOG_DEBUG << "No instances found";
2578                 return;
2579             }
2580             if (subtree.size() > 1)
2581             {
2582                 // More then one PowerIdlePowerSaver object is not supported and
2583                 // is an error
2584                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2585                                     "Power.IdlePowerSaver objects: "
2586                                  << subtree.size();
2587                 messages::internalError(aResp->res);
2588                 return;
2589             }
2590             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2591             {
2592                 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2593                 messages::internalError(aResp->res);
2594                 return;
2595             }
2596             const std::string& path = subtree[0].first;
2597             const std::string& service = subtree[0].second.begin()->first;
2598             if (service.empty())
2599             {
2600                 BMCWEB_LOG_DEBUG
2601                     << "Power.IdlePowerSaver service mapper error!";
2602                 messages::internalError(aResp->res);
2603                 return;
2604             }
2605 
2606             // Valid IdlePowerSaver object found, now read the current values
2607             crow::connections::systemBus->async_method_call(
2608                 [aResp](const boost::system::error_code ec,
2609                         ipsPropertiesType& properties) {
2610                     if (ec)
2611                     {
2612                         BMCWEB_LOG_ERROR
2613                             << "DBUS response error on IdlePowerSaver GetAll: "
2614                             << ec;
2615                         messages::internalError(aResp->res);
2616                         return;
2617                     }
2618 
2619                     if (parseIpsProperties(aResp, properties) == false)
2620                     {
2621                         messages::internalError(aResp->res);
2622                         return;
2623                     }
2624                 },
2625                 service, path, "org.freedesktop.DBus.Properties", "GetAll",
2626                 "xyz.openbmc_project.Control.Power.IdlePowerSaver");
2627         },
2628         "xyz.openbmc_project.ObjectMapper",
2629         "/xyz/openbmc_project/object_mapper",
2630         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2631         std::array<const char*, 1>{
2632             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2633 
2634     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2635 }
2636 
2637 /**
2638  * @brief Sets Idle Power Saver properties.
2639  *
2640  * @param[in] aResp      Shared pointer for generating response message.
2641  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2642  *                       RF request.
2643  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2644  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2645  * before entering idle state.
2646  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2647  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2648  * before exiting idle state
2649  *
2650  * @return None.
2651  */
2652 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2653                               const std::optional<bool> ipsEnable,
2654                               const std::optional<uint8_t> ipsEnterUtil,
2655                               const std::optional<uint64_t> ipsEnterTime,
2656                               const std::optional<uint8_t> ipsExitUtil,
2657                               const std::optional<uint64_t> ipsExitTime)
2658 {
2659     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2660 
2661     // Get IdlePowerSaver object path:
2662     crow::connections::systemBus->async_method_call(
2663         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2664          ipsExitTime](
2665             const boost::system::error_code ec,
2666             const std::vector<std::pair<
2667                 std::string,
2668                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2669                 subtree) {
2670             if (ec)
2671             {
2672                 BMCWEB_LOG_DEBUG
2673                     << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2674                     << ec;
2675                 messages::internalError(aResp->res);
2676                 return;
2677             }
2678             if (subtree.empty())
2679             {
2680                 // This is an optional D-Bus object, but user attempted to patch
2681                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2682                                            "IdlePowerSaver");
2683                 return;
2684             }
2685             if (subtree.size() > 1)
2686             {
2687                 // More then one PowerIdlePowerSaver object is not supported and
2688                 // is an error
2689                 BMCWEB_LOG_DEBUG
2690                     << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2691                     << subtree.size();
2692                 messages::internalError(aResp->res);
2693                 return;
2694             }
2695             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2696             {
2697                 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2698                 messages::internalError(aResp->res);
2699                 return;
2700             }
2701             const std::string& path = subtree[0].first;
2702             const std::string& service = subtree[0].second.begin()->first;
2703             if (service.empty())
2704             {
2705                 BMCWEB_LOG_DEBUG
2706                     << "Power.IdlePowerSaver service mapper error!";
2707                 messages::internalError(aResp->res);
2708                 return;
2709             }
2710 
2711             // Valid Power IdlePowerSaver object found, now set any values that
2712             // need to be updated
2713 
2714             if (ipsEnable)
2715             {
2716                 crow::connections::systemBus->async_method_call(
2717                     [aResp](const boost::system::error_code ec) {
2718                         if (ec)
2719                         {
2720                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2721                             messages::internalError(aResp->res);
2722                             return;
2723                         }
2724                     },
2725                     service, path, "org.freedesktop.DBus.Properties", "Set",
2726                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2727                     "Enabled", std::variant<bool>(*ipsEnable));
2728             }
2729             if (ipsEnterUtil)
2730             {
2731                 crow::connections::systemBus->async_method_call(
2732                     [aResp](const boost::system::error_code ec) {
2733                         if (ec)
2734                         {
2735                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2736                             messages::internalError(aResp->res);
2737                             return;
2738                         }
2739                     },
2740                     service, path, "org.freedesktop.DBus.Properties", "Set",
2741                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2742                     "EnterUtilizationPercent",
2743                     std::variant<uint8_t>(*ipsEnterUtil));
2744             }
2745             if (ipsEnterTime)
2746             {
2747                 // Convert from seconds into milliseconds for DBus
2748                 const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2749                 crow::connections::systemBus->async_method_call(
2750                     [aResp](const boost::system::error_code ec) {
2751                         if (ec)
2752                         {
2753                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2754                             messages::internalError(aResp->res);
2755                             return;
2756                         }
2757                     },
2758                     service, path, "org.freedesktop.DBus.Properties", "Set",
2759                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2760                     "EnterDwellTime", std::variant<uint64_t>(timeMilliseconds));
2761             }
2762             if (ipsExitUtil)
2763             {
2764                 crow::connections::systemBus->async_method_call(
2765                     [aResp](const boost::system::error_code ec) {
2766                         if (ec)
2767                         {
2768                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2769                             messages::internalError(aResp->res);
2770                             return;
2771                         }
2772                     },
2773                     service, path, "org.freedesktop.DBus.Properties", "Set",
2774                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2775                     "ExitUtilizationPercent",
2776                     std::variant<uint8_t>(*ipsExitUtil));
2777             }
2778             if (ipsExitTime)
2779             {
2780                 // Convert from seconds into milliseconds for DBus
2781                 const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2782                 crow::connections::systemBus->async_method_call(
2783                     [aResp](const boost::system::error_code ec) {
2784                         if (ec)
2785                         {
2786                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2787                             messages::internalError(aResp->res);
2788                             return;
2789                         }
2790                     },
2791                     service, path, "org.freedesktop.DBus.Properties", "Set",
2792                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2793                     "ExitDwellTime", std::variant<uint64_t>(timeMilliseconds));
2794             }
2795         },
2796         "xyz.openbmc_project.ObjectMapper",
2797         "/xyz/openbmc_project/object_mapper",
2798         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2799         std::array<const char*, 1>{
2800             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2801 
2802     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2803 }
2804 
2805 /**
2806  * SystemsCollection derived class for delivering ComputerSystems Collection
2807  * Schema
2808  */
2809 inline void requestRoutesSystemsCollection(App& app)
2810 {
2811     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2812         .privileges(redfish::privileges::getComputerSystemCollection)
2813         .methods(boost::beast::http::verb::get)(
2814             [](const crow::Request& /*req*/,
2815                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2816                 asyncResp->res.jsonValue["@odata.type"] =
2817                     "#ComputerSystemCollection.ComputerSystemCollection";
2818                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2819                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2820 
2821                 crow::connections::systemBus->async_method_call(
2822                     [asyncResp](const boost::system::error_code ec,
2823                                 const std::variant<std::string>& /*hostName*/) {
2824                         nlohmann::json& ifaceArray =
2825                             asyncResp->res.jsonValue["Members"];
2826                         ifaceArray = nlohmann::json::array();
2827                         auto& count =
2828                             asyncResp->res.jsonValue["Members@odata.count"];
2829                         ifaceArray.push_back(
2830                             {{"@odata.id", "/redfish/v1/Systems/system"}});
2831                         count = ifaceArray.size();
2832                         if (!ec)
2833                         {
2834                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
2835                             ifaceArray.push_back(
2836                                 {{"@odata.id",
2837                                   "/redfish/v1/Systems/hypervisor"}});
2838                             count = ifaceArray.size();
2839                         }
2840                     },
2841                     "xyz.openbmc_project.Settings",
2842                     "/xyz/openbmc_project/network/hypervisor",
2843                     "org.freedesktop.DBus.Properties", "Get",
2844                     "xyz.openbmc_project.Network.SystemConfiguration",
2845                     "HostName");
2846             });
2847 }
2848 
2849 /**
2850  * Function transceives data with dbus directly.
2851  */
2852 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2853 {
2854     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2855     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2856     constexpr char const* interfaceName =
2857         "xyz.openbmc_project.Control.Host.NMI";
2858     constexpr char const* method = "NMI";
2859 
2860     crow::connections::systemBus->async_method_call(
2861         [asyncResp](const boost::system::error_code ec) {
2862             if (ec)
2863             {
2864                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2865                 messages::internalError(asyncResp->res);
2866                 return;
2867             }
2868             messages::success(asyncResp->res);
2869         },
2870         serviceName, objectPath, interfaceName, method);
2871 }
2872 
2873 /**
2874  * SystemActionsReset class supports handle POST method for Reset action.
2875  * The class retrieves and sends data directly to D-Bus.
2876  */
2877 inline void requestRoutesSystemActionsReset(App& app)
2878 {
2879     /**
2880      * Function handles POST method request.
2881      * Analyzes POST body message before sends Reset request data to D-Bus.
2882      */
2883     BMCWEB_ROUTE(app,
2884                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2885         .privileges(redfish::privileges::postComputerSystem)
2886         .methods(
2887             boost::beast::http::verb::
2888                 post)([](const crow::Request& req,
2889                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2890             std::string resetType;
2891             if (!json_util::readJson(req, asyncResp->res, "ResetType",
2892                                      resetType))
2893             {
2894                 return;
2895             }
2896 
2897             // Get the command and host vs. chassis
2898             std::string command;
2899             bool hostCommand;
2900             if ((resetType == "On") || (resetType == "ForceOn"))
2901             {
2902                 command = "xyz.openbmc_project.State.Host.Transition.On";
2903                 hostCommand = true;
2904             }
2905             else if (resetType == "ForceOff")
2906             {
2907                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2908                 hostCommand = false;
2909             }
2910             else if (resetType == "ForceRestart")
2911             {
2912                 command =
2913                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2914                 hostCommand = true;
2915             }
2916             else if (resetType == "GracefulShutdown")
2917             {
2918                 command = "xyz.openbmc_project.State.Host.Transition.Off";
2919                 hostCommand = true;
2920             }
2921             else if (resetType == "GracefulRestart")
2922             {
2923                 command =
2924                     "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2925                 hostCommand = true;
2926             }
2927             else if (resetType == "PowerCycle")
2928             {
2929                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2930                 hostCommand = true;
2931             }
2932             else if (resetType == "Nmi")
2933             {
2934                 doNMI(asyncResp);
2935                 return;
2936             }
2937             else
2938             {
2939                 messages::actionParameterUnknown(asyncResp->res, "Reset",
2940                                                  resetType);
2941                 return;
2942             }
2943 
2944             if (hostCommand)
2945             {
2946                 crow::connections::systemBus->async_method_call(
2947                     [asyncResp, resetType](const boost::system::error_code ec) {
2948                         if (ec)
2949                         {
2950                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2951                             if (ec.value() ==
2952                                 boost::asio::error::invalid_argument)
2953                             {
2954                                 messages::actionParameterNotSupported(
2955                                     asyncResp->res, resetType, "Reset");
2956                             }
2957                             else
2958                             {
2959                                 messages::internalError(asyncResp->res);
2960                             }
2961                             return;
2962                         }
2963                         messages::success(asyncResp->res);
2964                     },
2965                     "xyz.openbmc_project.State.Host",
2966                     "/xyz/openbmc_project/state/host0",
2967                     "org.freedesktop.DBus.Properties", "Set",
2968                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2969                     std::variant<std::string>{command});
2970             }
2971             else
2972             {
2973                 crow::connections::systemBus->async_method_call(
2974                     [asyncResp, resetType](const boost::system::error_code ec) {
2975                         if (ec)
2976                         {
2977                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2978                             if (ec.value() ==
2979                                 boost::asio::error::invalid_argument)
2980                             {
2981                                 messages::actionParameterNotSupported(
2982                                     asyncResp->res, resetType, "Reset");
2983                             }
2984                             else
2985                             {
2986                                 messages::internalError(asyncResp->res);
2987                             }
2988                             return;
2989                         }
2990                         messages::success(asyncResp->res);
2991                     },
2992                     "xyz.openbmc_project.State.Chassis",
2993                     "/xyz/openbmc_project/state/chassis0",
2994                     "org.freedesktop.DBus.Properties", "Set",
2995                     "xyz.openbmc_project.State.Chassis",
2996                     "RequestedPowerTransition",
2997                     std::variant<std::string>{command});
2998             }
2999         });
3000 }
3001 
3002 /**
3003  * Systems derived class for delivering Computer Systems Schema.
3004  */
3005 inline void requestRoutesSystems(App& app)
3006 {
3007 
3008     /**
3009      * Functions triggers appropriate requests on DBus
3010      */
3011     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
3012         .privileges(redfish::privileges::getComputerSystem)
3013         .methods(
3014             boost::beast::http::verb::
3015                 get)([](const crow::Request&,
3016                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3017             asyncResp->res.jsonValue["@odata.type"] =
3018                 "#ComputerSystem.v1_16_0.ComputerSystem";
3019             asyncResp->res.jsonValue["Name"] = "system";
3020             asyncResp->res.jsonValue["Id"] = "system";
3021             asyncResp->res.jsonValue["SystemType"] = "Physical";
3022             asyncResp->res.jsonValue["Description"] = "Computer System";
3023             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
3024             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
3025                 "Disabled";
3026             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
3027                 uint64_t(0);
3028             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
3029                 "Disabled";
3030             asyncResp->res.jsonValue["@odata.id"] =
3031                 "/redfish/v1/Systems/system";
3032 
3033             asyncResp->res.jsonValue["Processors"] = {
3034                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
3035             asyncResp->res.jsonValue["Memory"] = {
3036                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
3037             asyncResp->res.jsonValue["Storage"] = {
3038                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
3039 
3040             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
3041                 {"target",
3042                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
3043                 {"@Redfish.ActionInfo",
3044                  "/redfish/v1/Systems/system/ResetActionInfo"}};
3045 
3046             asyncResp->res.jsonValue["LogServices"] = {
3047                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
3048 
3049             asyncResp->res.jsonValue["Bios"] = {
3050                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
3051 
3052             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
3053                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
3054 
3055             asyncResp->res.jsonValue["Status"] = {
3056                 {"Health", "OK"},
3057                 {"State", "Enabled"},
3058             };
3059 
3060             // Fill in SerialConsole info
3061             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
3062                 15;
3063             asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = {
3064                 {"ServiceEnabled", true},
3065             };
3066             // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
3067             asyncResp->res.jsonValue["SerialConsole"]["SSH"] = {
3068                 {"ServiceEnabled", true},
3069                 {"Port", 2200},
3070                 // https://github.com/openbmc/docs/blob/master/console.md
3071                 {"HotKeySequenceDisplay", "Press ~. to exit console"},
3072             };
3073 
3074 #ifdef BMCWEB_ENABLE_KVM
3075             // Fill in GraphicalConsole info
3076             asyncResp->res.jsonValue["GraphicalConsole"] = {
3077                 {"ServiceEnabled", true},
3078                 {"MaxConcurrentSessions", 4},
3079                 {"ConnectTypesSupported", {"KVMIP"}},
3080             };
3081 #endif // BMCWEB_ENABLE_KVM
3082             constexpr const std::array<const char*, 4> inventoryForSystems = {
3083                 "xyz.openbmc_project.Inventory.Item.Dimm",
3084                 "xyz.openbmc_project.Inventory.Item.Cpu",
3085                 "xyz.openbmc_project.Inventory.Item.Drive",
3086                 "xyz.openbmc_project.Inventory.Item.StorageController"};
3087 
3088             auto health = std::make_shared<HealthPopulate>(asyncResp);
3089             crow::connections::systemBus->async_method_call(
3090                 [health](const boost::system::error_code ec,
3091                          std::vector<std::string>& resp) {
3092                     if (ec)
3093                     {
3094                         // no inventory
3095                         return;
3096                     }
3097 
3098                     health->inventory = std::move(resp);
3099                 },
3100                 "xyz.openbmc_project.ObjectMapper",
3101                 "/xyz/openbmc_project/object_mapper",
3102                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
3103                 int32_t(0), inventoryForSystems);
3104 
3105             health->populate();
3106 
3107             getMainChassisId(
3108                 asyncResp, [](const std::string& chassisId,
3109                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3110                     aRsp->res.jsonValue["Links"]["Chassis"] = {
3111                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
3112                 });
3113 
3114             getLocationIndicatorActive(asyncResp);
3115             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3116             getIndicatorLedState(asyncResp);
3117             getComputerSystem(asyncResp, health);
3118             getHostState(asyncResp);
3119             getBootProperties(asyncResp);
3120             getBootProgress(asyncResp);
3121             getPCIeDeviceList(asyncResp, "PCIeDevices");
3122             getHostWatchdogTimer(asyncResp);
3123             getPowerRestorePolicy(asyncResp);
3124             getAutomaticRetry(asyncResp);
3125             getLastResetTime(asyncResp);
3126 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
3127             getProvisioningStatus(asyncResp);
3128 #endif
3129             getTrustedModuleRequiredToBoot(asyncResp);
3130             getPowerMode(asyncResp);
3131             getIdlePowerSaver(asyncResp);
3132         });
3133     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
3134         .privileges(redfish::privileges::patchComputerSystem)
3135         .methods(boost::beast::http::verb::patch)(
3136             [](const crow::Request& req,
3137                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3138                 std::optional<bool> locationIndicatorActive;
3139                 std::optional<std::string> indicatorLed;
3140                 std::optional<nlohmann::json> bootProps;
3141                 std::optional<nlohmann::json> wdtTimerProps;
3142                 std::optional<std::string> assetTag;
3143                 std::optional<std::string> powerRestorePolicy;
3144                 std::optional<std::string> powerMode;
3145                 std::optional<nlohmann::json> ipsProps;
3146                 if (!json_util::readJson(
3147                         req, asyncResp->res, "IndicatorLED", indicatorLed,
3148                         "LocationIndicatorActive", locationIndicatorActive,
3149                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
3150                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
3151                         assetTag, "PowerMode", powerMode, "IdlePowerSaver",
3152                         ipsProps))
3153                 {
3154                     return;
3155                 }
3156 
3157                 asyncResp->res.result(boost::beast::http::status::no_content);
3158 
3159                 if (assetTag)
3160                 {
3161                     setAssetTag(asyncResp, *assetTag);
3162                 }
3163 
3164                 if (wdtTimerProps)
3165                 {
3166                     std::optional<bool> wdtEnable;
3167                     std::optional<std::string> wdtTimeOutAction;
3168 
3169                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
3170                                              "FunctionEnabled", wdtEnable,
3171                                              "TimeoutAction", wdtTimeOutAction))
3172                     {
3173                         return;
3174                     }
3175                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3176                 }
3177 
3178                 if (bootProps)
3179                 {
3180                     std::optional<std::string> bootSource;
3181                     std::optional<std::string> bootType;
3182                     std::optional<std::string> bootEnable;
3183                     std::optional<std::string> automaticRetryConfig;
3184                     std::optional<bool> trustedModuleRequiredToBoot;
3185 
3186                     if (!json_util::readJson(
3187                             *bootProps, asyncResp->res,
3188                             "BootSourceOverrideTarget", bootSource,
3189                             "BootSourceOverrideMode", bootType,
3190                             "BootSourceOverrideEnabled", bootEnable,
3191                             "AutomaticRetryConfig", automaticRetryConfig,
3192                             "TrustedModuleRequiredToBoot",
3193                             trustedModuleRequiredToBoot))
3194                     {
3195                         return;
3196                     }
3197 
3198                     if (bootSource || bootType || bootEnable)
3199                     {
3200                         setBootProperties(asyncResp, bootSource, bootType,
3201                                           bootEnable);
3202                     }
3203                     if (automaticRetryConfig)
3204                     {
3205                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
3206                     }
3207 
3208                     if (trustedModuleRequiredToBoot)
3209                     {
3210                         setTrustedModuleRequiredToBoot(
3211                             asyncResp, *trustedModuleRequiredToBoot);
3212                     }
3213                 }
3214 
3215                 if (locationIndicatorActive)
3216                 {
3217                     setLocationIndicatorActive(asyncResp,
3218                                                *locationIndicatorActive);
3219                 }
3220 
3221                 // TODO (Gunnar): Remove IndicatorLED after enough time has
3222                 // passed
3223                 if (indicatorLed)
3224                 {
3225                     setIndicatorLedState(asyncResp, *indicatorLed);
3226                     asyncResp->res.addHeader(
3227                         boost::beast::http::field::warning,
3228                         "299 - \"IndicatorLED is deprecated. Use "
3229                         "LocationIndicatorActive instead.\"");
3230                 }
3231 
3232                 if (powerRestorePolicy)
3233                 {
3234                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3235                 }
3236 
3237                 if (powerMode)
3238                 {
3239                     setPowerMode(asyncResp, *powerMode);
3240                 }
3241 
3242                 if (ipsProps)
3243                 {
3244                     std::optional<bool> ipsEnable;
3245                     std::optional<uint8_t> ipsEnterUtil;
3246                     std::optional<uint64_t> ipsEnterTime;
3247                     std::optional<uint8_t> ipsExitUtil;
3248                     std::optional<uint64_t> ipsExitTime;
3249 
3250                     if (!json_util::readJson(
3251                             *ipsProps, asyncResp->res, "Enabled", ipsEnable,
3252                             "EnterUtilizationPercent", ipsEnterUtil,
3253                             "EnterDwellTimeSeconds", ipsEnterTime,
3254                             "ExitUtilizationPercent", ipsExitUtil,
3255                             "ExitDwellTimeSeconds", ipsExitTime))
3256                     {
3257                         return;
3258                     }
3259                     setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil,
3260                                       ipsEnterTime, ipsExitUtil, ipsExitTime);
3261                 }
3262             });
3263 }
3264 
3265 /**
3266  * SystemResetActionInfo derived class for delivering Computer Systems
3267  * ResetType AllowableValues using ResetInfo schema.
3268  */
3269 inline void requestRoutesSystemResetActionInfo(App& app)
3270 {
3271 
3272     /**
3273      * Functions triggers appropriate requests on DBus
3274      */
3275     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3276         .privileges(redfish::privileges::getActionInfo)
3277         .methods(boost::beast::http::verb::get)(
3278             [](const crow::Request&,
3279                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3280                 asyncResp->res.jsonValue = {
3281                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
3282                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
3283                     {"Name", "Reset Action Info"},
3284                     {"Id", "ResetActionInfo"},
3285                     {"Parameters",
3286                      {{{"Name", "ResetType"},
3287                        {"Required", true},
3288                        {"DataType", "String"},
3289                        {"AllowableValues",
3290                         {"On", "ForceOff", "ForceOn", "ForceRestart",
3291                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
3292                          "Nmi"}}}}}};
3293             });
3294 }
3295 } // namespace redfish
3296