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