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