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