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