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