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