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