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