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