xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 1d8782e7a0ed98878bd82c24c7cf830bb8cdc46f)
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             uint64_t lastResetTimeStamp = *lastResetTimePtr / 1000;
1175 
1176             // Convert to ISO 8601 standard
1177             aResp->res.jsonValue["LastResetTime"] =
1178                 crow::utility::getDateTimeUint(lastResetTimeStamp);
1179         },
1180         "xyz.openbmc_project.State.Chassis",
1181         "/xyz/openbmc_project/state/chassis0",
1182         "org.freedesktop.DBus.Properties", "Get",
1183         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1184 }
1185 
1186 /**
1187  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1188  *
1189  * @param[in] aResp     Shared pointer for generating response message.
1190  *
1191  * @return None.
1192  */
1193 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1194 {
1195     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1196 
1197     crow::connections::systemBus->async_method_call(
1198         [aResp](const boost::system::error_code ec,
1199                 std::variant<bool>& autoRebootEnabled) {
1200             if (ec)
1201             {
1202                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1203                 return;
1204             }
1205 
1206             const bool* autoRebootEnabledPtr =
1207                 std::get_if<bool>(&autoRebootEnabled);
1208 
1209             if (!autoRebootEnabledPtr)
1210             {
1211                 messages::internalError(aResp->res);
1212                 return;
1213             }
1214 
1215             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1216             if (*autoRebootEnabledPtr == true)
1217             {
1218                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1219                     "RetryAttempts";
1220                 // If AutomaticRetry (AutoReboot) is enabled see how many
1221                 // attempts are left
1222                 crow::connections::systemBus->async_method_call(
1223                     [aResp](const boost::system::error_code ec2,
1224                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1225                         if (ec2)
1226                         {
1227                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1228                             return;
1229                         }
1230 
1231                         const uint32_t* autoRebootAttemptsLeftPtr =
1232                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1233 
1234                         if (!autoRebootAttemptsLeftPtr)
1235                         {
1236                             messages::internalError(aResp->res);
1237                             return;
1238                         }
1239 
1240                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1241                                          << *autoRebootAttemptsLeftPtr;
1242 
1243                         aResp->res
1244                             .jsonValue["Boot"]
1245                                       ["RemainingAutomaticRetryAttempts"] =
1246                             *autoRebootAttemptsLeftPtr;
1247                     },
1248                     "xyz.openbmc_project.State.Host",
1249                     "/xyz/openbmc_project/state/host0",
1250                     "org.freedesktop.DBus.Properties", "Get",
1251                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1252                     "AttemptsLeft");
1253             }
1254             else
1255             {
1256                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1257                     "Disabled";
1258             }
1259 
1260             // Not on D-Bus. Hardcoded here:
1261             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1262             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1263 
1264             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1265             // and RetryAttempts. OpenBMC only supports Disabled and
1266             // RetryAttempts.
1267             aResp->res
1268                 .jsonValue["Boot"]
1269                           ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1270                 "Disabled", "RetryAttempts"};
1271         },
1272         "xyz.openbmc_project.Settings",
1273         "/xyz/openbmc_project/control/host0/auto_reboot",
1274         "org.freedesktop.DBus.Properties", "Get",
1275         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1276 }
1277 
1278 /**
1279  * @brief Retrieves power restore policy over DBUS.
1280  *
1281  * @param[in] aResp     Shared pointer for generating response message.
1282  *
1283  * @return None.
1284  */
1285 inline void
1286     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1287 {
1288     BMCWEB_LOG_DEBUG << "Get power restore policy";
1289 
1290     crow::connections::systemBus->async_method_call(
1291         [aResp](const boost::system::error_code ec,
1292                 std::variant<std::string>& policy) {
1293             if (ec)
1294             {
1295                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1296                 return;
1297             }
1298 
1299             const boost::container::flat_map<std::string, std::string> policyMaps = {
1300                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1301                  "AlwaysOn"},
1302                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1303                  "AlwaysOff"},
1304                 {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1305                  "LastState"}};
1306 
1307             const std::string* policyPtr = std::get_if<std::string>(&policy);
1308 
1309             if (!policyPtr)
1310             {
1311                 messages::internalError(aResp->res);
1312                 return;
1313             }
1314 
1315             auto policyMapsIt = policyMaps.find(*policyPtr);
1316             if (policyMapsIt == policyMaps.end())
1317             {
1318                 messages::internalError(aResp->res);
1319                 return;
1320             }
1321 
1322             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1323         },
1324         "xyz.openbmc_project.Settings",
1325         "/xyz/openbmc_project/control/host0/power_restore_policy",
1326         "org.freedesktop.DBus.Properties", "Get",
1327         "xyz.openbmc_project.Control.Power.RestorePolicy",
1328         "PowerRestorePolicy");
1329 }
1330 
1331 /**
1332  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1333  * TPM is required for booting the host.
1334  *
1335  * @param[in] aResp     Shared pointer for generating response message.
1336  *
1337  * @return None.
1338  */
1339 inline void getTrustedModuleRequiredToBoot(
1340     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1341 {
1342     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1343 
1344     crow::connections::systemBus->async_method_call(
1345         [aResp](
1346             const boost::system::error_code ec,
1347             std::vector<std::pair<
1348                 std::string,
1349                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1350                 subtree) {
1351             if (ec)
1352             {
1353                 BMCWEB_LOG_DEBUG
1354                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1355                 // This is an optional D-Bus object so just return if
1356                 // error occurs
1357                 return;
1358             }
1359             if (subtree.size() == 0)
1360             {
1361                 // As noted above, this is an optional interface so just return
1362                 // if there is no instance found
1363                 return;
1364             }
1365 
1366             /* When there is more than one TPMEnable object... */
1367             if (subtree.size() > 1)
1368             {
1369                 BMCWEB_LOG_DEBUG
1370                     << "DBUS response has more than 1 TPM Enable object:"
1371                     << subtree.size();
1372                 // Throw an internal Error and return
1373                 messages::internalError(aResp->res);
1374                 return;
1375             }
1376 
1377             // Make sure the Dbus response map has a service and objectPath
1378             // field
1379             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1380             {
1381                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1382                 messages::internalError(aResp->res);
1383                 return;
1384             }
1385 
1386             const std::string& path = subtree[0].first;
1387             const std::string& serv = subtree[0].second.begin()->first;
1388 
1389             // Valid TPM Enable object found, now reading the current value
1390             crow::connections::systemBus->async_method_call(
1391                 [aResp](const boost::system::error_code ec,
1392                         std::variant<bool>& tpmRequired) {
1393                     if (ec)
1394                     {
1395                         BMCWEB_LOG_DEBUG
1396                             << "D-BUS response error on TPM.Policy Get" << ec;
1397                         messages::internalError(aResp->res);
1398                         return;
1399                     }
1400 
1401                     const bool* tpmRequiredVal =
1402                         std::get_if<bool>(&tpmRequired);
1403 
1404                     if (!tpmRequiredVal)
1405                     {
1406                         messages::internalError(aResp->res);
1407                         return;
1408                     }
1409 
1410                     if (*tpmRequiredVal == true)
1411                     {
1412                         aResp->res
1413                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1414                             "Required";
1415                     }
1416                     else
1417                     {
1418                         aResp->res
1419                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1420                             "Disabled";
1421                     }
1422                 },
1423                 serv, path, "org.freedesktop.DBus.Properties", "Get",
1424                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable");
1425         },
1426         "xyz.openbmc_project.ObjectMapper",
1427         "/xyz/openbmc_project/object_mapper",
1428         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1429         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1430 }
1431 
1432 /**
1433  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1434  * TPM is required for booting the host.
1435  *
1436  * @param[in] aResp         Shared pointer for generating response message.
1437  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1438  *
1439  * @return None.
1440  */
1441 inline void setTrustedModuleRequiredToBoot(
1442     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1443 {
1444     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1445 
1446     crow::connections::systemBus->async_method_call(
1447         [aResp, tpmRequired](
1448             const boost::system::error_code ec,
1449             std::vector<std::pair<
1450                 std::string,
1451                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1452                 subtree) {
1453             if (ec)
1454             {
1455                 BMCWEB_LOG_DEBUG
1456                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1457                 messages::internalError(aResp->res);
1458                 return;
1459             }
1460             if (subtree.size() == 0)
1461             {
1462                 messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1463                                                  "TrustedModuleRequiredToBoot");
1464                 return;
1465             }
1466 
1467             /* When there is more than one TPMEnable object... */
1468             if (subtree.size() > 1)
1469             {
1470                 BMCWEB_LOG_DEBUG
1471                     << "DBUS response has more than 1 TPM Enable object:"
1472                     << subtree.size();
1473                 // Throw an internal Error and return
1474                 messages::internalError(aResp->res);
1475                 return;
1476             }
1477 
1478             // Make sure the Dbus response map has a service and objectPath
1479             // field
1480             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1481             {
1482                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1483                 messages::internalError(aResp->res);
1484                 return;
1485             }
1486 
1487             const std::string& path = subtree[0].first;
1488             const std::string& serv = subtree[0].second.begin()->first;
1489 
1490             if (serv.empty())
1491             {
1492                 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1493                 messages::internalError(aResp->res);
1494                 return;
1495             }
1496 
1497             // Valid TPM Enable object found, now setting the value
1498             crow::connections::systemBus->async_method_call(
1499                 [aResp](const boost::system::error_code ec) {
1500                     if (ec)
1501                     {
1502                         BMCWEB_LOG_DEBUG
1503                             << "DBUS response error: Set TrustedModuleRequiredToBoot"
1504                             << ec;
1505                         messages::internalError(aResp->res);
1506                         return;
1507                     }
1508                     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1509                 },
1510                 serv, path, "org.freedesktop.DBus.Properties", "Set",
1511                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1512                 std::variant<bool>(tpmRequired));
1513         },
1514         "xyz.openbmc_project.ObjectMapper",
1515         "/xyz/openbmc_project/object_mapper",
1516         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1517         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1518 }
1519 
1520 /**
1521  * @brief Sets boot properties into DBUS object(s).
1522  *
1523  * @param[in] aResp           Shared pointer for generating response message.
1524  * @param[in] bootType        The boot type to set.
1525  * @return Integer error code.
1526  */
1527 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1528                         const std::optional<std::string>& bootType)
1529 {
1530     std::string bootTypeStr;
1531 
1532     if (!bootType)
1533     {
1534         return;
1535     }
1536 
1537     // Source target specified
1538     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1539     // Figure out which DBUS interface and property to use
1540     if (*bootType == "Legacy")
1541     {
1542         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1543     }
1544     else if (*bootType == "UEFI")
1545     {
1546         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1547     }
1548     else
1549     {
1550         BMCWEB_LOG_DEBUG << "Invalid property value for "
1551                             "BootSourceOverrideMode: "
1552                          << *bootType;
1553         messages::propertyValueNotInList(aResp->res, *bootType,
1554                                          "BootSourceOverrideMode");
1555         return;
1556     }
1557 
1558     // Act on validated parameters
1559     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1560 
1561     crow::connections::systemBus->async_method_call(
1562         [aResp](const boost::system::error_code ec) {
1563             if (ec)
1564             {
1565                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1566                 if (ec.value() == boost::asio::error::host_unreachable)
1567                 {
1568                     messages::resourceNotFound(aResp->res, "Set", "BootType");
1569                     return;
1570                 }
1571                 messages::internalError(aResp->res);
1572                 return;
1573             }
1574             BMCWEB_LOG_DEBUG << "Boot type update done.";
1575         },
1576         "xyz.openbmc_project.Settings",
1577         "/xyz/openbmc_project/control/host0/boot",
1578         "org.freedesktop.DBus.Properties", "Set",
1579         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1580         std::variant<std::string>(bootTypeStr));
1581 }
1582 
1583 /**
1584  * @brief Sets boot properties into DBUS object(s).
1585  *
1586  * @param[in] aResp           Shared pointer for generating response message.
1587  * @param[in] bootType        The boot type to set.
1588  * @return Integer error code.
1589  */
1590 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1591                           const std::optional<std::string>& bootEnable)
1592 {
1593     if (!bootEnable)
1594     {
1595         return;
1596     }
1597     // Source target specified
1598     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1599 
1600     bool bootOverrideEnable = false;
1601     bool bootOverridePersistent = false;
1602     // Figure out which DBUS interface and property to use
1603     if (*bootEnable == "Disabled")
1604     {
1605         bootOverrideEnable = false;
1606     }
1607     else if (*bootEnable == "Once")
1608     {
1609         bootOverrideEnable = true;
1610         bootOverridePersistent = false;
1611     }
1612     else if (*bootEnable == "Continuous")
1613     {
1614         bootOverrideEnable = true;
1615         bootOverridePersistent = true;
1616     }
1617     else
1618     {
1619         BMCWEB_LOG_DEBUG
1620             << "Invalid property value for BootSourceOverrideEnabled: "
1621             << *bootEnable;
1622         messages::propertyValueNotInList(aResp->res, *bootEnable,
1623                                          "BootSourceOverrideEnabled");
1624         return;
1625     }
1626 
1627     // Act on validated parameters
1628     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1629 
1630     crow::connections::systemBus->async_method_call(
1631         [aResp](const boost::system::error_code ec) {
1632             if (ec)
1633             {
1634                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1635                 messages::internalError(aResp->res);
1636                 return;
1637             }
1638             BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1639         },
1640         "xyz.openbmc_project.Settings",
1641         "/xyz/openbmc_project/control/host0/boot",
1642         "org.freedesktop.DBus.Properties", "Set",
1643         "xyz.openbmc_project.Object.Enable", "Enabled",
1644         std::variant<bool>(bootOverrideEnable));
1645 
1646     if (!bootOverrideEnable)
1647     {
1648         return;
1649     }
1650 
1651     // In case boot override is enabled we need to set correct value for the
1652     // 'one_time' enable DBus interface
1653     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1654                      << bootOverridePersistent;
1655 
1656     crow::connections::systemBus->async_method_call(
1657         [aResp](const boost::system::error_code ec) {
1658             if (ec)
1659             {
1660                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1661                 messages::internalError(aResp->res);
1662                 return;
1663             }
1664             BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1665         },
1666         "xyz.openbmc_project.Settings",
1667         "/xyz/openbmc_project/control/host0/boot/one_time",
1668         "org.freedesktop.DBus.Properties", "Set",
1669         "xyz.openbmc_project.Object.Enable", "Enabled",
1670         std::variant<bool>(!bootOverridePersistent));
1671 }
1672 
1673 /**
1674  * @brief Sets boot properties into DBUS object(s).
1675  *
1676  * @param[in] aResp           Shared pointer for generating response message.
1677  * @param[in] bootSource      The boot source to set.
1678  *
1679  * @return Integer error code.
1680  */
1681 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1682                                 const std::optional<std::string>& bootSource)
1683 {
1684     std::string bootSourceStr;
1685     std::string bootModeStr;
1686 
1687     if (!bootSource)
1688     {
1689         return;
1690     }
1691 
1692     // Source target specified
1693     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1694     // Figure out which DBUS interface and property to use
1695     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr))
1696     {
1697         BMCWEB_LOG_DEBUG
1698             << "Invalid property value for BootSourceOverrideTarget: "
1699             << *bootSource;
1700         messages::propertyValueNotInList(aResp->res, *bootSource,
1701                                          "BootSourceTargetOverride");
1702         return;
1703     }
1704 
1705     // Act on validated parameters
1706     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1707     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1708 
1709     crow::connections::systemBus->async_method_call(
1710         [aResp](const boost::system::error_code ec) {
1711             if (ec)
1712             {
1713                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1714                 messages::internalError(aResp->res);
1715                 return;
1716             }
1717             BMCWEB_LOG_DEBUG << "Boot source update done.";
1718         },
1719         "xyz.openbmc_project.Settings",
1720         "/xyz/openbmc_project/control/host0/boot",
1721         "org.freedesktop.DBus.Properties", "Set",
1722         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1723         std::variant<std::string>(bootSourceStr));
1724 
1725     crow::connections::systemBus->async_method_call(
1726         [aResp](const boost::system::error_code ec) {
1727             if (ec)
1728             {
1729                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1730                 messages::internalError(aResp->res);
1731                 return;
1732             }
1733             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1734         },
1735         "xyz.openbmc_project.Settings",
1736         "/xyz/openbmc_project/control/host0/boot",
1737         "org.freedesktop.DBus.Properties", "Set",
1738         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1739         std::variant<std::string>(bootModeStr));
1740 }
1741 
1742 /**
1743  * @brief Sets Boot source override properties.
1744  *
1745  * @param[in] aResp      Shared pointer for generating response message.
1746  * @param[in] bootSource The boot source from incoming RF request.
1747  * @param[in] bootType   The boot type from incoming RF request.
1748  * @param[in] bootEnable The boot override enable from incoming RF request.
1749  *
1750  * @return Integer error code.
1751  */
1752 
1753 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1754                               const std::optional<std::string>& bootSource,
1755                               const std::optional<std::string>& bootType,
1756                               const std::optional<std::string>& bootEnable)
1757 {
1758     BMCWEB_LOG_DEBUG << "Set boot information.";
1759 
1760     setBootModeOrSource(aResp, bootSource);
1761     setBootType(aResp, bootType);
1762     setBootEnable(aResp, bootEnable);
1763 }
1764 
1765 /**
1766  * @brief Sets AssetTag
1767  *
1768  * @param[in] aResp   Shared pointer for generating response message.
1769  * @param[in] assetTag  "AssetTag" from request.
1770  *
1771  * @return None.
1772  */
1773 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1774                         const std::string& assetTag)
1775 {
1776     crow::connections::systemBus->async_method_call(
1777         [aResp, assetTag](
1778             const boost::system::error_code ec,
1779             const std::vector<std::pair<
1780                 std::string,
1781                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1782                 subtree) {
1783             if (ec)
1784             {
1785                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1786                 messages::internalError(aResp->res);
1787                 return;
1788             }
1789             if (subtree.size() == 0)
1790             {
1791                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1792                 messages::internalError(aResp->res);
1793                 return;
1794             }
1795             // Assume only 1 system D-Bus object
1796             // Throw an error if there is more than 1
1797             if (subtree.size() > 1)
1798             {
1799                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1800                 messages::internalError(aResp->res);
1801                 return;
1802             }
1803             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1804             {
1805                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1806                 messages::internalError(aResp->res);
1807                 return;
1808             }
1809 
1810             const std::string& path = subtree[0].first;
1811             const std::string& service = subtree[0].second.begin()->first;
1812 
1813             if (service.empty())
1814             {
1815                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1816                 messages::internalError(aResp->res);
1817                 return;
1818             }
1819 
1820             crow::connections::systemBus->async_method_call(
1821                 [aResp](const boost::system::error_code ec2) {
1822                     if (ec2)
1823                     {
1824                         BMCWEB_LOG_DEBUG
1825                             << "D-Bus response error on AssetTag Set " << ec2;
1826                         messages::internalError(aResp->res);
1827                         return;
1828                     }
1829                 },
1830                 service, path, "org.freedesktop.DBus.Properties", "Set",
1831                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1832                 std::variant<std::string>(assetTag));
1833         },
1834         "xyz.openbmc_project.ObjectMapper",
1835         "/xyz/openbmc_project/object_mapper",
1836         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1837         "/xyz/openbmc_project/inventory", int32_t(0),
1838         std::array<const char*, 1>{
1839             "xyz.openbmc_project.Inventory.Item.System"});
1840 }
1841 
1842 /**
1843  * @brief Sets automaticRetry (Auto Reboot)
1844  *
1845  * @param[in] aResp   Shared pointer for generating response message.
1846  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1847  *
1848  * @return None.
1849  */
1850 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1851                               const std::string& automaticRetryConfig)
1852 {
1853     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1854 
1855     // OpenBMC only supports "Disabled" and "RetryAttempts".
1856     bool autoRebootEnabled;
1857 
1858     if (automaticRetryConfig == "Disabled")
1859     {
1860         autoRebootEnabled = false;
1861     }
1862     else if (automaticRetryConfig == "RetryAttempts")
1863     {
1864         autoRebootEnabled = true;
1865     }
1866     else
1867     {
1868         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1869                          << automaticRetryConfig;
1870         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1871                                          "AutomaticRetryConfig");
1872         return;
1873     }
1874 
1875     crow::connections::systemBus->async_method_call(
1876         [aResp](const boost::system::error_code ec) {
1877             if (ec)
1878             {
1879                 messages::internalError(aResp->res);
1880                 return;
1881             }
1882         },
1883         "xyz.openbmc_project.Settings",
1884         "/xyz/openbmc_project/control/host0/auto_reboot",
1885         "org.freedesktop.DBus.Properties", "Set",
1886         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1887         std::variant<bool>(autoRebootEnabled));
1888 }
1889 
1890 /**
1891  * @brief Sets power restore policy properties.
1892  *
1893  * @param[in] aResp   Shared pointer for generating response message.
1894  * @param[in] policy  power restore policy properties from request.
1895  *
1896  * @return None.
1897  */
1898 inline void
1899     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1900                           const std::string& policy)
1901 {
1902     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1903 
1904     const boost::container::flat_map<std::string, std::string> policyMaps = {
1905         {"AlwaysOn",
1906          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1907         {"AlwaysOff",
1908          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1909         {"LastState",
1910          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1911 
1912     std::string powerRestorPolicy;
1913 
1914     auto policyMapsIt = policyMaps.find(policy);
1915     if (policyMapsIt == policyMaps.end())
1916     {
1917         messages::propertyValueNotInList(aResp->res, policy,
1918                                          "PowerRestorePolicy");
1919         return;
1920     }
1921 
1922     powerRestorPolicy = policyMapsIt->second;
1923 
1924     crow::connections::systemBus->async_method_call(
1925         [aResp](const boost::system::error_code ec) {
1926             if (ec)
1927             {
1928                 messages::internalError(aResp->res);
1929                 return;
1930             }
1931         },
1932         "xyz.openbmc_project.Settings",
1933         "/xyz/openbmc_project/control/host0/power_restore_policy",
1934         "org.freedesktop.DBus.Properties", "Set",
1935         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1936         std::variant<std::string>(powerRestorPolicy));
1937 }
1938 
1939 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1940 /**
1941  * @brief Retrieves provisioning status
1942  *
1943  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1944  *
1945  * @return None.
1946  */
1947 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1948 {
1949     BMCWEB_LOG_DEBUG << "Get OEM information.";
1950     crow::connections::systemBus->async_method_call(
1951         [aResp](const boost::system::error_code ec,
1952                 const std::vector<std::pair<std::string, VariantType>>&
1953                     propertiesList) {
1954             nlohmann::json& oemPFR =
1955                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1956             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1957                 "#OemComputerSystem.OpenBmc";
1958             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1959 
1960             if (ec)
1961             {
1962                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1963                 // not an error, don't have to have the interface
1964                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1965                 return;
1966             }
1967 
1968             const bool* provState = nullptr;
1969             const bool* lockState = nullptr;
1970             for (const std::pair<std::string, VariantType>& property :
1971                  propertiesList)
1972             {
1973                 if (property.first == "UfmProvisioned")
1974                 {
1975                     provState = std::get_if<bool>(&property.second);
1976                 }
1977                 else if (property.first == "UfmLocked")
1978                 {
1979                     lockState = std::get_if<bool>(&property.second);
1980                 }
1981             }
1982 
1983             if ((provState == nullptr) || (lockState == nullptr))
1984             {
1985                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1986                 messages::internalError(aResp->res);
1987                 return;
1988             }
1989 
1990             if (*provState == true)
1991             {
1992                 if (*lockState == true)
1993                 {
1994                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1995                 }
1996                 else
1997                 {
1998                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1999                 }
2000             }
2001             else
2002             {
2003                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
2004             }
2005         },
2006         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
2007         "org.freedesktop.DBus.Properties", "GetAll",
2008         "xyz.openbmc_project.PFR.Attributes");
2009 }
2010 #endif
2011 
2012 /**
2013  * @brief Translate the PowerMode to a response message.
2014  *
2015  * @param[in] aResp  Shared pointer for generating response message.
2016  * @param[in] modeValue  PowerMode value to be translated
2017  *
2018  * @return None.
2019  */
2020 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2021                                const std::string& modeValue)
2022 {
2023     std::string modeString;
2024 
2025     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
2026     {
2027         aResp->res.jsonValue["PowerMode"] = "Static";
2028     }
2029     else if (
2030         modeValue ==
2031         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
2032     {
2033         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
2034     }
2035     else if (modeValue ==
2036              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
2037     {
2038         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
2039     }
2040     else if (modeValue ==
2041              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
2042     {
2043         aResp->res.jsonValue["PowerMode"] = "OEM";
2044     }
2045     else
2046     {
2047         // Any other values would be invalid
2048         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
2049         messages::internalError(aResp->res);
2050     }
2051 }
2052 
2053 /**
2054  * @brief Retrieves system power mode
2055  *
2056  * @param[in] aResp  Shared pointer for generating response message.
2057  *
2058  * @return None.
2059  */
2060 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2061 {
2062     BMCWEB_LOG_DEBUG << "Get power mode.";
2063 
2064     // Get Power Mode object path:
2065     crow::connections::systemBus->async_method_call(
2066         [aResp](
2067             const boost::system::error_code ec,
2068             const std::vector<std::pair<
2069                 std::string,
2070                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2071                 subtree) {
2072             if (ec)
2073             {
2074                 BMCWEB_LOG_DEBUG
2075                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2076                 // This is an optional D-Bus object so just return if
2077                 // error occurs
2078                 return;
2079             }
2080             if (subtree.empty())
2081             {
2082                 // As noted above, this is an optional interface so just return
2083                 // if there is no instance found
2084                 return;
2085             }
2086             if (subtree.size() > 1)
2087             {
2088                 // More then one PowerMode object is not supported and is an
2089                 // error
2090                 BMCWEB_LOG_DEBUG
2091                     << "Found more than 1 system D-Bus Power.Mode objects: "
2092                     << subtree.size();
2093                 messages::internalError(aResp->res);
2094                 return;
2095             }
2096             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2097             {
2098                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2099                 messages::internalError(aResp->res);
2100                 return;
2101             }
2102             const std::string& path = subtree[0].first;
2103             const std::string& service = subtree[0].second.begin()->first;
2104             if (service.empty())
2105             {
2106                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2107                 messages::internalError(aResp->res);
2108                 return;
2109             }
2110             // Valid Power Mode object found, now read the current value
2111             crow::connections::systemBus->async_method_call(
2112                 [aResp](const boost::system::error_code ec,
2113                         const std::variant<std::string>& pmode) {
2114                     if (ec)
2115                     {
2116                         BMCWEB_LOG_DEBUG
2117                             << "DBUS response error on PowerMode Get: " << ec;
2118                         messages::internalError(aResp->res);
2119                         return;
2120                     }
2121 
2122                     const std::string* s = std::get_if<std::string>(&pmode);
2123                     if (s == nullptr)
2124                     {
2125                         BMCWEB_LOG_DEBUG << "Unable to get PowerMode value";
2126                         messages::internalError(aResp->res);
2127                         return;
2128                     }
2129 
2130                     aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] =
2131                         {"Static", "MaximumPerformance", "PowerSaving"};
2132 
2133                     BMCWEB_LOG_DEBUG << "Current power mode: " << *s;
2134                     translatePowerMode(aResp, *s);
2135                 },
2136                 service, path, "org.freedesktop.DBus.Properties", "Get",
2137                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode");
2138         },
2139         "xyz.openbmc_project.ObjectMapper",
2140         "/xyz/openbmc_project/object_mapper",
2141         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2142         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2143 }
2144 
2145 /**
2146  * @brief Validate the specified mode is valid and return the PowerMode
2147  * name associated with that string
2148  *
2149  * @param[in] aResp   Shared pointer for generating response message.
2150  * @param[in] modeString  String representing the desired PowerMode
2151  *
2152  * @return PowerMode value or empty string if mode is not valid
2153  */
2154 inline std::string
2155     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2156                       const std::string& modeString)
2157 {
2158     std::string mode;
2159 
2160     if (modeString == "Static")
2161     {
2162         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2163     }
2164     else if (modeString == "MaximumPerformance")
2165     {
2166         mode =
2167             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2168     }
2169     else if (modeString == "PowerSaving")
2170     {
2171         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2172     }
2173     else
2174     {
2175         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2176     }
2177     return mode;
2178 }
2179 
2180 /**
2181  * @brief Sets system power mode.
2182  *
2183  * @param[in] aResp   Shared pointer for generating response message.
2184  * @param[in] pmode   System power mode from request.
2185  *
2186  * @return None.
2187  */
2188 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2189                          const std::string& pmode)
2190 {
2191     BMCWEB_LOG_DEBUG << "Set power mode.";
2192 
2193     std::string powerMode = validatePowerMode(aResp, pmode);
2194     if (powerMode.empty())
2195     {
2196         return;
2197     }
2198 
2199     // Get Power Mode object path:
2200     crow::connections::systemBus->async_method_call(
2201         [aResp, powerMode](
2202             const boost::system::error_code ec,
2203             const std::vector<std::pair<
2204                 std::string,
2205                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2206                 subtree) {
2207             if (ec)
2208             {
2209                 BMCWEB_LOG_DEBUG
2210                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2211                 // This is an optional D-Bus object, but user attempted to patch
2212                 messages::internalError(aResp->res);
2213                 return;
2214             }
2215             if (subtree.empty())
2216             {
2217                 // This is an optional D-Bus object, but user attempted to patch
2218                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2219                                            "PowerMode");
2220                 return;
2221             }
2222             if (subtree.size() > 1)
2223             {
2224                 // More then one PowerMode object is not supported and is an
2225                 // error
2226                 BMCWEB_LOG_DEBUG
2227                     << "Found more than 1 system D-Bus Power.Mode objects: "
2228                     << subtree.size();
2229                 messages::internalError(aResp->res);
2230                 return;
2231             }
2232             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2233             {
2234                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2235                 messages::internalError(aResp->res);
2236                 return;
2237             }
2238             const std::string& path = subtree[0].first;
2239             const std::string& service = subtree[0].second.begin()->first;
2240             if (service.empty())
2241             {
2242                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2243                 messages::internalError(aResp->res);
2244                 return;
2245             }
2246 
2247             BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2248                              << path;
2249 
2250             // Set the Power Mode property
2251             crow::connections::systemBus->async_method_call(
2252                 [aResp](const boost::system::error_code ec) {
2253                     if (ec)
2254                     {
2255                         messages::internalError(aResp->res);
2256                         return;
2257                     }
2258                 },
2259                 service, path, "org.freedesktop.DBus.Properties", "Set",
2260                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2261                 std::variant<std::string>(powerMode));
2262         },
2263         "xyz.openbmc_project.ObjectMapper",
2264         "/xyz/openbmc_project/object_mapper",
2265         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2266         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2267 }
2268 
2269 /**
2270  * @brief Translates watchdog timeout action DBUS property value to redfish.
2271  *
2272  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2273  *
2274  * @return Returns as a string, the timeout action in Redfish terms. If
2275  * translation cannot be done, returns an empty string.
2276  */
2277 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2278 {
2279     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2280     {
2281         return "None";
2282     }
2283     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2284     {
2285         return "ResetSystem";
2286     }
2287     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2288     {
2289         return "PowerDown";
2290     }
2291     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2292     {
2293         return "PowerCycle";
2294     }
2295 
2296     return "";
2297 }
2298 
2299 /**
2300  *@brief Translates timeout action from Redfish to DBUS property value.
2301  *
2302  *@param[in] rfAction The timeout action in Redfish.
2303  *
2304  *@return Returns as a string, the time_out action as expected by DBUS.
2305  *If translation cannot be done, returns an empty string.
2306  */
2307 
2308 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2309 {
2310     if (rfAction == "None")
2311     {
2312         return "xyz.openbmc_project.State.Watchdog.Action.None";
2313     }
2314     if (rfAction == "PowerCycle")
2315     {
2316         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2317     }
2318     if (rfAction == "PowerDown")
2319     {
2320         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2321     }
2322     if (rfAction == "ResetSystem")
2323     {
2324         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2325     }
2326 
2327     return "";
2328 }
2329 
2330 /**
2331  * @brief Retrieves host watchdog timer properties over DBUS
2332  *
2333  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2334  *
2335  * @return None.
2336  */
2337 inline void
2338     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2339 {
2340     BMCWEB_LOG_DEBUG << "Get host watchodg";
2341     crow::connections::systemBus->async_method_call(
2342         [aResp](const boost::system::error_code ec,
2343                 PropertiesType& properties) {
2344             if (ec)
2345             {
2346                 // watchdog service is stopped
2347                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2348                 return;
2349             }
2350 
2351             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2352 
2353             nlohmann::json& hostWatchdogTimer =
2354                 aResp->res.jsonValue["HostWatchdogTimer"];
2355 
2356             // watchdog service is running/enabled
2357             hostWatchdogTimer["Status"]["State"] = "Enabled";
2358 
2359             for (const auto& property : properties)
2360             {
2361                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
2362                 if (property.first == "Enabled")
2363                 {
2364                     const bool* state = std::get_if<bool>(&property.second);
2365 
2366                     if (!state)
2367                     {
2368                         messages::internalError(aResp->res);
2369                         return;
2370                     }
2371 
2372                     hostWatchdogTimer["FunctionEnabled"] = *state;
2373                 }
2374                 else if (property.first == "ExpireAction")
2375                 {
2376                     const std::string* s =
2377                         std::get_if<std::string>(&property.second);
2378                     if (!s)
2379                     {
2380                         messages::internalError(aResp->res);
2381                         return;
2382                     }
2383 
2384                     std::string action = dbusToRfWatchdogAction(*s);
2385                     if (action.empty())
2386                     {
2387                         messages::internalError(aResp->res);
2388                         return;
2389                     }
2390                     hostWatchdogTimer["TimeoutAction"] = action;
2391                 }
2392             }
2393         },
2394         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2395         "org.freedesktop.DBus.Properties", "GetAll",
2396         "xyz.openbmc_project.State.Watchdog");
2397 }
2398 
2399 /**
2400  * @brief Sets Host WatchDog Timer properties.
2401  *
2402  * @param[in] aResp      Shared pointer for generating response message.
2403  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2404  *                       RF request.
2405  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2406  *
2407  * @return None.
2408  */
2409 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2410                              const std::optional<bool> wdtEnable,
2411                              const std::optional<std::string>& wdtTimeOutAction)
2412 {
2413     BMCWEB_LOG_DEBUG << "Set host watchdog";
2414 
2415     if (wdtTimeOutAction)
2416     {
2417         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2418         // check if TimeOut Action is Valid
2419         if (wdtTimeOutActStr.empty())
2420         {
2421             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2422                              << *wdtTimeOutAction;
2423             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2424                                              "TimeoutAction");
2425             return;
2426         }
2427 
2428         crow::connections::systemBus->async_method_call(
2429             [aResp](const boost::system::error_code ec) {
2430                 if (ec)
2431                 {
2432                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2433                     messages::internalError(aResp->res);
2434                     return;
2435                 }
2436             },
2437             "xyz.openbmc_project.Watchdog",
2438             "/xyz/openbmc_project/watchdog/host0",
2439             "org.freedesktop.DBus.Properties", "Set",
2440             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2441             std::variant<std::string>(wdtTimeOutActStr));
2442     }
2443 
2444     if (wdtEnable)
2445     {
2446         crow::connections::systemBus->async_method_call(
2447             [aResp](const boost::system::error_code ec) {
2448                 if (ec)
2449                 {
2450                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2451                     messages::internalError(aResp->res);
2452                     return;
2453                 }
2454             },
2455             "xyz.openbmc_project.Watchdog",
2456             "/xyz/openbmc_project/watchdog/host0",
2457             "org.freedesktop.DBus.Properties", "Set",
2458             "xyz.openbmc_project.State.Watchdog", "Enabled",
2459             std::variant<bool>(*wdtEnable));
2460     }
2461 }
2462 
2463 using ipsPropertiesType =
2464     std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>;
2465 /**
2466  * @brief Parse the Idle Power Saver properties into json
2467  *
2468  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2469  * @param[in] properties  IPS property data from DBus.
2470  *
2471  * @return true if successful
2472  */
2473 inline bool parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2474                                ipsPropertiesType& properties)
2475 {
2476     for (const auto& property : properties)
2477     {
2478         if (property.first == "Enabled")
2479         {
2480             const bool* state = std::get_if<bool>(&property.second);
2481             if (!state)
2482             {
2483                 return false;
2484             }
2485             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *state;
2486         }
2487         else if (property.first == "EnterUtilizationPercent")
2488         {
2489             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2490             if (!util)
2491             {
2492                 return false;
2493             }
2494             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2495         }
2496         else if (property.first == "EnterDwellTime")
2497         {
2498             // Convert Dbus time from milliseconds to seconds
2499             const uint64_t* timeMilliseconds =
2500                 std::get_if<uint64_t>(&property.second);
2501             if (!timeMilliseconds)
2502             {
2503                 return false;
2504             }
2505             const std::chrono::duration<uint64_t, std::milli> ms(
2506                 *timeMilliseconds);
2507             aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2508                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2509                     .count();
2510         }
2511         else if (property.first == "ExitUtilizationPercent")
2512         {
2513             const uint8_t* util = std::get_if<uint8_t>(&property.second);
2514             if (!util)
2515             {
2516                 return false;
2517             }
2518             aResp->res.jsonValue["IdlePowerSaver"][property.first] = *util;
2519         }
2520         else if (property.first == "ExitDwellTime")
2521         {
2522             // Convert Dbus time from milliseconds to seconds
2523             const uint64_t* timeMilliseconds =
2524                 std::get_if<uint64_t>(&property.second);
2525             if (!timeMilliseconds)
2526             {
2527                 return false;
2528             }
2529             const std::chrono::duration<uint64_t, std::milli> ms(
2530                 *timeMilliseconds);
2531             aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2532                 std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2533                     .count();
2534         }
2535         else
2536         {
2537             BMCWEB_LOG_WARNING << "Unexpected IdlePowerSaver property: "
2538                                << property.first;
2539         }
2540     }
2541 
2542     return true;
2543 }
2544 
2545 /**
2546  * @brief Retrieves host watchdog timer properties over DBUS
2547  *
2548  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2549  *
2550  * @return None.
2551  */
2552 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2553 {
2554     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2555 
2556     // Get IdlePowerSaver object path:
2557     crow::connections::systemBus->async_method_call(
2558         [aResp](
2559             const boost::system::error_code ec,
2560             const std::vector<std::pair<
2561                 std::string,
2562                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2563                 subtree) {
2564             if (ec)
2565             {
2566                 BMCWEB_LOG_DEBUG
2567                     << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2568                     << ec;
2569                 messages::internalError(aResp->res);
2570                 return;
2571             }
2572             if (subtree.empty())
2573             {
2574                 // This is an optional interface so just return
2575                 // if there is no instance found
2576                 BMCWEB_LOG_DEBUG << "No instances found";
2577                 return;
2578             }
2579             if (subtree.size() > 1)
2580             {
2581                 // More then one PowerIdlePowerSaver object is not supported and
2582                 // is an error
2583                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2584                                     "Power.IdlePowerSaver objects: "
2585                                  << subtree.size();
2586                 messages::internalError(aResp->res);
2587                 return;
2588             }
2589             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2590             {
2591                 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2592                 messages::internalError(aResp->res);
2593                 return;
2594             }
2595             const std::string& path = subtree[0].first;
2596             const std::string& service = subtree[0].second.begin()->first;
2597             if (service.empty())
2598             {
2599                 BMCWEB_LOG_DEBUG
2600                     << "Power.IdlePowerSaver service mapper error!";
2601                 messages::internalError(aResp->res);
2602                 return;
2603             }
2604 
2605             // Valid IdlePowerSaver object found, now read the current values
2606             crow::connections::systemBus->async_method_call(
2607                 [aResp](const boost::system::error_code ec,
2608                         ipsPropertiesType& properties) {
2609                     if (ec)
2610                     {
2611                         BMCWEB_LOG_ERROR
2612                             << "DBUS response error on IdlePowerSaver GetAll: "
2613                             << ec;
2614                         messages::internalError(aResp->res);
2615                         return;
2616                     }
2617 
2618                     if (parseIpsProperties(aResp, properties) == false)
2619                     {
2620                         messages::internalError(aResp->res);
2621                         return;
2622                     }
2623                 },
2624                 service, path, "org.freedesktop.DBus.Properties", "GetAll",
2625                 "xyz.openbmc_project.Control.Power.IdlePowerSaver");
2626         },
2627         "xyz.openbmc_project.ObjectMapper",
2628         "/xyz/openbmc_project/object_mapper",
2629         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2630         std::array<const char*, 1>{
2631             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2632 
2633     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2634 }
2635 
2636 /**
2637  * @brief Sets Idle Power Saver properties.
2638  *
2639  * @param[in] aResp      Shared pointer for generating response message.
2640  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2641  *                       RF request.
2642  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2643  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2644  * before entering idle state.
2645  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2646  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2647  * before exiting idle state
2648  *
2649  * @return None.
2650  */
2651 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2652                               const std::optional<bool> ipsEnable,
2653                               const std::optional<uint8_t> ipsEnterUtil,
2654                               const std::optional<uint64_t> ipsEnterTime,
2655                               const std::optional<uint8_t> ipsExitUtil,
2656                               const std::optional<uint64_t> ipsExitTime)
2657 {
2658     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2659 
2660     // Get IdlePowerSaver object path:
2661     crow::connections::systemBus->async_method_call(
2662         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2663          ipsExitTime](
2664             const boost::system::error_code ec,
2665             const std::vector<std::pair<
2666                 std::string,
2667                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2668                 subtree) {
2669             if (ec)
2670             {
2671                 BMCWEB_LOG_DEBUG
2672                     << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2673                     << ec;
2674                 messages::internalError(aResp->res);
2675                 return;
2676             }
2677             if (subtree.empty())
2678             {
2679                 // This is an optional D-Bus object, but user attempted to patch
2680                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2681                                            "IdlePowerSaver");
2682                 return;
2683             }
2684             if (subtree.size() > 1)
2685             {
2686                 // More then one PowerIdlePowerSaver object is not supported and
2687                 // is an error
2688                 BMCWEB_LOG_DEBUG
2689                     << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2690                     << subtree.size();
2691                 messages::internalError(aResp->res);
2692                 return;
2693             }
2694             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2695             {
2696                 BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2697                 messages::internalError(aResp->res);
2698                 return;
2699             }
2700             const std::string& path = subtree[0].first;
2701             const std::string& service = subtree[0].second.begin()->first;
2702             if (service.empty())
2703             {
2704                 BMCWEB_LOG_DEBUG
2705                     << "Power.IdlePowerSaver service mapper error!";
2706                 messages::internalError(aResp->res);
2707                 return;
2708             }
2709 
2710             // Valid Power IdlePowerSaver object found, now set any values that
2711             // need to be updated
2712 
2713             if (ipsEnable)
2714             {
2715                 crow::connections::systemBus->async_method_call(
2716                     [aResp](const boost::system::error_code ec) {
2717                         if (ec)
2718                         {
2719                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2720                             messages::internalError(aResp->res);
2721                             return;
2722                         }
2723                     },
2724                     service, path, "org.freedesktop.DBus.Properties", "Set",
2725                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2726                     "Enabled", std::variant<bool>(*ipsEnable));
2727             }
2728             if (ipsEnterUtil)
2729             {
2730                 crow::connections::systemBus->async_method_call(
2731                     [aResp](const boost::system::error_code ec) {
2732                         if (ec)
2733                         {
2734                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2735                             messages::internalError(aResp->res);
2736                             return;
2737                         }
2738                     },
2739                     service, path, "org.freedesktop.DBus.Properties", "Set",
2740                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2741                     "EnterUtilizationPercent",
2742                     std::variant<uint8_t>(*ipsEnterUtil));
2743             }
2744             if (ipsEnterTime)
2745             {
2746                 // Convert from seconds into milliseconds for DBus
2747                 const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2748                 crow::connections::systemBus->async_method_call(
2749                     [aResp](const boost::system::error_code ec) {
2750                         if (ec)
2751                         {
2752                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2753                             messages::internalError(aResp->res);
2754                             return;
2755                         }
2756                     },
2757                     service, path, "org.freedesktop.DBus.Properties", "Set",
2758                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2759                     "EnterDwellTime", std::variant<uint64_t>(timeMilliseconds));
2760             }
2761             if (ipsExitUtil)
2762             {
2763                 crow::connections::systemBus->async_method_call(
2764                     [aResp](const boost::system::error_code ec) {
2765                         if (ec)
2766                         {
2767                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2768                             messages::internalError(aResp->res);
2769                             return;
2770                         }
2771                     },
2772                     service, path, "org.freedesktop.DBus.Properties", "Set",
2773                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2774                     "ExitUtilizationPercent",
2775                     std::variant<uint8_t>(*ipsExitUtil));
2776             }
2777             if (ipsExitTime)
2778             {
2779                 // Convert from seconds into milliseconds for DBus
2780                 const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2781                 crow::connections::systemBus->async_method_call(
2782                     [aResp](const boost::system::error_code ec) {
2783                         if (ec)
2784                         {
2785                             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2786                             messages::internalError(aResp->res);
2787                             return;
2788                         }
2789                     },
2790                     service, path, "org.freedesktop.DBus.Properties", "Set",
2791                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2792                     "ExitDwellTime", std::variant<uint64_t>(timeMilliseconds));
2793             }
2794         },
2795         "xyz.openbmc_project.ObjectMapper",
2796         "/xyz/openbmc_project/object_mapper",
2797         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2798         std::array<const char*, 1>{
2799             "xyz.openbmc_project.Control.Power.IdlePowerSaver"});
2800 
2801     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2802 }
2803 
2804 /**
2805  * SystemsCollection derived class for delivering ComputerSystems Collection
2806  * Schema
2807  */
2808 inline void requestRoutesSystemsCollection(App& app)
2809 {
2810     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2811         .privileges(redfish::privileges::getComputerSystemCollection)
2812         .methods(boost::beast::http::verb::get)(
2813             [](const crow::Request& /*req*/,
2814                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2815                 asyncResp->res.jsonValue["@odata.type"] =
2816                     "#ComputerSystemCollection.ComputerSystemCollection";
2817                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2818                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2819 
2820                 crow::connections::systemBus->async_method_call(
2821                     [asyncResp](const boost::system::error_code ec,
2822                                 const std::variant<std::string>& /*hostName*/) {
2823                         nlohmann::json& ifaceArray =
2824                             asyncResp->res.jsonValue["Members"];
2825                         ifaceArray = nlohmann::json::array();
2826                         auto& count =
2827                             asyncResp->res.jsonValue["Members@odata.count"];
2828                         ifaceArray.push_back(
2829                             {{"@odata.id", "/redfish/v1/Systems/system"}});
2830                         count = ifaceArray.size();
2831                         if (!ec)
2832                         {
2833                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
2834                             ifaceArray.push_back(
2835                                 {{"@odata.id",
2836                                   "/redfish/v1/Systems/hypervisor"}});
2837                             count = ifaceArray.size();
2838                         }
2839                     },
2840                     "xyz.openbmc_project.Settings",
2841                     "/xyz/openbmc_project/network/hypervisor",
2842                     "org.freedesktop.DBus.Properties", "Get",
2843                     "xyz.openbmc_project.Network.SystemConfiguration",
2844                     "HostName");
2845             });
2846 }
2847 
2848 /**
2849  * Function transceives data with dbus directly.
2850  */
2851 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2852 {
2853     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2854     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2855     constexpr char const* interfaceName =
2856         "xyz.openbmc_project.Control.Host.NMI";
2857     constexpr char const* method = "NMI";
2858 
2859     crow::connections::systemBus->async_method_call(
2860         [asyncResp](const boost::system::error_code ec) {
2861             if (ec)
2862             {
2863                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2864                 messages::internalError(asyncResp->res);
2865                 return;
2866             }
2867             messages::success(asyncResp->res);
2868         },
2869         serviceName, objectPath, interfaceName, method);
2870 }
2871 
2872 /**
2873  * SystemActionsReset class supports handle POST method for Reset action.
2874  * The class retrieves and sends data directly to D-Bus.
2875  */
2876 inline void requestRoutesSystemActionsReset(App& app)
2877 {
2878     /**
2879      * Function handles POST method request.
2880      * Analyzes POST body message before sends Reset request data to D-Bus.
2881      */
2882     BMCWEB_ROUTE(app,
2883                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2884         .privileges(redfish::privileges::postComputerSystem)
2885         .methods(
2886             boost::beast::http::verb::
2887                 post)([](const crow::Request& req,
2888                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2889             std::string resetType;
2890             if (!json_util::readJson(req, asyncResp->res, "ResetType",
2891                                      resetType))
2892             {
2893                 return;
2894             }
2895 
2896             // Get the command and host vs. chassis
2897             std::string command;
2898             bool hostCommand;
2899             if ((resetType == "On") || (resetType == "ForceOn"))
2900             {
2901                 command = "xyz.openbmc_project.State.Host.Transition.On";
2902                 hostCommand = true;
2903             }
2904             else if (resetType == "ForceOff")
2905             {
2906                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2907                 hostCommand = false;
2908             }
2909             else if (resetType == "ForceRestart")
2910             {
2911                 command =
2912                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2913                 hostCommand = true;
2914             }
2915             else if (resetType == "GracefulShutdown")
2916             {
2917                 command = "xyz.openbmc_project.State.Host.Transition.Off";
2918                 hostCommand = true;
2919             }
2920             else if (resetType == "GracefulRestart")
2921             {
2922                 command =
2923                     "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2924                 hostCommand = true;
2925             }
2926             else if (resetType == "PowerCycle")
2927             {
2928                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2929                 hostCommand = true;
2930             }
2931             else if (resetType == "Nmi")
2932             {
2933                 doNMI(asyncResp);
2934                 return;
2935             }
2936             else
2937             {
2938                 messages::actionParameterUnknown(asyncResp->res, "Reset",
2939                                                  resetType);
2940                 return;
2941             }
2942 
2943             if (hostCommand)
2944             {
2945                 crow::connections::systemBus->async_method_call(
2946                     [asyncResp, resetType](const boost::system::error_code ec) {
2947                         if (ec)
2948                         {
2949                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2950                             if (ec.value() ==
2951                                 boost::asio::error::invalid_argument)
2952                             {
2953                                 messages::actionParameterNotSupported(
2954                                     asyncResp->res, resetType, "Reset");
2955                             }
2956                             else
2957                             {
2958                                 messages::internalError(asyncResp->res);
2959                             }
2960                             return;
2961                         }
2962                         messages::success(asyncResp->res);
2963                     },
2964                     "xyz.openbmc_project.State.Host",
2965                     "/xyz/openbmc_project/state/host0",
2966                     "org.freedesktop.DBus.Properties", "Set",
2967                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2968                     std::variant<std::string>{command});
2969             }
2970             else
2971             {
2972                 crow::connections::systemBus->async_method_call(
2973                     [asyncResp, resetType](const boost::system::error_code ec) {
2974                         if (ec)
2975                         {
2976                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2977                             if (ec.value() ==
2978                                 boost::asio::error::invalid_argument)
2979                             {
2980                                 messages::actionParameterNotSupported(
2981                                     asyncResp->res, resetType, "Reset");
2982                             }
2983                             else
2984                             {
2985                                 messages::internalError(asyncResp->res);
2986                             }
2987                             return;
2988                         }
2989                         messages::success(asyncResp->res);
2990                     },
2991                     "xyz.openbmc_project.State.Chassis",
2992                     "/xyz/openbmc_project/state/chassis0",
2993                     "org.freedesktop.DBus.Properties", "Set",
2994                     "xyz.openbmc_project.State.Chassis",
2995                     "RequestedPowerTransition",
2996                     std::variant<std::string>{command});
2997             }
2998         });
2999 }
3000 
3001 /**
3002  * Systems derived class for delivering Computer Systems Schema.
3003  */
3004 inline void requestRoutesSystems(App& app)
3005 {
3006 
3007     /**
3008      * Functions triggers appropriate requests on DBus
3009      */
3010     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
3011         .privileges(redfish::privileges::getComputerSystem)
3012         .methods(
3013             boost::beast::http::verb::
3014                 get)([](const crow::Request&,
3015                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3016             asyncResp->res.jsonValue["@odata.type"] =
3017                 "#ComputerSystem.v1_16_0.ComputerSystem";
3018             asyncResp->res.jsonValue["Name"] = "system";
3019             asyncResp->res.jsonValue["Id"] = "system";
3020             asyncResp->res.jsonValue["SystemType"] = "Physical";
3021             asyncResp->res.jsonValue["Description"] = "Computer System";
3022             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
3023             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
3024                 "Disabled";
3025             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
3026                 uint64_t(0);
3027             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
3028                 "Disabled";
3029             asyncResp->res.jsonValue["@odata.id"] =
3030                 "/redfish/v1/Systems/system";
3031 
3032             asyncResp->res.jsonValue["Processors"] = {
3033                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
3034             asyncResp->res.jsonValue["Memory"] = {
3035                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
3036             asyncResp->res.jsonValue["Storage"] = {
3037                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
3038 
3039             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
3040                 {"target",
3041                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
3042                 {"@Redfish.ActionInfo",
3043                  "/redfish/v1/Systems/system/ResetActionInfo"}};
3044 
3045             asyncResp->res.jsonValue["LogServices"] = {
3046                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
3047 
3048             asyncResp->res.jsonValue["Bios"] = {
3049                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
3050 
3051             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
3052                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
3053 
3054             asyncResp->res.jsonValue["Status"] = {
3055                 {"Health", "OK"},
3056                 {"State", "Enabled"},
3057             };
3058 
3059             // Fill in SerialConsole info
3060             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
3061                 15;
3062             asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = {
3063                 {"ServiceEnabled", true},
3064             };
3065             // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
3066             asyncResp->res.jsonValue["SerialConsole"]["SSH"] = {
3067                 {"ServiceEnabled", true},
3068                 {"Port", 2200},
3069                 // https://github.com/openbmc/docs/blob/master/console.md
3070                 {"HotKeySequenceDisplay", "Press ~. to exit console"},
3071             };
3072 
3073 #ifdef BMCWEB_ENABLE_KVM
3074             // Fill in GraphicalConsole info
3075             asyncResp->res.jsonValue["GraphicalConsole"] = {
3076                 {"ServiceEnabled", true},
3077                 {"MaxConcurrentSessions", 4},
3078                 {"ConnectTypesSupported", {"KVMIP"}},
3079             };
3080 #endif // BMCWEB_ENABLE_KVM
3081             constexpr const std::array<const char*, 4> inventoryForSystems = {
3082                 "xyz.openbmc_project.Inventory.Item.Dimm",
3083                 "xyz.openbmc_project.Inventory.Item.Cpu",
3084                 "xyz.openbmc_project.Inventory.Item.Drive",
3085                 "xyz.openbmc_project.Inventory.Item.StorageController"};
3086 
3087             auto health = std::make_shared<HealthPopulate>(asyncResp);
3088             crow::connections::systemBus->async_method_call(
3089                 [health](const boost::system::error_code ec,
3090                          std::vector<std::string>& resp) {
3091                     if (ec)
3092                     {
3093                         // no inventory
3094                         return;
3095                     }
3096 
3097                     health->inventory = std::move(resp);
3098                 },
3099                 "xyz.openbmc_project.ObjectMapper",
3100                 "/xyz/openbmc_project/object_mapper",
3101                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
3102                 int32_t(0), inventoryForSystems);
3103 
3104             health->populate();
3105 
3106             getMainChassisId(
3107                 asyncResp, [](const std::string& chassisId,
3108                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3109                     aRsp->res.jsonValue["Links"]["Chassis"] = {
3110                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
3111                 });
3112 
3113             getLocationIndicatorActive(asyncResp);
3114             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3115             getIndicatorLedState(asyncResp);
3116             getComputerSystem(asyncResp, health);
3117             getHostState(asyncResp);
3118             getBootProperties(asyncResp);
3119             getBootProgress(asyncResp);
3120             getPCIeDeviceList(asyncResp, "PCIeDevices");
3121             getHostWatchdogTimer(asyncResp);
3122             getPowerRestorePolicy(asyncResp);
3123             getAutomaticRetry(asyncResp);
3124             getLastResetTime(asyncResp);
3125 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
3126             getProvisioningStatus(asyncResp);
3127 #endif
3128             getTrustedModuleRequiredToBoot(asyncResp);
3129             getPowerMode(asyncResp);
3130             getIdlePowerSaver(asyncResp);
3131         });
3132     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
3133         .privileges(redfish::privileges::patchComputerSystem)
3134         .methods(boost::beast::http::verb::patch)(
3135             [](const crow::Request& req,
3136                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3137                 std::optional<bool> locationIndicatorActive;
3138                 std::optional<std::string> indicatorLed;
3139                 std::optional<nlohmann::json> bootProps;
3140                 std::optional<nlohmann::json> wdtTimerProps;
3141                 std::optional<std::string> assetTag;
3142                 std::optional<std::string> powerRestorePolicy;
3143                 std::optional<std::string> powerMode;
3144                 std::optional<nlohmann::json> ipsProps;
3145                 if (!json_util::readJson(
3146                         req, asyncResp->res, "IndicatorLED", indicatorLed,
3147                         "LocationIndicatorActive", locationIndicatorActive,
3148                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
3149                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
3150                         assetTag, "PowerMode", powerMode, "IdlePowerSaver",
3151                         ipsProps))
3152                 {
3153                     return;
3154                 }
3155 
3156                 asyncResp->res.result(boost::beast::http::status::no_content);
3157 
3158                 if (assetTag)
3159                 {
3160                     setAssetTag(asyncResp, *assetTag);
3161                 }
3162 
3163                 if (wdtTimerProps)
3164                 {
3165                     std::optional<bool> wdtEnable;
3166                     std::optional<std::string> wdtTimeOutAction;
3167 
3168                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
3169                                              "FunctionEnabled", wdtEnable,
3170                                              "TimeoutAction", wdtTimeOutAction))
3171                     {
3172                         return;
3173                     }
3174                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3175                 }
3176 
3177                 if (bootProps)
3178                 {
3179                     std::optional<std::string> bootSource;
3180                     std::optional<std::string> bootType;
3181                     std::optional<std::string> bootEnable;
3182                     std::optional<std::string> automaticRetryConfig;
3183                     std::optional<bool> trustedModuleRequiredToBoot;
3184 
3185                     if (!json_util::readJson(
3186                             *bootProps, asyncResp->res,
3187                             "BootSourceOverrideTarget", bootSource,
3188                             "BootSourceOverrideMode", bootType,
3189                             "BootSourceOverrideEnabled", bootEnable,
3190                             "AutomaticRetryConfig", automaticRetryConfig,
3191                             "TrustedModuleRequiredToBoot",
3192                             trustedModuleRequiredToBoot))
3193                     {
3194                         return;
3195                     }
3196 
3197                     if (bootSource || bootType || bootEnable)
3198                     {
3199                         setBootProperties(asyncResp, bootSource, bootType,
3200                                           bootEnable);
3201                     }
3202                     if (automaticRetryConfig)
3203                     {
3204                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
3205                     }
3206 
3207                     if (trustedModuleRequiredToBoot)
3208                     {
3209                         setTrustedModuleRequiredToBoot(
3210                             asyncResp, *trustedModuleRequiredToBoot);
3211                     }
3212                 }
3213 
3214                 if (locationIndicatorActive)
3215                 {
3216                     setLocationIndicatorActive(asyncResp,
3217                                                *locationIndicatorActive);
3218                 }
3219 
3220                 // TODO (Gunnar): Remove IndicatorLED after enough time has
3221                 // passed
3222                 if (indicatorLed)
3223                 {
3224                     setIndicatorLedState(asyncResp, *indicatorLed);
3225                     asyncResp->res.addHeader(
3226                         boost::beast::http::field::warning,
3227                         "299 - \"IndicatorLED is deprecated. Use "
3228                         "LocationIndicatorActive instead.\"");
3229                 }
3230 
3231                 if (powerRestorePolicy)
3232                 {
3233                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3234                 }
3235 
3236                 if (powerMode)
3237                 {
3238                     setPowerMode(asyncResp, *powerMode);
3239                 }
3240 
3241                 if (ipsProps)
3242                 {
3243                     std::optional<bool> ipsEnable;
3244                     std::optional<uint8_t> ipsEnterUtil;
3245                     std::optional<uint64_t> ipsEnterTime;
3246                     std::optional<uint8_t> ipsExitUtil;
3247                     std::optional<uint64_t> ipsExitTime;
3248 
3249                     if (!json_util::readJson(
3250                             *ipsProps, asyncResp->res, "Enabled", ipsEnable,
3251                             "EnterUtilizationPercent", ipsEnterUtil,
3252                             "EnterDwellTimeSeconds", ipsEnterTime,
3253                             "ExitUtilizationPercent", ipsExitUtil,
3254                             "ExitDwellTimeSeconds", ipsExitTime))
3255                     {
3256                         return;
3257                     }
3258                     setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil,
3259                                       ipsEnterTime, ipsExitUtil, ipsExitTime);
3260                 }
3261             });
3262 }
3263 
3264 /**
3265  * SystemResetActionInfo derived class for delivering Computer Systems
3266  * ResetType AllowableValues using ResetInfo schema.
3267  */
3268 inline void requestRoutesSystemResetActionInfo(App& app)
3269 {
3270 
3271     /**
3272      * Functions triggers appropriate requests on DBus
3273      */
3274     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3275         .privileges(redfish::privileges::getActionInfo)
3276         .methods(boost::beast::http::verb::get)(
3277             [](const crow::Request&,
3278                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3279                 asyncResp->res.jsonValue = {
3280                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
3281                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
3282                     {"Name", "Reset Action Info"},
3283                     {"Id", "ResetActionInfo"},
3284                     {"Parameters",
3285                      {{{"Name", "ResetType"},
3286                        {"Required", true},
3287                        {"DataType", "String"},
3288                        {"AllowableValues",
3289                         {"On", "ForceOff", "ForceOn", "ForceRestart",
3290                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
3291                          "Nmi"}}}}}};
3292             });
3293 }
3294 } // namespace redfish
3295