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