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