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