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