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