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