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