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