xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 33c6b58026e5dd3bc600d152a07b95f863bfa1a7)
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 Automatic Retry properties. Known on D-Bus as AutoReboot.
1154  *
1155  * @param[in] aResp     Shared pointer for generating response message.
1156  *
1157  * @return None.
1158  */
1159 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1160 {
1161     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1162 
1163     sdbusplus::asio::getProperty<bool>(
1164         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1165         "/xyz/openbmc_project/control/host0/auto_reboot",
1166         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1167         [aResp](const boost::system::error_code& ec, bool autoRebootEnabled) {
1168         if (ec)
1169         {
1170             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1171             return;
1172         }
1173 
1174         BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled;
1175         if (autoRebootEnabled)
1176         {
1177             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1178                 "RetryAttempts";
1179             // If AutomaticRetry (AutoReboot) is enabled see how many
1180             // attempts are left
1181             sdbusplus::asio::getProperty<uint32_t>(
1182                 *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
1183                 "/xyz/openbmc_project/state/host0",
1184                 "xyz.openbmc_project.Control.Boot.RebootAttempts",
1185                 "AttemptsLeft",
1186                 [aResp](const boost::system::error_code& ec2,
1187                         const uint32_t autoRebootAttemptsLeft) {
1188                 if (ec2)
1189                 {
1190                     BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1191                     return;
1192                 }
1193 
1194                 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1195                                  << autoRebootAttemptsLeft;
1196 
1197                 aResp->res
1198                     .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1199                     autoRebootAttemptsLeft;
1200                 });
1201         }
1202         else
1203         {
1204             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled";
1205         }
1206 
1207         // Not on D-Bus. Hardcoded here:
1208         // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1209         aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1210 
1211         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1212         // and RetryAttempts. OpenBMC only supports Disabled and
1213         // RetryAttempts.
1214         aResp->res.jsonValue["Boot"]
1215                             ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1216             "Disabled", "RetryAttempts"};
1217         });
1218 }
1219 
1220 /**
1221  * @brief Retrieves power restore policy over DBUS.
1222  *
1223  * @param[in] aResp     Shared pointer for generating response message.
1224  *
1225  * @return None.
1226  */
1227 inline void
1228     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1229 {
1230     BMCWEB_LOG_DEBUG << "Get power restore policy";
1231 
1232     sdbusplus::asio::getProperty<std::string>(
1233         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1234         "/xyz/openbmc_project/control/host0/power_restore_policy",
1235         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1236         [aResp](const boost::system::error_code& ec,
1237                 const std::string& policy) {
1238         if (ec)
1239         {
1240             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1241             return;
1242         }
1243 
1244         const boost::container::flat_map<std::string, std::string> policyMaps = {
1245             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1246              "AlwaysOn"},
1247             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1248              "AlwaysOff"},
1249             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1250              "LastState"},
1251             // Return `AlwaysOff` when power restore policy set to "None"
1252             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None",
1253              "AlwaysOff"}};
1254 
1255         auto policyMapsIt = policyMaps.find(policy);
1256         if (policyMapsIt == policyMaps.end())
1257         {
1258             messages::internalError(aResp->res);
1259             return;
1260         }
1261 
1262         aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1263         });
1264 }
1265 
1266 /**
1267  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1268  * TPM is required for booting the host.
1269  *
1270  * @param[in] aResp     Shared pointer for generating response message.
1271  *
1272  * @return None.
1273  */
1274 inline void getTrustedModuleRequiredToBoot(
1275     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1276 {
1277     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1278     constexpr std::array<std::string_view, 1> interfaces = {
1279         "xyz.openbmc_project.Control.TPM.Policy"};
1280     dbus::utility::getSubTree(
1281         "/", 0, interfaces,
1282         [aResp](const boost::system::error_code& ec,
1283                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1284         if (ec)
1285         {
1286             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1287                              << ec;
1288             // This is an optional D-Bus object so just return if
1289             // error occurs
1290             return;
1291         }
1292         if (subtree.empty())
1293         {
1294             // As noted above, this is an optional interface so just return
1295             // if there is no instance found
1296             return;
1297         }
1298 
1299         /* When there is more than one TPMEnable object... */
1300         if (subtree.size() > 1)
1301         {
1302             BMCWEB_LOG_DEBUG
1303                 << "DBUS response has more than 1 TPM Enable object:"
1304                 << subtree.size();
1305             // Throw an internal Error and return
1306             messages::internalError(aResp->res);
1307             return;
1308         }
1309 
1310         // Make sure the Dbus response map has a service and objectPath
1311         // field
1312         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1313         {
1314             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1315             messages::internalError(aResp->res);
1316             return;
1317         }
1318 
1319         const std::string& path = subtree[0].first;
1320         const std::string& serv = subtree[0].second.begin()->first;
1321 
1322         // Valid TPM Enable object found, now reading the current value
1323         sdbusplus::asio::getProperty<bool>(
1324             *crow::connections::systemBus, serv, path,
1325             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1326             [aResp](const boost::system::error_code& ec2, bool tpmRequired) {
1327             if (ec2)
1328             {
1329                 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get"
1330                                  << ec2;
1331                 messages::internalError(aResp->res);
1332                 return;
1333             }
1334 
1335             if (tpmRequired)
1336             {
1337                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1338                     "Required";
1339             }
1340             else
1341             {
1342                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1343                     "Disabled";
1344             }
1345             });
1346         });
1347 }
1348 
1349 /**
1350  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1351  * TPM is required for booting the host.
1352  *
1353  * @param[in] aResp         Shared pointer for generating response message.
1354  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1355  *
1356  * @return None.
1357  */
1358 inline void setTrustedModuleRequiredToBoot(
1359     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1360 {
1361     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1362     constexpr std::array<std::string_view, 1> interfaces = {
1363         "xyz.openbmc_project.Control.TPM.Policy"};
1364     dbus::utility::getSubTree(
1365         "/", 0, interfaces,
1366         [aResp,
1367          tpmRequired](const boost::system::error_code& ec,
1368                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
1369         if (ec)
1370         {
1371             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1372                              << ec;
1373             messages::internalError(aResp->res);
1374             return;
1375         }
1376         if (subtree.empty())
1377         {
1378             messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1379                                              "TrustedModuleRequiredToBoot");
1380             return;
1381         }
1382 
1383         /* When there is more than one TPMEnable object... */
1384         if (subtree.size() > 1)
1385         {
1386             BMCWEB_LOG_DEBUG
1387                 << "DBUS response has more than 1 TPM Enable object:"
1388                 << subtree.size();
1389             // Throw an internal Error and return
1390             messages::internalError(aResp->res);
1391             return;
1392         }
1393 
1394         // Make sure the Dbus response map has a service and objectPath
1395         // field
1396         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1397         {
1398             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1399             messages::internalError(aResp->res);
1400             return;
1401         }
1402 
1403         const std::string& path = subtree[0].first;
1404         const std::string& serv = subtree[0].second.begin()->first;
1405 
1406         if (serv.empty())
1407         {
1408             BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1409             messages::internalError(aResp->res);
1410             return;
1411         }
1412 
1413         // Valid TPM Enable object found, now setting the value
1414         crow::connections::systemBus->async_method_call(
1415             [aResp](const boost::system::error_code& ec2) {
1416             if (ec2)
1417             {
1418                 BMCWEB_LOG_DEBUG
1419                     << "DBUS response error: Set TrustedModuleRequiredToBoot"
1420                     << ec2;
1421                 messages::internalError(aResp->res);
1422                 return;
1423             }
1424             BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1425             },
1426             serv, path, "org.freedesktop.DBus.Properties", "Set",
1427             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1428             dbus::utility::DbusVariantType(tpmRequired));
1429         });
1430 }
1431 
1432 /**
1433  * @brief Sets boot properties into DBUS object(s).
1434  *
1435  * @param[in] aResp           Shared pointer for generating response message.
1436  * @param[in] bootType        The boot type to set.
1437  * @return Integer error code.
1438  */
1439 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1440                         const std::optional<std::string>& bootType)
1441 {
1442     std::string bootTypeStr;
1443 
1444     if (!bootType)
1445     {
1446         return;
1447     }
1448 
1449     // Source target specified
1450     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1451     // Figure out which DBUS interface and property to use
1452     if (*bootType == "Legacy")
1453     {
1454         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1455     }
1456     else if (*bootType == "UEFI")
1457     {
1458         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1459     }
1460     else
1461     {
1462         BMCWEB_LOG_DEBUG << "Invalid property value for "
1463                             "BootSourceOverrideMode: "
1464                          << *bootType;
1465         messages::propertyValueNotInList(aResp->res, *bootType,
1466                                          "BootSourceOverrideMode");
1467         return;
1468     }
1469 
1470     // Act on validated parameters
1471     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1472 
1473     crow::connections::systemBus->async_method_call(
1474         [aResp](const boost::system::error_code& ec) {
1475         if (ec)
1476         {
1477             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1478             if (ec.value() == boost::asio::error::host_unreachable)
1479             {
1480                 messages::resourceNotFound(aResp->res, "Set", "BootType");
1481                 return;
1482             }
1483             messages::internalError(aResp->res);
1484             return;
1485         }
1486         BMCWEB_LOG_DEBUG << "Boot type update done.";
1487         },
1488         "xyz.openbmc_project.Settings",
1489         "/xyz/openbmc_project/control/host0/boot",
1490         "org.freedesktop.DBus.Properties", "Set",
1491         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1492         dbus::utility::DbusVariantType(bootTypeStr));
1493 }
1494 
1495 /**
1496  * @brief Sets boot properties into DBUS object(s).
1497  *
1498  * @param[in] aResp           Shared pointer for generating response message.
1499  * @param[in] bootType        The boot type to set.
1500  * @return Integer error code.
1501  */
1502 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1503                           const std::optional<std::string>& bootEnable)
1504 {
1505     if (!bootEnable)
1506     {
1507         return;
1508     }
1509     // Source target specified
1510     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1511 
1512     bool bootOverrideEnable = false;
1513     bool bootOverridePersistent = false;
1514     // Figure out which DBUS interface and property to use
1515     if (*bootEnable == "Disabled")
1516     {
1517         bootOverrideEnable = false;
1518     }
1519     else if (*bootEnable == "Once")
1520     {
1521         bootOverrideEnable = true;
1522         bootOverridePersistent = false;
1523     }
1524     else if (*bootEnable == "Continuous")
1525     {
1526         bootOverrideEnable = true;
1527         bootOverridePersistent = true;
1528     }
1529     else
1530     {
1531         BMCWEB_LOG_DEBUG
1532             << "Invalid property value for BootSourceOverrideEnabled: "
1533             << *bootEnable;
1534         messages::propertyValueNotInList(aResp->res, *bootEnable,
1535                                          "BootSourceOverrideEnabled");
1536         return;
1537     }
1538 
1539     // Act on validated parameters
1540     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1541 
1542     crow::connections::systemBus->async_method_call(
1543         [aResp](const boost::system::error_code& ec2) {
1544         if (ec2)
1545         {
1546             BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
1547             messages::internalError(aResp->res);
1548             return;
1549         }
1550         BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1551         },
1552         "xyz.openbmc_project.Settings",
1553         "/xyz/openbmc_project/control/host0/boot",
1554         "org.freedesktop.DBus.Properties", "Set",
1555         "xyz.openbmc_project.Object.Enable", "Enabled",
1556         dbus::utility::DbusVariantType(bootOverrideEnable));
1557 
1558     if (!bootOverrideEnable)
1559     {
1560         return;
1561     }
1562 
1563     // In case boot override is enabled we need to set correct value for the
1564     // 'one_time' enable DBus interface
1565     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1566                      << bootOverridePersistent;
1567 
1568     crow::connections::systemBus->async_method_call(
1569         [aResp](const boost::system::error_code& ec) {
1570         if (ec)
1571         {
1572             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1573             messages::internalError(aResp->res);
1574             return;
1575         }
1576         BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1577         },
1578         "xyz.openbmc_project.Settings",
1579         "/xyz/openbmc_project/control/host0/boot/one_time",
1580         "org.freedesktop.DBus.Properties", "Set",
1581         "xyz.openbmc_project.Object.Enable", "Enabled",
1582         dbus::utility::DbusVariantType(!bootOverridePersistent));
1583 }
1584 
1585 /**
1586  * @brief Sets boot properties into DBUS object(s).
1587  *
1588  * @param[in] aResp           Shared pointer for generating response message.
1589  * @param[in] bootSource      The boot source to set.
1590  *
1591  * @return Integer error code.
1592  */
1593 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1594                                 const std::optional<std::string>& bootSource)
1595 {
1596     std::string bootSourceStr;
1597     std::string bootModeStr;
1598 
1599     if (!bootSource)
1600     {
1601         return;
1602     }
1603 
1604     // Source target specified
1605     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1606     // Figure out which DBUS interface and property to use
1607     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) !=
1608         0)
1609     {
1610         BMCWEB_LOG_DEBUG
1611             << "Invalid property value for BootSourceOverrideTarget: "
1612             << *bootSource;
1613         messages::propertyValueNotInList(aResp->res, *bootSource,
1614                                          "BootSourceTargetOverride");
1615         return;
1616     }
1617 
1618     // Act on validated parameters
1619     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1620     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1621 
1622     crow::connections::systemBus->async_method_call(
1623         [aResp](const boost::system::error_code& ec) {
1624         if (ec)
1625         {
1626             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1627             messages::internalError(aResp->res);
1628             return;
1629         }
1630         BMCWEB_LOG_DEBUG << "Boot source update done.";
1631         },
1632         "xyz.openbmc_project.Settings",
1633         "/xyz/openbmc_project/control/host0/boot",
1634         "org.freedesktop.DBus.Properties", "Set",
1635         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1636         dbus::utility::DbusVariantType(bootSourceStr));
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 mode update done.";
1647         },
1648         "xyz.openbmc_project.Settings",
1649         "/xyz/openbmc_project/control/host0/boot",
1650         "org.freedesktop.DBus.Properties", "Set",
1651         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1652         dbus::utility::DbusVariantType(bootModeStr));
1653 }
1654 
1655 /**
1656  * @brief Sets Boot source override properties.
1657  *
1658  * @param[in] aResp      Shared pointer for generating response message.
1659  * @param[in] bootSource The boot source from incoming RF request.
1660  * @param[in] bootType   The boot type from incoming RF request.
1661  * @param[in] bootEnable The boot override enable from incoming RF request.
1662  *
1663  * @return Integer error code.
1664  */
1665 
1666 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1667                               const std::optional<std::string>& bootSource,
1668                               const std::optional<std::string>& bootType,
1669                               const std::optional<std::string>& bootEnable)
1670 {
1671     BMCWEB_LOG_DEBUG << "Set boot information.";
1672 
1673     setBootModeOrSource(aResp, bootSource);
1674     setBootType(aResp, bootType);
1675     setBootEnable(aResp, bootEnable);
1676 }
1677 
1678 /**
1679  * @brief Sets AssetTag
1680  *
1681  * @param[in] aResp   Shared pointer for generating response message.
1682  * @param[in] assetTag  "AssetTag" from request.
1683  *
1684  * @return None.
1685  */
1686 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1687                         const std::string& assetTag)
1688 {
1689     constexpr std::array<std::string_view, 1> interfaces = {
1690         "xyz.openbmc_project.Inventory.Item.System"};
1691     dbus::utility::getSubTree(
1692         "/xyz/openbmc_project/inventory", 0, interfaces,
1693         [aResp,
1694          assetTag](const boost::system::error_code& ec,
1695                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
1696         if (ec)
1697         {
1698             BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1699             messages::internalError(aResp->res);
1700             return;
1701         }
1702         if (subtree.empty())
1703         {
1704             BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1705             messages::internalError(aResp->res);
1706             return;
1707         }
1708         // Assume only 1 system D-Bus object
1709         // Throw an error if there is more than 1
1710         if (subtree.size() > 1)
1711         {
1712             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1713             messages::internalError(aResp->res);
1714             return;
1715         }
1716         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1717         {
1718             BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1719             messages::internalError(aResp->res);
1720             return;
1721         }
1722 
1723         const std::string& path = subtree[0].first;
1724         const std::string& service = subtree[0].second.begin()->first;
1725 
1726         if (service.empty())
1727         {
1728             BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1729             messages::internalError(aResp->res);
1730             return;
1731         }
1732 
1733         crow::connections::systemBus->async_method_call(
1734             [aResp](const boost::system::error_code& ec2) {
1735             if (ec2)
1736             {
1737                 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set "
1738                                  << ec2;
1739                 messages::internalError(aResp->res);
1740                 return;
1741             }
1742             },
1743             service, path, "org.freedesktop.DBus.Properties", "Set",
1744             "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1745             dbus::utility::DbusVariantType(assetTag));
1746         });
1747 }
1748 
1749 /**
1750  * @brief Sets automaticRetry (Auto Reboot)
1751  *
1752  * @param[in] aResp   Shared pointer for generating response message.
1753  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1754  *
1755  * @return None.
1756  */
1757 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1758                               const std::string& automaticRetryConfig)
1759 {
1760     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1761 
1762     // OpenBMC only supports "Disabled" and "RetryAttempts".
1763     bool autoRebootEnabled = false;
1764 
1765     if (automaticRetryConfig == "Disabled")
1766     {
1767         autoRebootEnabled = false;
1768     }
1769     else if (automaticRetryConfig == "RetryAttempts")
1770     {
1771         autoRebootEnabled = true;
1772     }
1773     else
1774     {
1775         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1776                          << automaticRetryConfig;
1777         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1778                                          "AutomaticRetryConfig");
1779         return;
1780     }
1781 
1782     crow::connections::systemBus->async_method_call(
1783         [aResp](const boost::system::error_code& ec) {
1784         if (ec)
1785         {
1786             messages::internalError(aResp->res);
1787             return;
1788         }
1789         },
1790         "xyz.openbmc_project.Settings",
1791         "/xyz/openbmc_project/control/host0/auto_reboot",
1792         "org.freedesktop.DBus.Properties", "Set",
1793         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1794         dbus::utility::DbusVariantType(autoRebootEnabled));
1795 }
1796 
1797 /**
1798  * @brief Sets power restore policy properties.
1799  *
1800  * @param[in] aResp   Shared pointer for generating response message.
1801  * @param[in] policy  power restore policy properties from request.
1802  *
1803  * @return None.
1804  */
1805 inline void
1806     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1807                           const std::string& policy)
1808 {
1809     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1810 
1811     const boost::container::flat_map<std::string, std::string> policyMaps = {
1812         {"AlwaysOn",
1813          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1814         {"AlwaysOff",
1815          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1816         {"LastState",
1817          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1818 
1819     std::string powerRestorPolicy;
1820 
1821     auto policyMapsIt = policyMaps.find(policy);
1822     if (policyMapsIt == policyMaps.end())
1823     {
1824         messages::propertyValueNotInList(aResp->res, policy,
1825                                          "PowerRestorePolicy");
1826         return;
1827     }
1828 
1829     powerRestorPolicy = policyMapsIt->second;
1830 
1831     crow::connections::systemBus->async_method_call(
1832         [aResp](const boost::system::error_code& ec) {
1833         if (ec)
1834         {
1835             messages::internalError(aResp->res);
1836             return;
1837         }
1838         },
1839         "xyz.openbmc_project.Settings",
1840         "/xyz/openbmc_project/control/host0/power_restore_policy",
1841         "org.freedesktop.DBus.Properties", "Set",
1842         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1843         dbus::utility::DbusVariantType(powerRestorPolicy));
1844 }
1845 
1846 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1847 /**
1848  * @brief Retrieves provisioning status
1849  *
1850  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1851  *
1852  * @return None.
1853  */
1854 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1855 {
1856     BMCWEB_LOG_DEBUG << "Get OEM information.";
1857     sdbusplus::asio::getAllProperties(
1858         *crow::connections::systemBus, "xyz.openbmc_project.PFR.Manager",
1859         "/xyz/openbmc_project/pfr", "xyz.openbmc_project.PFR.Attributes",
1860         [aResp](const boost::system::error_code& ec,
1861                 const dbus::utility::DBusPropertiesMap& propertiesList) {
1862         nlohmann::json& oemPFR =
1863             aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1864         aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1865             "#OemComputerSystem.OpenBmc";
1866         oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1867 
1868         if (ec)
1869         {
1870             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1871             // not an error, don't have to have the interface
1872             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1873             return;
1874         }
1875 
1876         const bool* provState = nullptr;
1877         const bool* lockState = nullptr;
1878 
1879         const bool success = sdbusplus::unpackPropertiesNoThrow(
1880             dbus_utils::UnpackErrorPrinter(), propertiesList, "UfmProvisioned",
1881             provState, "UfmLocked", lockState);
1882 
1883         if (!success)
1884         {
1885             messages::internalError(aResp->res);
1886             return;
1887         }
1888 
1889         if ((provState == nullptr) || (lockState == nullptr))
1890         {
1891             BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1892             messages::internalError(aResp->res);
1893             return;
1894         }
1895 
1896         if (*provState == true)
1897         {
1898             if (*lockState == true)
1899             {
1900                 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1901             }
1902             else
1903             {
1904                 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1905             }
1906         }
1907         else
1908         {
1909             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1910         }
1911         });
1912 }
1913 #endif
1914 
1915 /**
1916  * @brief Translate the PowerMode to a response message.
1917  *
1918  * @param[in] aResp  Shared pointer for generating response message.
1919  * @param[in] modeValue  PowerMode value to be translated
1920  *
1921  * @return None.
1922  */
1923 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1924                                const std::string& modeValue)
1925 {
1926     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
1927     {
1928         aResp->res.jsonValue["PowerMode"] = "Static";
1929     }
1930     else if (
1931         modeValue ==
1932         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
1933     {
1934         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
1935     }
1936     else if (modeValue ==
1937              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
1938     {
1939         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
1940     }
1941     else if (modeValue ==
1942              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
1943     {
1944         aResp->res.jsonValue["PowerMode"] = "OEM";
1945     }
1946     else
1947     {
1948         // Any other values would be invalid
1949         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
1950         messages::internalError(aResp->res);
1951     }
1952 }
1953 
1954 /**
1955  * @brief Retrieves system power mode
1956  *
1957  * @param[in] aResp  Shared pointer for generating response message.
1958  *
1959  * @return None.
1960  */
1961 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1962 {
1963     BMCWEB_LOG_DEBUG << "Get power mode.";
1964 
1965     // Get Power Mode object path:
1966     constexpr std::array<std::string_view, 1> interfaces = {
1967         "xyz.openbmc_project.Control.Power.Mode"};
1968     dbus::utility::getSubTree(
1969         "/", 0, interfaces,
1970         [aResp](const boost::system::error_code& ec,
1971                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1972         if (ec)
1973         {
1974             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
1975                              << ec;
1976             // This is an optional D-Bus object so just return if
1977             // error occurs
1978             return;
1979         }
1980         if (subtree.empty())
1981         {
1982             // As noted above, this is an optional interface so just return
1983             // if there is no instance found
1984             return;
1985         }
1986         if (subtree.size() > 1)
1987         {
1988             // More then one PowerMode object is not supported and is an
1989             // error
1990             BMCWEB_LOG_DEBUG
1991                 << "Found more than 1 system D-Bus Power.Mode objects: "
1992                 << subtree.size();
1993             messages::internalError(aResp->res);
1994             return;
1995         }
1996         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
1997         {
1998             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
1999             messages::internalError(aResp->res);
2000             return;
2001         }
2002         const std::string& path = subtree[0].first;
2003         const std::string& service = subtree[0].second.begin()->first;
2004         if (service.empty())
2005         {
2006             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2007             messages::internalError(aResp->res);
2008             return;
2009         }
2010         // Valid Power Mode object found, now read the current value
2011         sdbusplus::asio::getProperty<std::string>(
2012             *crow::connections::systemBus, service, path,
2013             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2014             [aResp](const boost::system::error_code& ec2,
2015                     const std::string& pmode) {
2016             if (ec2)
2017             {
2018                 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: "
2019                                  << ec2;
2020                 messages::internalError(aResp->res);
2021                 return;
2022             }
2023 
2024             aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = {
2025                 "Static", "MaximumPerformance", "PowerSaving"};
2026 
2027             BMCWEB_LOG_DEBUG << "Current power mode: " << pmode;
2028             translatePowerMode(aResp, pmode);
2029             });
2030         });
2031 }
2032 
2033 /**
2034  * @brief Validate the specified mode is valid and return the PowerMode
2035  * name associated with that string
2036  *
2037  * @param[in] aResp   Shared pointer for generating response message.
2038  * @param[in] modeString  String representing the desired PowerMode
2039  *
2040  * @return PowerMode value or empty string if mode is not valid
2041  */
2042 inline std::string
2043     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2044                       const std::string& modeString)
2045 {
2046     std::string mode;
2047 
2048     if (modeString == "Static")
2049     {
2050         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2051     }
2052     else if (modeString == "MaximumPerformance")
2053     {
2054         mode =
2055             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2056     }
2057     else if (modeString == "PowerSaving")
2058     {
2059         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2060     }
2061     else
2062     {
2063         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2064     }
2065     return mode;
2066 }
2067 
2068 /**
2069  * @brief Sets system power mode.
2070  *
2071  * @param[in] aResp   Shared pointer for generating response message.
2072  * @param[in] pmode   System power mode from request.
2073  *
2074  * @return None.
2075  */
2076 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2077                          const std::string& pmode)
2078 {
2079     BMCWEB_LOG_DEBUG << "Set power mode.";
2080 
2081     std::string powerMode = validatePowerMode(aResp, pmode);
2082     if (powerMode.empty())
2083     {
2084         return;
2085     }
2086 
2087     // Get Power Mode object path:
2088     constexpr std::array<std::string_view, 1> interfaces = {
2089         "xyz.openbmc_project.Control.Power.Mode"};
2090     dbus::utility::getSubTree(
2091         "/", 0, interfaces,
2092         [aResp,
2093          powerMode](const boost::system::error_code& ec,
2094                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2095         if (ec)
2096         {
2097             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
2098                              << ec;
2099             // This is an optional D-Bus object, but user attempted to patch
2100             messages::internalError(aResp->res);
2101             return;
2102         }
2103         if (subtree.empty())
2104         {
2105             // This is an optional D-Bus object, but user attempted to patch
2106             messages::resourceNotFound(aResp->res, "ComputerSystem",
2107                                        "PowerMode");
2108             return;
2109         }
2110         if (subtree.size() > 1)
2111         {
2112             // More then one PowerMode object is not supported and is an
2113             // error
2114             BMCWEB_LOG_DEBUG
2115                 << "Found more than 1 system D-Bus Power.Mode objects: "
2116                 << subtree.size();
2117             messages::internalError(aResp->res);
2118             return;
2119         }
2120         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2121         {
2122             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2123             messages::internalError(aResp->res);
2124             return;
2125         }
2126         const std::string& path = subtree[0].first;
2127         const std::string& service = subtree[0].second.begin()->first;
2128         if (service.empty())
2129         {
2130             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2131             messages::internalError(aResp->res);
2132             return;
2133         }
2134 
2135         BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2136                          << path;
2137 
2138         // Set the Power Mode property
2139         crow::connections::systemBus->async_method_call(
2140             [aResp](const boost::system::error_code& ec2) {
2141             if (ec2)
2142             {
2143                 messages::internalError(aResp->res);
2144                 return;
2145             }
2146             },
2147             service, path, "org.freedesktop.DBus.Properties", "Set",
2148             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2149             dbus::utility::DbusVariantType(powerMode));
2150         });
2151 }
2152 
2153 /**
2154  * @brief Translates watchdog timeout action DBUS property value to redfish.
2155  *
2156  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2157  *
2158  * @return Returns as a string, the timeout action in Redfish terms. If
2159  * translation cannot be done, returns an empty string.
2160  */
2161 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2162 {
2163     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2164     {
2165         return "None";
2166     }
2167     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2168     {
2169         return "ResetSystem";
2170     }
2171     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2172     {
2173         return "PowerDown";
2174     }
2175     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2176     {
2177         return "PowerCycle";
2178     }
2179 
2180     return "";
2181 }
2182 
2183 /**
2184  *@brief Translates timeout action from Redfish to DBUS property value.
2185  *
2186  *@param[in] rfAction The timeout action in Redfish.
2187  *
2188  *@return Returns as a string, the time_out action as expected by DBUS.
2189  *If translation cannot be done, returns an empty string.
2190  */
2191 
2192 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2193 {
2194     if (rfAction == "None")
2195     {
2196         return "xyz.openbmc_project.State.Watchdog.Action.None";
2197     }
2198     if (rfAction == "PowerCycle")
2199     {
2200         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2201     }
2202     if (rfAction == "PowerDown")
2203     {
2204         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2205     }
2206     if (rfAction == "ResetSystem")
2207     {
2208         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2209     }
2210 
2211     return "";
2212 }
2213 
2214 /**
2215  * @brief Retrieves host watchdog timer properties over DBUS
2216  *
2217  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2218  *
2219  * @return None.
2220  */
2221 inline void
2222     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2223 {
2224     BMCWEB_LOG_DEBUG << "Get host watchodg";
2225     sdbusplus::asio::getAllProperties(
2226         *crow::connections::systemBus, "xyz.openbmc_project.Watchdog",
2227         "/xyz/openbmc_project/watchdog/host0",
2228         "xyz.openbmc_project.State.Watchdog",
2229         [aResp](const boost::system::error_code& ec,
2230                 const dbus::utility::DBusPropertiesMap& properties) {
2231         if (ec)
2232         {
2233             // watchdog service is stopped
2234             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2235             return;
2236         }
2237 
2238         BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2239 
2240         nlohmann::json& hostWatchdogTimer =
2241             aResp->res.jsonValue["HostWatchdogTimer"];
2242 
2243         // watchdog service is running/enabled
2244         hostWatchdogTimer["Status"]["State"] = "Enabled";
2245 
2246         const bool* enabled = nullptr;
2247         const std::string* expireAction = nullptr;
2248 
2249         const bool success = sdbusplus::unpackPropertiesNoThrow(
2250             dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2251             "ExpireAction", expireAction);
2252 
2253         if (!success)
2254         {
2255             messages::internalError(aResp->res);
2256             return;
2257         }
2258 
2259         if (enabled != nullptr)
2260         {
2261             hostWatchdogTimer["FunctionEnabled"] = *enabled;
2262         }
2263 
2264         if (expireAction != nullptr)
2265         {
2266             std::string action = dbusToRfWatchdogAction(*expireAction);
2267             if (action.empty())
2268             {
2269                 messages::internalError(aResp->res);
2270                 return;
2271             }
2272             hostWatchdogTimer["TimeoutAction"] = action;
2273         }
2274         });
2275 }
2276 
2277 /**
2278  * @brief Sets Host WatchDog Timer properties.
2279  *
2280  * @param[in] aResp      Shared pointer for generating response message.
2281  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2282  *                       RF request.
2283  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2284  *
2285  * @return None.
2286  */
2287 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2288                              const std::optional<bool> wdtEnable,
2289                              const std::optional<std::string>& wdtTimeOutAction)
2290 {
2291     BMCWEB_LOG_DEBUG << "Set host watchdog";
2292 
2293     if (wdtTimeOutAction)
2294     {
2295         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2296         // check if TimeOut Action is Valid
2297         if (wdtTimeOutActStr.empty())
2298         {
2299             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2300                              << *wdtTimeOutAction;
2301             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2302                                              "TimeoutAction");
2303             return;
2304         }
2305 
2306         crow::connections::systemBus->async_method_call(
2307             [aResp](const boost::system::error_code& ec) {
2308             if (ec)
2309             {
2310                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2311                 messages::internalError(aResp->res);
2312                 return;
2313             }
2314             },
2315             "xyz.openbmc_project.Watchdog",
2316             "/xyz/openbmc_project/watchdog/host0",
2317             "org.freedesktop.DBus.Properties", "Set",
2318             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2319             dbus::utility::DbusVariantType(wdtTimeOutActStr));
2320     }
2321 
2322     if (wdtEnable)
2323     {
2324         crow::connections::systemBus->async_method_call(
2325             [aResp](const boost::system::error_code& ec) {
2326             if (ec)
2327             {
2328                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2329                 messages::internalError(aResp->res);
2330                 return;
2331             }
2332             },
2333             "xyz.openbmc_project.Watchdog",
2334             "/xyz/openbmc_project/watchdog/host0",
2335             "org.freedesktop.DBus.Properties", "Set",
2336             "xyz.openbmc_project.State.Watchdog", "Enabled",
2337             dbus::utility::DbusVariantType(*wdtEnable));
2338     }
2339 }
2340 
2341 /**
2342  * @brief Parse the Idle Power Saver properties into json
2343  *
2344  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2345  * @param[in] properties  IPS property data from DBus.
2346  *
2347  * @return true if successful
2348  */
2349 inline bool
2350     parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2351                        const dbus::utility::DBusPropertiesMap& properties)
2352 {
2353     const bool* enabled = nullptr;
2354     const uint8_t* enterUtilizationPercent = nullptr;
2355     const uint64_t* enterDwellTime = nullptr;
2356     const uint8_t* exitUtilizationPercent = nullptr;
2357     const uint64_t* exitDwellTime = nullptr;
2358 
2359     const bool success = sdbusplus::unpackPropertiesNoThrow(
2360         dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2361         "EnterUtilizationPercent", enterUtilizationPercent,
2362         "ExitUtilizationPercent", exitUtilizationPercent, "ExitDwellTime",
2363         exitDwellTime);
2364 
2365     if (!success)
2366     {
2367         return false;
2368     }
2369 
2370     if (enabled != nullptr)
2371     {
2372         aResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled;
2373     }
2374 
2375     if (enterUtilizationPercent != nullptr)
2376     {
2377         aResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] =
2378             *enterUtilizationPercent;
2379     }
2380 
2381     if (enterDwellTime != nullptr)
2382     {
2383         const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime);
2384         aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2385             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2386                 .count();
2387     }
2388 
2389     if (exitUtilizationPercent != nullptr)
2390     {
2391         aResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] =
2392             *exitUtilizationPercent;
2393     }
2394 
2395     if (exitDwellTime != nullptr)
2396     {
2397         const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime);
2398         aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2399             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2400                 .count();
2401     }
2402 
2403     return true;
2404 }
2405 
2406 /**
2407  * @brief Retrieves host watchdog timer properties over DBUS
2408  *
2409  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2410  *
2411  * @return None.
2412  */
2413 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2414 {
2415     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2416 
2417     // Get IdlePowerSaver object path:
2418     constexpr std::array<std::string_view, 1> interfaces = {
2419         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2420     dbus::utility::getSubTree(
2421         "/", 0, interfaces,
2422         [aResp](const boost::system::error_code& ec,
2423                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2424         if (ec)
2425         {
2426             BMCWEB_LOG_DEBUG
2427                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2428                 << ec;
2429             messages::internalError(aResp->res);
2430             return;
2431         }
2432         if (subtree.empty())
2433         {
2434             // This is an optional interface so just return
2435             // if there is no instance found
2436             BMCWEB_LOG_DEBUG << "No instances found";
2437             return;
2438         }
2439         if (subtree.size() > 1)
2440         {
2441             // More then one PowerIdlePowerSaver object is not supported and
2442             // is an error
2443             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2444                                 "Power.IdlePowerSaver objects: "
2445                              << subtree.size();
2446             messages::internalError(aResp->res);
2447             return;
2448         }
2449         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2450         {
2451             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2452             messages::internalError(aResp->res);
2453             return;
2454         }
2455         const std::string& path = subtree[0].first;
2456         const std::string& service = subtree[0].second.begin()->first;
2457         if (service.empty())
2458         {
2459             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2460             messages::internalError(aResp->res);
2461             return;
2462         }
2463 
2464         // Valid IdlePowerSaver object found, now read the current values
2465         sdbusplus::asio::getAllProperties(
2466             *crow::connections::systemBus, service, path,
2467             "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2468             [aResp](const boost::system::error_code& ec2,
2469                     const dbus::utility::DBusPropertiesMap& properties) {
2470             if (ec2)
2471             {
2472                 BMCWEB_LOG_ERROR
2473                     << "DBUS response error on IdlePowerSaver GetAll: " << ec2;
2474                 messages::internalError(aResp->res);
2475                 return;
2476             }
2477 
2478             if (!parseIpsProperties(aResp, properties))
2479             {
2480                 messages::internalError(aResp->res);
2481                 return;
2482             }
2483             });
2484         });
2485 
2486     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2487 }
2488 
2489 /**
2490  * @brief Sets Idle Power Saver properties.
2491  *
2492  * @param[in] aResp      Shared pointer for generating response message.
2493  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2494  *                       RF request.
2495  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2496  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2497  * before entering idle state.
2498  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2499  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2500  * before exiting idle state
2501  *
2502  * @return None.
2503  */
2504 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2505                               const std::optional<bool> ipsEnable,
2506                               const std::optional<uint8_t> ipsEnterUtil,
2507                               const std::optional<uint64_t> ipsEnterTime,
2508                               const std::optional<uint8_t> ipsExitUtil,
2509                               const std::optional<uint64_t> ipsExitTime)
2510 {
2511     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2512 
2513     // Get IdlePowerSaver object path:
2514     constexpr std::array<std::string_view, 1> interfaces = {
2515         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2516     dbus::utility::getSubTree(
2517         "/", 0, interfaces,
2518         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2519          ipsExitTime](const boost::system::error_code& ec,
2520                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
2521         if (ec)
2522         {
2523             BMCWEB_LOG_DEBUG
2524                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2525                 << ec;
2526             messages::internalError(aResp->res);
2527             return;
2528         }
2529         if (subtree.empty())
2530         {
2531             // This is an optional D-Bus object, but user attempted to patch
2532             messages::resourceNotFound(aResp->res, "ComputerSystem",
2533                                        "IdlePowerSaver");
2534             return;
2535         }
2536         if (subtree.size() > 1)
2537         {
2538             // More then one PowerIdlePowerSaver object is not supported and
2539             // is an error
2540             BMCWEB_LOG_DEBUG
2541                 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2542                 << subtree.size();
2543             messages::internalError(aResp->res);
2544             return;
2545         }
2546         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2547         {
2548             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2549             messages::internalError(aResp->res);
2550             return;
2551         }
2552         const std::string& path = subtree[0].first;
2553         const std::string& service = subtree[0].second.begin()->first;
2554         if (service.empty())
2555         {
2556             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2557             messages::internalError(aResp->res);
2558             return;
2559         }
2560 
2561         // Valid Power IdlePowerSaver object found, now set any values that
2562         // need to be updated
2563 
2564         if (ipsEnable)
2565         {
2566             crow::connections::systemBus->async_method_call(
2567                 [aResp](const boost::system::error_code& ec2) {
2568                 if (ec2)
2569                 {
2570                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2571                     messages::internalError(aResp->res);
2572                     return;
2573                 }
2574                 },
2575                 service, path, "org.freedesktop.DBus.Properties", "Set",
2576                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled",
2577                 dbus::utility::DbusVariantType(*ipsEnable));
2578         }
2579         if (ipsEnterUtil)
2580         {
2581             crow::connections::systemBus->async_method_call(
2582                 [aResp](const boost::system::error_code& ec2) {
2583                 if (ec2)
2584                 {
2585                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2586                     messages::internalError(aResp->res);
2587                     return;
2588                 }
2589                 },
2590                 service, path, "org.freedesktop.DBus.Properties", "Set",
2591                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2592                 "EnterUtilizationPercent",
2593                 dbus::utility::DbusVariantType(*ipsEnterUtil));
2594         }
2595         if (ipsEnterTime)
2596         {
2597             // Convert from seconds into milliseconds for DBus
2598             const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2599             crow::connections::systemBus->async_method_call(
2600                 [aResp](const boost::system::error_code& ec2) {
2601                 if (ec2)
2602                 {
2603                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2604                     messages::internalError(aResp->res);
2605                     return;
2606                 }
2607                 },
2608                 service, path, "org.freedesktop.DBus.Properties", "Set",
2609                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2610                 "EnterDwellTime",
2611                 dbus::utility::DbusVariantType(timeMilliseconds));
2612         }
2613         if (ipsExitUtil)
2614         {
2615             crow::connections::systemBus->async_method_call(
2616                 [aResp](const boost::system::error_code& ec2) {
2617                 if (ec2)
2618                 {
2619                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2620                     messages::internalError(aResp->res);
2621                     return;
2622                 }
2623                 },
2624                 service, path, "org.freedesktop.DBus.Properties", "Set",
2625                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2626                 "ExitUtilizationPercent",
2627                 dbus::utility::DbusVariantType(*ipsExitUtil));
2628         }
2629         if (ipsExitTime)
2630         {
2631             // Convert from seconds into milliseconds for DBus
2632             const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2633             crow::connections::systemBus->async_method_call(
2634                 [aResp](const boost::system::error_code& ec2) {
2635                 if (ec2)
2636                 {
2637                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2638                     messages::internalError(aResp->res);
2639                     return;
2640                 }
2641                 },
2642                 service, path, "org.freedesktop.DBus.Properties", "Set",
2643                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2644                 "ExitDwellTime",
2645                 dbus::utility::DbusVariantType(timeMilliseconds));
2646         }
2647         });
2648 
2649     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2650 }
2651 
2652 inline void handleComputerSystemHead(
2653     crow::App& app, const crow::Request& req,
2654     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2655 {
2656     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2657     {
2658         return;
2659     }
2660     asyncResp->res.addHeader(
2661         boost::beast::http::field::link,
2662         "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby");
2663 }
2664 
2665 /**
2666  * SystemsCollection derived class for delivering ComputerSystems Collection
2667  * Schema
2668  */
2669 inline void requestRoutesSystemsCollection(App& app)
2670 {
2671     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2672         .privileges(redfish::privileges::headComputerSystemCollection)
2673         .methods(boost::beast::http::verb::head)(
2674             std::bind_front(handleComputerSystemHead, std::ref(app)));
2675 
2676     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2677         .privileges(redfish::privileges::getComputerSystemCollection)
2678         .methods(boost::beast::http::verb::get)(
2679             [&app](const crow::Request& req,
2680                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2681         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2682         {
2683             return;
2684         }
2685 
2686         asyncResp->res.addHeader(
2687             boost::beast::http::field::link,
2688             "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby");
2689         asyncResp->res.jsonValue["@odata.type"] =
2690             "#ComputerSystemCollection.ComputerSystemCollection";
2691         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2692         asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2693 
2694         sdbusplus::asio::getProperty<std::string>(
2695             *crow::connections::systemBus, "xyz.openbmc_project.Settings",
2696             "/xyz/openbmc_project/network/hypervisor",
2697             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
2698             [asyncResp](const boost::system::error_code& ec2,
2699                         const std::string& /*hostName*/) {
2700             nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
2701             ifaceArray = nlohmann::json::array();
2702             auto& count = asyncResp->res.jsonValue["Members@odata.count"];
2703 
2704             nlohmann::json::object_t system;
2705             system["@odata.id"] = "/redfish/v1/Systems/system";
2706             ifaceArray.push_back(std::move(system));
2707             count = ifaceArray.size();
2708             if (!ec2)
2709             {
2710                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
2711                 nlohmann::json::object_t hypervisor;
2712                 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor";
2713                 ifaceArray.push_back(std::move(hypervisor));
2714                 count = ifaceArray.size();
2715             }
2716             });
2717         });
2718 }
2719 
2720 /**
2721  * Function transceives data with dbus directly.
2722  */
2723 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2724 {
2725     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2726     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2727     constexpr char const* interfaceName =
2728         "xyz.openbmc_project.Control.Host.NMI";
2729     constexpr char const* method = "NMI";
2730 
2731     crow::connections::systemBus->async_method_call(
2732         [asyncResp](const boost::system::error_code& ec) {
2733         if (ec)
2734         {
2735             BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2736             messages::internalError(asyncResp->res);
2737             return;
2738         }
2739         messages::success(asyncResp->res);
2740         },
2741         serviceName, objectPath, interfaceName, method);
2742 }
2743 
2744 /**
2745  * SystemActionsReset class supports handle POST method for Reset action.
2746  * The class retrieves and sends data directly to D-Bus.
2747  */
2748 inline void requestRoutesSystemActionsReset(App& app)
2749 {
2750     /**
2751      * Function handles POST method request.
2752      * Analyzes POST body message before sends Reset request data to D-Bus.
2753      */
2754     BMCWEB_ROUTE(app,
2755                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2756         .privileges(redfish::privileges::postComputerSystem)
2757         .methods(boost::beast::http::verb::post)(
2758             [&app](const crow::Request& req,
2759                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2760         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2761         {
2762             return;
2763         }
2764         std::string resetType;
2765         if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
2766                                        resetType))
2767         {
2768             return;
2769         }
2770 
2771         // Get the command and host vs. chassis
2772         std::string command;
2773         bool hostCommand = true;
2774         if ((resetType == "On") || (resetType == "ForceOn"))
2775         {
2776             command = "xyz.openbmc_project.State.Host.Transition.On";
2777             hostCommand = true;
2778         }
2779         else if (resetType == "ForceOff")
2780         {
2781             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2782             hostCommand = false;
2783         }
2784         else if (resetType == "ForceRestart")
2785         {
2786             command =
2787                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2788             hostCommand = true;
2789         }
2790         else if (resetType == "GracefulShutdown")
2791         {
2792             command = "xyz.openbmc_project.State.Host.Transition.Off";
2793             hostCommand = true;
2794         }
2795         else if (resetType == "GracefulRestart")
2796         {
2797             command =
2798                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2799             hostCommand = true;
2800         }
2801         else if (resetType == "PowerCycle")
2802         {
2803             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2804             hostCommand = true;
2805         }
2806         else if (resetType == "Nmi")
2807         {
2808             doNMI(asyncResp);
2809             return;
2810         }
2811         else
2812         {
2813             messages::actionParameterUnknown(asyncResp->res, "Reset",
2814                                              resetType);
2815             return;
2816         }
2817 
2818         if (hostCommand)
2819         {
2820             crow::connections::systemBus->async_method_call(
2821                 [asyncResp, resetType](const boost::system::error_code& ec) {
2822                 if (ec)
2823                 {
2824                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2825                     if (ec.value() == boost::asio::error::invalid_argument)
2826                     {
2827                         messages::actionParameterNotSupported(
2828                             asyncResp->res, resetType, "Reset");
2829                     }
2830                     else
2831                     {
2832                         messages::internalError(asyncResp->res);
2833                     }
2834                     return;
2835                 }
2836                 messages::success(asyncResp->res);
2837                 },
2838                 "xyz.openbmc_project.State.Host",
2839                 "/xyz/openbmc_project/state/host0",
2840                 "org.freedesktop.DBus.Properties", "Set",
2841                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2842                 dbus::utility::DbusVariantType{command});
2843         }
2844         else
2845         {
2846             crow::connections::systemBus->async_method_call(
2847                 [asyncResp, resetType](const boost::system::error_code& ec) {
2848                 if (ec)
2849                 {
2850                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2851                     if (ec.value() == boost::asio::error::invalid_argument)
2852                     {
2853                         messages::actionParameterNotSupported(
2854                             asyncResp->res, resetType, "Reset");
2855                     }
2856                     else
2857                     {
2858                         messages::internalError(asyncResp->res);
2859                     }
2860                     return;
2861                 }
2862                 messages::success(asyncResp->res);
2863                 },
2864                 "xyz.openbmc_project.State.Chassis",
2865                 "/xyz/openbmc_project/state/chassis0",
2866                 "org.freedesktop.DBus.Properties", "Set",
2867                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2868                 dbus::utility::DbusVariantType{command});
2869         }
2870         });
2871 }
2872 
2873 inline void handleComputerSystemCollectionHead(
2874     App& app, const crow::Request& req,
2875     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2876 {
2877     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2878     {
2879         return;
2880     }
2881 
2882     asyncResp->res.addHeader(
2883         boost::beast::http::field::link,
2884         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
2885 }
2886 
2887 inline void afterPortRequest(
2888     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2889     const boost::system::error_code& ec,
2890     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
2891 {
2892     if (ec)
2893     {
2894         messages::internalError(asyncResp->res);
2895         return;
2896     }
2897     for (const auto& data : socketData)
2898     {
2899         const std::string& socketPath = get<0>(data);
2900         const std::string& protocolName = get<1>(data);
2901         bool isProtocolEnabled = get<2>(data);
2902         nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"];
2903         dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled;
2904         // need to retrieve port number for
2905         // obmc-console-ssh service
2906         if (protocolName == "SSH")
2907         {
2908             getPortNumber(socketPath, [asyncResp, protocolName](
2909                                           const boost::system::error_code ec1,
2910                                           int portNumber) {
2911                 if (ec1)
2912                 {
2913                     messages::internalError(asyncResp->res);
2914                     return;
2915                 }
2916                 nlohmann::json& dataJson1 =
2917                     asyncResp->res.jsonValue["SerialConsole"];
2918                 dataJson1[protocolName]["Port"] = portNumber;
2919             });
2920         }
2921     }
2922 }
2923 /**
2924  * Systems derived class for delivering Computer Systems Schema.
2925  */
2926 inline void requestRoutesSystems(App& app)
2927 {
2928 
2929     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2930         .privileges(redfish::privileges::headComputerSystem)
2931         .methods(boost::beast::http::verb::head)(
2932             std::bind_front(handleComputerSystemCollectionHead, std::ref(app)));
2933     /**
2934      * Functions triggers appropriate requests on DBus
2935      */
2936     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
2937         .privileges(redfish::privileges::getComputerSystem)
2938         .methods(boost::beast::http::verb::get)(
2939             [&app](const crow::Request& req,
2940                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2941                    const std::string& systemName) {
2942         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2943         {
2944             return;
2945         }
2946 
2947         if (systemName == "hypervisor")
2948         {
2949             handleHypervisorSystemGet(asyncResp);
2950             return;
2951         }
2952 
2953         if (systemName != "system")
2954         {
2955             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2956                                        systemName);
2957             return;
2958         }
2959         asyncResp->res.addHeader(
2960             boost::beast::http::field::link,
2961             "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
2962         asyncResp->res.jsonValue["@odata.type"] =
2963             "#ComputerSystem.v1_16_0.ComputerSystem";
2964         asyncResp->res.jsonValue["Name"] = "system";
2965         asyncResp->res.jsonValue["Id"] = "system";
2966         asyncResp->res.jsonValue["SystemType"] = "Physical";
2967         asyncResp->res.jsonValue["Description"] = "Computer System";
2968         asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2969         asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2970             "Disabled";
2971         asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2972             uint64_t(0);
2973         asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2974             "Disabled";
2975         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2976 
2977         asyncResp->res.jsonValue["Processors"]["@odata.id"] =
2978             "/redfish/v1/Systems/system/Processors";
2979         asyncResp->res.jsonValue["Memory"]["@odata.id"] =
2980             "/redfish/v1/Systems/system/Memory";
2981         asyncResp->res.jsonValue["Storage"]["@odata.id"] =
2982             "/redfish/v1/Systems/system/Storage";
2983         asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] =
2984             "/redfish/v1/Systems/system/FabricAdapters";
2985 
2986         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
2987             "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset";
2988         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]
2989                                 ["@Redfish.ActionInfo"] =
2990             "/redfish/v1/Systems/system/ResetActionInfo";
2991 
2992         asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
2993             "/redfish/v1/Systems/system/LogServices";
2994         asyncResp->res.jsonValue["Bios"]["@odata.id"] =
2995             "/redfish/v1/Systems/system/Bios";
2996 
2997         nlohmann::json::array_t managedBy;
2998         nlohmann::json& manager = managedBy.emplace_back();
2999         manager["@odata.id"] = "/redfish/v1/Managers/bmc";
3000         asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
3001         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
3002         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
3003 
3004         // Fill in SerialConsole info
3005         asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
3006         asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] =
3007             true;
3008 
3009         // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
3010         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] =
3011             true;
3012         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
3013         asyncResp->res
3014             .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
3015             "Press ~. to exit console";
3016         getPortStatusAndPath(std::span{protocolToDBusForSystems},
3017                              std::bind_front(afterPortRequest, asyncResp));
3018 
3019 #ifdef BMCWEB_ENABLE_KVM
3020         // Fill in GraphicalConsole info
3021         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
3022         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
3023             4;
3024         asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
3025             nlohmann::json::array_t({"KVMIP"});
3026 
3027 #endif // BMCWEB_ENABLE_KVM
3028         constexpr std::array<std::string_view, 4> inventoryForSystems{
3029             "xyz.openbmc_project.Inventory.Item.Dimm",
3030             "xyz.openbmc_project.Inventory.Item.Cpu",
3031             "xyz.openbmc_project.Inventory.Item.Drive",
3032             "xyz.openbmc_project.Inventory.Item.StorageController"};
3033 
3034         auto health = std::make_shared<HealthPopulate>(asyncResp);
3035         dbus::utility::getSubTreePaths(
3036             "/", 0, inventoryForSystems,
3037             [health](const boost::system::error_code& ec,
3038                      const std::vector<std::string>& resp) {
3039             if (ec)
3040             {
3041                 // no inventory
3042                 return;
3043             }
3044 
3045             health->inventory = resp;
3046             });
3047 
3048         health->populate();
3049 
3050         getMainChassisId(asyncResp,
3051                          [](const std::string& chassisId,
3052                             const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3053             nlohmann::json::array_t chassisArray;
3054             nlohmann::json& chassis = chassisArray.emplace_back();
3055             chassis["@odata.id"] = crow::utility::urlFromPieces(
3056                 "redfish", "v1", "Chassis", chassisId);
3057             aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
3058         });
3059 
3060         getLocationIndicatorActive(asyncResp);
3061         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3062         getIndicatorLedState(asyncResp);
3063         getComputerSystem(asyncResp, health);
3064         getHostState(asyncResp);
3065         getBootProperties(asyncResp);
3066         getBootProgress(asyncResp);
3067         getBootProgressLastStateTime(asyncResp);
3068         getPCIeDeviceList(asyncResp, "PCIeDevices");
3069         getHostWatchdogTimer(asyncResp);
3070         getPowerRestorePolicy(asyncResp);
3071         getAutomaticRetry(asyncResp);
3072         getLastResetTime(asyncResp);
3073 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
3074         getProvisioningStatus(asyncResp);
3075 #endif
3076         getTrustedModuleRequiredToBoot(asyncResp);
3077         getPowerMode(asyncResp);
3078         getIdlePowerSaver(asyncResp);
3079         });
3080 
3081     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3082         .privileges(redfish::privileges::patchComputerSystem)
3083         .methods(boost::beast::http::verb::patch)(
3084             [&app](const crow::Request& req,
3085                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3086                    const std::string& systemName) {
3087         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3088         {
3089             return;
3090         }
3091         if (systemName != "system")
3092         {
3093             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3094                                        systemName);
3095             return;
3096         }
3097 
3098         asyncResp->res.addHeader(
3099             boost::beast::http::field::link,
3100             "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3101 
3102         std::optional<bool> locationIndicatorActive;
3103         std::optional<std::string> indicatorLed;
3104         std::optional<std::string> assetTag;
3105         std::optional<std::string> powerRestorePolicy;
3106         std::optional<std::string> powerMode;
3107         std::optional<bool> wdtEnable;
3108         std::optional<std::string> wdtTimeOutAction;
3109         std::optional<std::string> bootSource;
3110         std::optional<std::string> bootType;
3111         std::optional<std::string> bootEnable;
3112         std::optional<std::string> bootAutomaticRetry;
3113         std::optional<bool> bootTrustedModuleRequired;
3114         std::optional<bool> ipsEnable;
3115         std::optional<uint8_t> ipsEnterUtil;
3116         std::optional<uint64_t> ipsEnterTime;
3117         std::optional<uint8_t> ipsExitUtil;
3118         std::optional<uint64_t> ipsExitTime;
3119 
3120         // clang-format off
3121                 if (!json_util::readJsonPatch(
3122                         req, asyncResp->res,
3123                         "IndicatorLED", indicatorLed,
3124                         "LocationIndicatorActive", locationIndicatorActive,
3125                         "AssetTag", assetTag,
3126                         "PowerRestorePolicy", powerRestorePolicy,
3127                         "PowerMode", powerMode,
3128                         "HostWatchdogTimer/FunctionEnabled", wdtEnable,
3129                         "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
3130                         "Boot/BootSourceOverrideTarget", bootSource,
3131                         "Boot/BootSourceOverrideMode", bootType,
3132                         "Boot/BootSourceOverrideEnabled", bootEnable,
3133                         "Boot/AutomaticRetryConfig", bootAutomaticRetry,
3134                         "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
3135                         "IdlePowerSaver/Enabled", ipsEnable,
3136                         "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
3137                         "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3138                         "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3139                         "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3140                 {
3141                     return;
3142                 }
3143         // clang-format on
3144 
3145         asyncResp->res.result(boost::beast::http::status::no_content);
3146 
3147         if (assetTag)
3148         {
3149             setAssetTag(asyncResp, *assetTag);
3150         }
3151 
3152         if (wdtEnable || wdtTimeOutAction)
3153         {
3154             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3155         }
3156 
3157         if (bootSource || bootType || bootEnable)
3158         {
3159             setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3160         }
3161         if (bootAutomaticRetry)
3162         {
3163             setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3164         }
3165 
3166         if (bootTrustedModuleRequired)
3167         {
3168             setTrustedModuleRequiredToBoot(asyncResp,
3169                                            *bootTrustedModuleRequired);
3170         }
3171 
3172         if (locationIndicatorActive)
3173         {
3174             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3175         }
3176 
3177         // TODO (Gunnar): Remove IndicatorLED after enough time has
3178         // passed
3179         if (indicatorLed)
3180         {
3181             setIndicatorLedState(asyncResp, *indicatorLed);
3182             asyncResp->res.addHeader(boost::beast::http::field::warning,
3183                                      "299 - \"IndicatorLED is deprecated. Use "
3184                                      "LocationIndicatorActive instead.\"");
3185         }
3186 
3187         if (powerRestorePolicy)
3188         {
3189             setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3190         }
3191 
3192         if (powerMode)
3193         {
3194             setPowerMode(asyncResp, *powerMode);
3195         }
3196 
3197         if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil ||
3198             ipsExitTime)
3199         {
3200             setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3201                               ipsExitUtil, ipsExitTime);
3202         }
3203         });
3204 }
3205 
3206 inline void handleSystemCollectionResetActionHead(
3207     crow::App& app, const crow::Request& req,
3208     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3209 {
3210     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3211     {
3212         return;
3213     }
3214     asyncResp->res.addHeader(
3215         boost::beast::http::field::link,
3216         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3217 }
3218 
3219 /**
3220  * SystemResetActionInfo derived class for delivering Computer Systems
3221  * ResetType AllowableValues using ResetInfo schema.
3222  */
3223 inline void requestRoutesSystemResetActionInfo(App& app)
3224 {
3225     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3226         .privileges(redfish::privileges::headActionInfo)
3227         .methods(boost::beast::http::verb::head)(std::bind_front(
3228             handleSystemCollectionResetActionHead, std::ref(app)));
3229     /**
3230      * Functions triggers appropriate requests on DBus
3231      */
3232     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3233         .privileges(redfish::privileges::getActionInfo)
3234         .methods(boost::beast::http::verb::get)(
3235             [&app](const crow::Request& req,
3236                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3237                    const std::string& systemName) {
3238         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3239         {
3240             return;
3241         }
3242 
3243         if (systemName == "hypervisor")
3244         {
3245             handleHypervisorResetActionGet(asyncResp);
3246             return;
3247         }
3248 
3249         if (systemName != "system")
3250         {
3251             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3252                                        systemName);
3253             return;
3254         }
3255 
3256         asyncResp->res.addHeader(
3257             boost::beast::http::field::link,
3258             "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3259 
3260         asyncResp->res.jsonValue["@odata.id"] =
3261             "/redfish/v1/Systems/system/ResetActionInfo";
3262         asyncResp->res.jsonValue["@odata.type"] =
3263             "#ActionInfo.v1_1_2.ActionInfo";
3264         asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3265         asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3266 
3267         nlohmann::json::array_t parameters;
3268         nlohmann::json::object_t parameter;
3269 
3270         parameter["Name"] = "ResetType";
3271         parameter["Required"] = true;
3272         parameter["DataType"] = "String";
3273         nlohmann::json::array_t allowableValues;
3274         allowableValues.emplace_back("On");
3275         allowableValues.emplace_back("ForceOff");
3276         allowableValues.emplace_back("ForceOn");
3277         allowableValues.emplace_back("ForceRestart");
3278         allowableValues.emplace_back("GracefulRestart");
3279         allowableValues.emplace_back("GracefulShutdown");
3280         allowableValues.emplace_back("PowerCycle");
3281         allowableValues.emplace_back("Nmi");
3282         parameter["AllowableValues"] = std::move(allowableValues);
3283         parameters.emplace_back(std::move(parameter));
3284 
3285         asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3286         });
3287 }
3288 } // namespace redfish
3289