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