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