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