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