xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 4f48d5f67f293e50340e7f4bf866435e03a6fc62)
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 "health.hpp"
19 #include "led.hpp"
20 #include "pcie.hpp"
21 #include "redfish_util.hpp"
22 
23 #include <app.hpp>
24 #include <boost/container/flat_map.hpp>
25 #include <registries/privilege_registry.hpp>
26 #include <utils/fw_utils.hpp>
27 #include <utils/json_utils.hpp>
28 
29 #include <variant>
30 
31 namespace redfish
32 {
33 
34 /**
35  * @brief Updates the Functional State of DIMMs
36  *
37  * @param[in] aResp Shared pointer for completing asynchronous calls
38  * @param[in] dimmState Dimm's Functional state, true/false
39  *
40  * @return None.
41  */
42 inline void
43     updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
44                          const std::variant<bool>& dimmState)
45 {
46     const bool* isDimmFunctional = std::get_if<bool>(&dimmState);
47     if (isDimmFunctional == nullptr)
48     {
49         messages::internalError(aResp->res);
50         return;
51     }
52     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
53 
54     // Set it as Enabled if at least one DIMM is functional
55     // Update STATE only if previous State was DISABLED and current Dimm is
56     // ENABLED.
57     nlohmann::json& prevMemSummary =
58         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
59     if (prevMemSummary == "Disabled")
60     {
61         if (*isDimmFunctional == true)
62         {
63             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
64                 "Enabled";
65         }
66     }
67 }
68 
69 /*
70  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
71  *
72  * @param[in] aResp Shared pointer for completing asynchronous calls
73  * @param[in] cpuPresenceState CPU present or not
74  *
75  * @return None.
76  */
77 inline void
78     modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
79                            const std::variant<bool>& cpuPresenceState)
80 {
81     const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState);
82 
83     if (isCpuPresent == nullptr)
84     {
85         messages::internalError(aResp->res);
86         return;
87     }
88     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
89 
90     if (*isCpuPresent == true)
91     {
92         nlohmann::json& procCount =
93             aResp->res.jsonValue["ProcessorSummary"]["Count"];
94         auto procCountPtr =
95             procCount.get_ptr<nlohmann::json::number_integer_t*>();
96         if (procCountPtr != nullptr)
97         {
98             // shouldn't be possible to be nullptr
99             *procCountPtr += 1;
100         }
101     }
102 }
103 
104 /*
105  * @brief Update "ProcessorSummary" "Status" "State" based on
106  *        CPU Functional State
107  *
108  * @param[in] aResp Shared pointer for completing asynchronous calls
109  * @param[in] cpuFunctionalState is CPU functional true/false
110  *
111  * @return None.
112  */
113 inline void
114     modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
115                              const std::variant<bool>& cpuFunctionalState)
116 {
117     const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
118 
119     if (isCpuFunctional == nullptr)
120     {
121         messages::internalError(aResp->res);
122         return;
123     }
124     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
125 
126     nlohmann::json& prevProcState =
127         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
128 
129     // Set it as Enabled if at least one CPU is functional
130     // Update STATE only if previous State was Non_Functional and current CPU is
131     // Functional.
132     if (prevProcState == "Disabled")
133     {
134         if (*isCpuFunctional == true)
135         {
136             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
137                 "Enabled";
138         }
139     }
140 }
141 
142 /*
143  * @brief Retrieves computer system properties over dbus
144  *
145  * @param[in] aResp Shared pointer for completing asynchronous calls
146  * @param[in] systemHealth  Shared HealthPopulate pointer
147  *
148  * @return None.
149  */
150 inline void
151     getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
152                       const std::shared_ptr<HealthPopulate>& systemHealth)
153 {
154     BMCWEB_LOG_DEBUG << "Get available system components.";
155 
156     crow::connections::systemBus->async_method_call(
157         [aResp, systemHealth](
158             const boost::system::error_code ec,
159             const std::vector<std::pair<
160                 std::string,
161                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
162                 subtree) {
163             if (ec)
164             {
165                 BMCWEB_LOG_DEBUG << "DBUS response error";
166                 messages::internalError(aResp->res);
167                 return;
168             }
169             // Iterate over all retrieved ObjectPaths.
170             for (const std::pair<std::string,
171                                  std::vector<std::pair<
172                                      std::string, std::vector<std::string>>>>&
173                      object : subtree)
174             {
175                 const std::string& path = object.first;
176                 BMCWEB_LOG_DEBUG << "Got path: " << path;
177                 const std::vector<
178                     std::pair<std::string, std::vector<std::string>>>&
179                     connectionNames = object.second;
180                 if (connectionNames.size() < 1)
181                 {
182                     continue;
183                 }
184 
185                 auto memoryHealth = std::make_shared<HealthPopulate>(
186                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
187 
188                 auto cpuHealth = std::make_shared<HealthPopulate>(
189                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
190 
191                 systemHealth->children.emplace_back(memoryHealth);
192                 systemHealth->children.emplace_back(cpuHealth);
193 
194                 // This is not system, so check if it's cpu, dimm, UUID or
195                 // BiosVer
196                 for (const auto& connection : connectionNames)
197                 {
198                     for (const auto& interfaceName : connection.second)
199                     {
200                         if (interfaceName ==
201                             "xyz.openbmc_project.Inventory.Item.Dimm")
202                         {
203                             BMCWEB_LOG_DEBUG
204                                 << "Found Dimm, now get its properties.";
205 
206                             crow::connections::systemBus->async_method_call(
207                                 [aResp, service{connection.first},
208                                  path](const boost::system::error_code ec2,
209                                        const std::vector<
210                                            std::pair<std::string, VariantType>>&
211                                            properties) {
212                                     if (ec2)
213                                     {
214                                         BMCWEB_LOG_ERROR
215                                             << "DBUS response error " << ec2;
216                                         messages::internalError(aResp->res);
217                                         return;
218                                     }
219                                     BMCWEB_LOG_DEBUG << "Got "
220                                                      << properties.size()
221                                                      << " Dimm properties.";
222 
223                                     if (properties.size() > 0)
224                                     {
225                                         for (const std::pair<std::string,
226                                                              VariantType>&
227                                                  property : properties)
228                                         {
229                                             if (property.first !=
230                                                 "MemorySizeInKB")
231                                             {
232                                                 continue;
233                                             }
234                                             const uint32_t* value =
235                                                 std::get_if<uint32_t>(
236                                                     &property.second);
237                                             if (value == nullptr)
238                                             {
239                                                 BMCWEB_LOG_DEBUG
240                                                     << "Find incorrect type of "
241                                                        "MemorySize";
242                                                 continue;
243                                             }
244                                             nlohmann::json& totalMemory =
245                                                 aResp->res
246                                                     .jsonValue["MemorySummar"
247                                                                "y"]
248                                                               ["TotalSystemMe"
249                                                                "moryGiB"];
250                                             uint64_t* preValue =
251                                                 totalMemory
252                                                     .get_ptr<uint64_t*>();
253                                             if (preValue == nullptr)
254                                             {
255                                                 continue;
256                                             }
257                                             aResp->res
258                                                 .jsonValue["MemorySummary"]
259                                                           ["TotalSystemMemoryGi"
260                                                            "B"] =
261                                                 *value / (1024 * 1024) +
262                                                 *preValue;
263                                             aResp->res
264                                                 .jsonValue["MemorySummary"]
265                                                           ["Status"]["State"] =
266                                                 "Enabled";
267                                         }
268                                     }
269                                     else
270                                     {
271                                         auto getDimmProperties =
272                                             [aResp](
273                                                 const boost::system::error_code
274                                                     ec3,
275                                                 const std::variant<bool>&
276                                                     dimmState) {
277                                                 if (ec3)
278                                                 {
279                                                     BMCWEB_LOG_ERROR
280                                                         << "DBUS response "
281                                                            "error "
282                                                         << ec3;
283                                                     return;
284                                                 }
285                                                 updateDimmProperties(aResp,
286                                                                      dimmState);
287                                             };
288                                         crow::connections::systemBus
289                                             ->async_method_call(
290                                                 std::move(getDimmProperties),
291                                                 service, path,
292                                                 "org.freedesktop.DBus."
293                                                 "Properties",
294                                                 "Get",
295                                                 "xyz.openbmc_project.State."
296                                                 "Decorator.OperationalStatus",
297                                                 "Functional");
298                                     }
299                                 },
300                                 connection.first, path,
301                                 "org.freedesktop.DBus.Properties", "GetAll",
302                                 "xyz.openbmc_project.Inventory.Item.Dimm");
303 
304                             memoryHealth->inventory.emplace_back(path);
305                         }
306                         else if (interfaceName ==
307                                  "xyz.openbmc_project.Inventory.Item.Cpu")
308                         {
309                             BMCWEB_LOG_DEBUG
310                                 << "Found Cpu, now get its properties.";
311 
312                             crow::connections::systemBus->async_method_call(
313                                 [aResp, service{connection.first},
314                                  path](const boost::system::error_code ec2,
315                                        const std::vector<
316                                            std::pair<std::string, VariantType>>&
317                                            properties) {
318                                     if (ec2)
319                                     {
320                                         BMCWEB_LOG_ERROR
321                                             << "DBUS response error " << ec2;
322                                         messages::internalError(aResp->res);
323                                         return;
324                                     }
325                                     BMCWEB_LOG_DEBUG << "Got "
326                                                      << properties.size()
327                                                      << " Cpu properties.";
328 
329                                     if (properties.size() > 0)
330                                     {
331                                         const uint64_t* processorId = nullptr;
332                                         const std::string* procFamily = nullptr;
333                                         nlohmann::json& procSummary =
334                                             aResp->res.jsonValue["ProcessorSumm"
335                                                                  "ary"];
336                                         nlohmann::json& procCount =
337                                             procSummary["Count"];
338 
339                                         auto procCountPtr = procCount.get_ptr<
340                                             nlohmann::json::
341                                                 number_integer_t*>();
342                                         if (procCountPtr == nullptr)
343                                         {
344                                             messages::internalError(aResp->res);
345                                             return;
346                                         }
347                                         for (const auto& property : properties)
348                                         {
349 
350                                             if (property.first == "Id")
351                                             {
352                                                 processorId =
353                                                     std::get_if<uint64_t>(
354                                                         &property.second);
355                                                 if (nullptr != procFamily)
356                                                 {
357                                                     break;
358                                                 }
359                                                 continue;
360                                             }
361 
362                                             if (property.first == "Family")
363                                             {
364                                                 procFamily =
365                                                     std::get_if<std::string>(
366                                                         &property.second);
367                                                 if (nullptr != processorId)
368                                                 {
369                                                     break;
370                                                 }
371                                                 continue;
372                                             }
373                                         }
374 
375                                         if (procFamily != nullptr &&
376                                             processorId != nullptr)
377                                         {
378                                             if (procCountPtr != nullptr &&
379                                                 *processorId != 0)
380                                             {
381                                                 *procCountPtr += 1;
382                                                 procSummary["Status"]["State"] =
383                                                     "Enabled";
384 
385                                                 procSummary["Model"] =
386                                                     *procFamily;
387                                             }
388                                         }
389                                     }
390                                     else
391                                     {
392                                         auto getCpuPresenceState =
393                                             [aResp](
394                                                 const boost::system::error_code
395                                                     ec3,
396                                                 const std::variant<bool>&
397                                                     cpuPresenceCheck) {
398                                                 if (ec3)
399                                                 {
400                                                     BMCWEB_LOG_ERROR
401                                                         << "DBUS response "
402                                                            "error "
403                                                         << ec3;
404                                                     return;
405                                                 }
406                                                 modifyCpuPresenceState(
407                                                     aResp, cpuPresenceCheck);
408                                             };
409 
410                                         auto getCpuFunctionalState =
411                                             [aResp](
412                                                 const boost::system::error_code
413                                                     ec3,
414                                                 const std::variant<bool>&
415                                                     cpuFunctionalCheck) {
416                                                 if (ec3)
417                                                 {
418                                                     BMCWEB_LOG_ERROR
419                                                         << "DBUS response "
420                                                            "error "
421                                                         << ec3;
422                                                     return;
423                                                 }
424                                                 modifyCpuFunctionalState(
425                                                     aResp, cpuFunctionalCheck);
426                                             };
427                                         // Get the Presence of CPU
428                                         crow::connections::systemBus
429                                             ->async_method_call(
430                                                 std::move(getCpuPresenceState),
431                                                 service, path,
432                                                 "org.freedesktop.DBus."
433                                                 "Properties",
434                                                 "Get",
435                                                 "xyz.openbmc_project.Inventory."
436                                                 "Item",
437                                                 "Present");
438 
439                                         // Get the Functional State
440                                         crow::connections::systemBus
441                                             ->async_method_call(
442                                                 std::move(
443                                                     getCpuFunctionalState),
444                                                 service, path,
445                                                 "org.freedesktop.DBus."
446                                                 "Properties",
447                                                 "Get",
448                                                 "xyz.openbmc_project.State."
449                                                 "Decorator."
450                                                 "OperationalStatus",
451                                                 "Functional");
452 
453                                         // Get the MODEL from
454                                         // xyz.openbmc_project.Inventory.Decorator.Asset
455                                         // support it later as Model  is Empty
456                                         // currently.
457                                     }
458                                 },
459                                 connection.first, path,
460                                 "org.freedesktop.DBus.Properties", "GetAll",
461                                 "xyz.openbmc_project.Inventory.Item.Cpu");
462 
463                             cpuHealth->inventory.emplace_back(path);
464                         }
465                         else if (interfaceName ==
466                                  "xyz.openbmc_project.Common.UUID")
467                         {
468                             BMCWEB_LOG_DEBUG
469                                 << "Found UUID, now get its properties.";
470                             crow::connections::systemBus->async_method_call(
471                                 [aResp](
472                                     const boost::system::error_code ec3,
473                                     const std::vector<
474                                         std::pair<std::string, VariantType>>&
475                                         properties) {
476                                     if (ec3)
477                                     {
478                                         BMCWEB_LOG_DEBUG
479                                             << "DBUS response error " << ec3;
480                                         messages::internalError(aResp->res);
481                                         return;
482                                     }
483                                     BMCWEB_LOG_DEBUG << "Got "
484                                                      << properties.size()
485                                                      << " UUID properties.";
486                                     for (const std::pair<std::string,
487                                                          VariantType>&
488                                              property : properties)
489                                     {
490                                         if (property.first == "UUID")
491                                         {
492                                             const std::string* value =
493                                                 std::get_if<std::string>(
494                                                     &property.second);
495 
496                                             if (value != nullptr)
497                                             {
498                                                 std::string valueStr = *value;
499                                                 if (valueStr.size() == 32)
500                                                 {
501                                                     valueStr.insert(8, 1, '-');
502                                                     valueStr.insert(13, 1, '-');
503                                                     valueStr.insert(18, 1, '-');
504                                                     valueStr.insert(23, 1, '-');
505                                                 }
506                                                 BMCWEB_LOG_DEBUG << "UUID = "
507                                                                  << valueStr;
508                                                 aResp->res.jsonValue["UUID"] =
509                                                     valueStr;
510                                             }
511                                         }
512                                     }
513                                 },
514                                 connection.first, path,
515                                 "org.freedesktop.DBus.Properties", "GetAll",
516                                 "xyz.openbmc_project.Common.UUID");
517                         }
518                         else if (interfaceName ==
519                                  "xyz.openbmc_project.Inventory.Item.System")
520                         {
521                             crow::connections::systemBus->async_method_call(
522                                 [aResp](
523                                     const boost::system::error_code ec2,
524                                     const std::vector<
525                                         std::pair<std::string, VariantType>>&
526                                         propertiesList) {
527                                     if (ec2)
528                                     {
529                                         // doesn't have to include this
530                                         // interface
531                                         return;
532                                     }
533                                     BMCWEB_LOG_DEBUG
534                                         << "Got " << propertiesList.size()
535                                         << " properties for system";
536                                     for (const std::pair<std::string,
537                                                          VariantType>&
538                                              property : propertiesList)
539                                     {
540                                         const std::string& propertyName =
541                                             property.first;
542                                         if ((propertyName == "PartNumber") ||
543                                             (propertyName == "SerialNumber") ||
544                                             (propertyName == "Manufacturer") ||
545                                             (propertyName == "Model") ||
546                                             (propertyName == "SubModel"))
547                                         {
548                                             const std::string* value =
549                                                 std::get_if<std::string>(
550                                                     &property.second);
551                                             if (value != nullptr)
552                                             {
553                                                 aResp->res
554                                                     .jsonValue[propertyName] =
555                                                     *value;
556                                             }
557                                         }
558                                     }
559 
560                                     // Grab the bios version
561                                     fw_util::populateFirmwareInformation(
562                                         aResp, fw_util::biosPurpose,
563                                         "BiosVersion", false);
564                                 },
565                                 connection.first, path,
566                                 "org.freedesktop.DBus.Properties", "GetAll",
567                                 "xyz.openbmc_project.Inventory.Decorator."
568                                 "Asset");
569 
570                             crow::connections::systemBus->async_method_call(
571                                 [aResp](
572                                     const boost::system::error_code ec2,
573                                     const std::variant<std::string>& property) {
574                                     if (ec2)
575                                     {
576                                         // doesn't have to include this
577                                         // interface
578                                         return;
579                                     }
580 
581                                     const std::string* value =
582                                         std::get_if<std::string>(&property);
583                                     if (value != nullptr)
584                                     {
585                                         aResp->res.jsonValue["AssetTag"] =
586                                             *value;
587                                     }
588                                 },
589                                 connection.first, path,
590                                 "org.freedesktop.DBus.Properties", "Get",
591                                 "xyz.openbmc_project.Inventory.Decorator."
592                                 "AssetTag",
593                                 "AssetTag");
594                         }
595                     }
596                 }
597             }
598         },
599         "xyz.openbmc_project.ObjectMapper",
600         "/xyz/openbmc_project/object_mapper",
601         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
602         "/xyz/openbmc_project/inventory", int32_t(0),
603         std::array<const char*, 5>{
604             "xyz.openbmc_project.Inventory.Decorator.Asset",
605             "xyz.openbmc_project.Inventory.Item.Cpu",
606             "xyz.openbmc_project.Inventory.Item.Dimm",
607             "xyz.openbmc_project.Inventory.Item.System",
608             "xyz.openbmc_project.Common.UUID",
609         });
610 }
611 
612 /**
613  * @brief Retrieves host state properties over dbus
614  *
615  * @param[in] aResp     Shared pointer for completing asynchronous calls.
616  *
617  * @return None.
618  */
619 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
620 {
621     BMCWEB_LOG_DEBUG << "Get host information.";
622     crow::connections::systemBus->async_method_call(
623         [aResp](const boost::system::error_code ec,
624                 const std::variant<std::string>& hostState) {
625             if (ec)
626             {
627                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
628                 messages::internalError(aResp->res);
629                 return;
630             }
631 
632             const std::string* s = std::get_if<std::string>(&hostState);
633             BMCWEB_LOG_DEBUG << "Host state: " << *s;
634             if (s != nullptr)
635             {
636                 // Verify Host State
637                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
638                 {
639                     aResp->res.jsonValue["PowerState"] = "On";
640                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
641                 }
642                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
643                                "Quiesced")
644                 {
645                     aResp->res.jsonValue["PowerState"] = "On";
646                     aResp->res.jsonValue["Status"]["State"] = "Quiesced";
647                 }
648                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
649                                "DiagnosticMode")
650                 {
651                     aResp->res.jsonValue["PowerState"] = "On";
652                     aResp->res.jsonValue["Status"]["State"] = "InTest";
653                 }
654                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
655                                "TransitioningToRunning")
656                 {
657                     aResp->res.jsonValue["PowerState"] = "PoweringOn";
658                     aResp->res.jsonValue["Status"]["State"] = "Starting";
659                 }
660                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
661                                "TransitioningToOff")
662                 {
663                     aResp->res.jsonValue["PowerState"] = "PoweringOff";
664                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
665                 }
666                 else
667                 {
668                     aResp->res.jsonValue["PowerState"] = "Off";
669                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
670                 }
671             }
672         },
673         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
674         "org.freedesktop.DBus.Properties", "Get",
675         "xyz.openbmc_project.State.Host", "CurrentHostState");
676 }
677 
678 /**
679  * @brief Translates boot source DBUS property value to redfish.
680  *
681  * @param[in] dbusSource    The boot source in DBUS speak.
682  *
683  * @return Returns as a string, the boot source in Redfish terms. If translation
684  * cannot be done, returns an empty string.
685  */
686 inline std::string dbusToRfBootSource(const std::string& dbusSource)
687 {
688     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
689     {
690         return "None";
691     }
692     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
693     {
694         return "Hdd";
695     }
696     if (dbusSource ==
697         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
698     {
699         return "Cd";
700     }
701     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
702     {
703         return "Pxe";
704     }
705     if (dbusSource ==
706         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
707     {
708         return "Usb";
709     }
710     return "";
711 }
712 
713 /**
714  * @brief Translates boot mode DBUS property value to redfish.
715  *
716  * @param[in] dbusMode    The boot mode in DBUS speak.
717  *
718  * @return Returns as a string, the boot mode in Redfish terms. If translation
719  * cannot be done, returns an empty string.
720  */
721 inline std::string dbusToRfBootMode(const std::string& dbusMode)
722 {
723     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
724     {
725         return "None";
726     }
727     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
728     {
729         return "Diags";
730     }
731     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
732     {
733         return "BiosSetup";
734     }
735     return "";
736 }
737 
738 /**
739  * @brief Translates boot source from Redfish to the DBus boot paths.
740  *
741  * @param[in] rfSource    The boot source in Redfish.
742  * @param[out] bootSource The DBus source
743  * @param[out] bootMode   the DBus boot mode
744  *
745  * @return Integer error code.
746  */
747 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
748                                 const std::string& rfSource,
749                                 std::string& bootSource, std::string& bootMode)
750 {
751     // The caller has initialized the bootSource and bootMode to:
752     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
753     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
754     // Only modify the bootSource/bootMode variable needed to achieve the
755     // desired boot action.
756 
757     if (rfSource == "None")
758     {
759         return 0;
760     }
761     if (rfSource == "Pxe")
762     {
763         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
764     }
765     else if (rfSource == "Hdd")
766     {
767         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
768     }
769     else if (rfSource == "Diags")
770     {
771         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
772     }
773     else if (rfSource == "Cd")
774     {
775         bootSource =
776             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
777     }
778     else if (rfSource == "BiosSetup")
779     {
780         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
781     }
782     else if (rfSource == "Usb")
783     {
784         bootSource =
785             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
786     }
787     else
788     {
789         BMCWEB_LOG_DEBUG << "Invalid property value for "
790                             "BootSourceOverrideTarget: "
791                          << bootSource;
792         messages::propertyValueNotInList(aResp->res, rfSource,
793                                          "BootSourceTargetOverride");
794         return -1;
795     }
796     return 0;
797 }
798 
799 /**
800  * @brief Retrieves boot progress of the system
801  *
802  * @param[in] aResp  Shared pointer for generating response message.
803  *
804  * @return None.
805  */
806 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
807 {
808     crow::connections::systemBus->async_method_call(
809         [aResp](const boost::system::error_code ec,
810                 const std::variant<std::string>& bootProgress) {
811             if (ec)
812             {
813                 // BootProgress is an optional object so just do nothing if
814                 // not found
815                 return;
816             }
817 
818             const std::string* bootProgressStr =
819                 std::get_if<std::string>(&bootProgress);
820 
821             if (!bootProgressStr)
822             {
823                 // Interface implemented but property not found, return error
824                 // for that
825                 messages::internalError(aResp->res);
826                 return;
827             }
828 
829             BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
830 
831             // Now convert the D-Bus BootProgress to the appropriate Redfish
832             // enum
833             std::string rfBpLastState = "None";
834             if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress."
835                                     "ProgressStages.Unspecified")
836             {
837                 rfBpLastState = "None";
838             }
839             else if (*bootProgressStr ==
840                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
841                      "PrimaryProcInit")
842             {
843                 rfBpLastState = "PrimaryProcessorInitializationStarted";
844             }
845             else if (*bootProgressStr ==
846                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
847                      "BusInit")
848             {
849                 rfBpLastState = "BusInitializationStarted";
850             }
851             else if (*bootProgressStr ==
852                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
853                      "MemoryInit")
854             {
855                 rfBpLastState = "MemoryInitializationStarted";
856             }
857             else if (*bootProgressStr ==
858                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
859                      "SecondaryProcInit")
860             {
861                 rfBpLastState = "SecondaryProcessorInitializationStarted";
862             }
863             else if (*bootProgressStr ==
864                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
865                      "PCIInit")
866             {
867                 rfBpLastState = "PCIResourceConfigStarted";
868             }
869             else if (*bootProgressStr ==
870                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
871                      "SystemInitComplete")
872             {
873                 rfBpLastState = "SystemHardwareInitializationComplete";
874             }
875             else if (*bootProgressStr ==
876                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
877                      "OSStart")
878             {
879                 rfBpLastState = "OSBootStarted";
880             }
881             else if (*bootProgressStr ==
882                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
883                      "OSRunning")
884             {
885                 rfBpLastState = "OSRunning";
886             }
887             else
888             {
889                 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
890                                  << *bootProgressStr;
891                 // Just return the default
892             }
893 
894             aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
895         },
896         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
897         "org.freedesktop.DBus.Properties", "Get",
898         "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
899 }
900 
901 /**
902  * @brief Retrieves boot mode over DBUS and fills out the response
903  *
904  * @param[in] aResp         Shared pointer for generating response message.
905  * @param[in] bootDbusObj   The dbus object to query for boot properties.
906  *
907  * @return None.
908  */
909 inline void getBootMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
910                         const std::string& bootDbusObj)
911 {
912     crow::connections::systemBus->async_method_call(
913         [aResp](const boost::system::error_code ec,
914                 const std::variant<std::string>& bootMode) {
915             if (ec)
916             {
917                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
918                 messages::internalError(aResp->res);
919                 return;
920             }
921 
922             const std::string* bootModeStr =
923                 std::get_if<std::string>(&bootMode);
924 
925             if (!bootModeStr)
926             {
927                 messages::internalError(aResp->res);
928                 return;
929             }
930 
931             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
932 
933             // TODO (Santosh): Do we need to support override mode?
934             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
935             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
936                                          "AllowableValues"] = {
937                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
938 
939             if (*bootModeStr !=
940                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
941             {
942                 auto rfMode = dbusToRfBootMode(*bootModeStr);
943                 if (!rfMode.empty())
944                 {
945                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
946                         rfMode;
947                 }
948             }
949 
950             // If the BootSourceOverrideTarget is still "None" at the end,
951             // reset the BootSourceOverrideEnabled to indicate that
952             // overrides are disabled
953             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
954                 "None")
955             {
956                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
957                     "Disabled";
958             }
959         },
960         "xyz.openbmc_project.Settings", bootDbusObj,
961         "org.freedesktop.DBus.Properties", "Get",
962         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
963 }
964 
965 /**
966  * @brief Retrieves boot source over DBUS
967  *
968  * @param[in] aResp         Shared pointer for generating response message.
969  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
970  *
971  * @return None.
972  */
973 inline void getBootSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
974                           bool oneTimeEnabled)
975 {
976     std::string bootDbusObj =
977         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
978                        : "/xyz/openbmc_project/control/host0/boot";
979 
980     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
981     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
982         (oneTimeEnabled) ? "Once" : "Continuous";
983 
984     crow::connections::systemBus->async_method_call(
985         [aResp, bootDbusObj](const boost::system::error_code ec,
986                              const std::variant<std::string>& bootSource) {
987             if (ec)
988             {
989                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
990                 messages::internalError(aResp->res);
991                 return;
992             }
993 
994             const std::string* bootSourceStr =
995                 std::get_if<std::string>(&bootSource);
996 
997             if (!bootSourceStr)
998             {
999                 messages::internalError(aResp->res);
1000                 return;
1001             }
1002             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
1003 
1004             auto rfSource = dbusToRfBootSource(*bootSourceStr);
1005             if (!rfSource.empty())
1006             {
1007                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1008                     rfSource;
1009             }
1010         },
1011         "xyz.openbmc_project.Settings", bootDbusObj,
1012         "org.freedesktop.DBus.Properties", "Get",
1013         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
1014     getBootMode(aResp, bootDbusObj);
1015 }
1016 
1017 /**
1018  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1019  * get boot source and boot mode.
1020  *
1021  * @param[in] aResp     Shared pointer for generating response message.
1022  *
1023  * @return None.
1024  */
1025 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1026 {
1027     BMCWEB_LOG_DEBUG << "Get boot information.";
1028 
1029     crow::connections::systemBus->async_method_call(
1030         [aResp](const boost::system::error_code ec,
1031                 const std::variant<bool>& oneTime) {
1032             if (ec)
1033             {
1034                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1035                 // not an error, don't have to have the interface
1036                 return;
1037             }
1038 
1039             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1040 
1041             if (!oneTimePtr)
1042             {
1043                 messages::internalError(aResp->res);
1044                 return;
1045             }
1046             getBootSource(aResp, *oneTimePtr);
1047         },
1048         "xyz.openbmc_project.Settings",
1049         "/xyz/openbmc_project/control/host0/boot/one_time",
1050         "org.freedesktop.DBus.Properties", "Get",
1051         "xyz.openbmc_project.Object.Enable", "Enabled");
1052 }
1053 
1054 /**
1055  * @brief Retrieves the Last Reset Time
1056  *
1057  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1058  * and power off. Even though this is the "system" Redfish object look at the
1059  * chassis D-Bus interface for the LastStateChangeTime since this has the
1060  * last power operation time.
1061  *
1062  * @param[in] aResp     Shared pointer for generating response message.
1063  *
1064  * @return None.
1065  */
1066 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1067 {
1068     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1069 
1070     crow::connections::systemBus->async_method_call(
1071         [aResp](const boost::system::error_code ec,
1072                 std::variant<uint64_t>& lastResetTime) {
1073             if (ec)
1074             {
1075                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1076                 return;
1077             }
1078 
1079             const uint64_t* lastResetTimePtr =
1080                 std::get_if<uint64_t>(&lastResetTime);
1081 
1082             if (!lastResetTimePtr)
1083             {
1084                 messages::internalError(aResp->res);
1085                 return;
1086             }
1087             // LastStateChangeTime is epoch time, in milliseconds
1088             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1089             time_t lastResetTimeStamp =
1090                 static_cast<time_t>(*lastResetTimePtr / 1000);
1091 
1092             // Convert to ISO 8601 standard
1093             aResp->res.jsonValue["LastResetTime"] =
1094                 crow::utility::getDateTime(lastResetTimeStamp);
1095         },
1096         "xyz.openbmc_project.State.Chassis",
1097         "/xyz/openbmc_project/state/chassis0",
1098         "org.freedesktop.DBus.Properties", "Get",
1099         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1100 }
1101 
1102 /**
1103  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1104  *
1105  * @param[in] aResp     Shared pointer for generating response message.
1106  *
1107  * @return None.
1108  */
1109 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1110 {
1111     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1112 
1113     crow::connections::systemBus->async_method_call(
1114         [aResp](const boost::system::error_code ec,
1115                 std::variant<bool>& autoRebootEnabled) {
1116             if (ec)
1117             {
1118                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1119                 return;
1120             }
1121 
1122             const bool* autoRebootEnabledPtr =
1123                 std::get_if<bool>(&autoRebootEnabled);
1124 
1125             if (!autoRebootEnabledPtr)
1126             {
1127                 messages::internalError(aResp->res);
1128                 return;
1129             }
1130 
1131             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1132             if (*autoRebootEnabledPtr == true)
1133             {
1134                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1135                     "RetryAttempts";
1136                 // If AutomaticRetry (AutoReboot) is enabled see how many
1137                 // attempts are left
1138                 crow::connections::systemBus->async_method_call(
1139                     [aResp](const boost::system::error_code ec2,
1140                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1141                         if (ec2)
1142                         {
1143                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1144                             return;
1145                         }
1146 
1147                         const uint32_t* autoRebootAttemptsLeftPtr =
1148                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1149 
1150                         if (!autoRebootAttemptsLeftPtr)
1151                         {
1152                             messages::internalError(aResp->res);
1153                             return;
1154                         }
1155 
1156                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1157                                          << *autoRebootAttemptsLeftPtr;
1158 
1159                         aResp->res
1160                             .jsonValue["Boot"]
1161                                       ["RemainingAutomaticRetryAttempts"] =
1162                             *autoRebootAttemptsLeftPtr;
1163                     },
1164                     "xyz.openbmc_project.State.Host",
1165                     "/xyz/openbmc_project/state/host0",
1166                     "org.freedesktop.DBus.Properties", "Get",
1167                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1168                     "AttemptsLeft");
1169             }
1170             else
1171             {
1172                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1173                     "Disabled";
1174             }
1175 
1176             // Not on D-Bus. Hardcoded here:
1177             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1178             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1179 
1180             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1181             // and RetryAttempts. OpenBMC only supports Disabled and
1182             // RetryAttempts.
1183             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1184                                          "AllowableValues"] = {"Disabled",
1185                                                                "RetryAttempts"};
1186         },
1187         "xyz.openbmc_project.Settings",
1188         "/xyz/openbmc_project/control/host0/auto_reboot",
1189         "org.freedesktop.DBus.Properties", "Get",
1190         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1191 }
1192 
1193 /**
1194  * @brief Retrieves power restore policy over DBUS.
1195  *
1196  * @param[in] aResp     Shared pointer for generating response message.
1197  *
1198  * @return None.
1199  */
1200 inline void
1201     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1202 {
1203     BMCWEB_LOG_DEBUG << "Get power restore policy";
1204 
1205     crow::connections::systemBus->async_method_call(
1206         [aResp](const boost::system::error_code ec,
1207                 std::variant<std::string>& policy) {
1208             if (ec)
1209             {
1210                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1211                 return;
1212             }
1213 
1214             const boost::container::flat_map<std::string, std::string>
1215                 policyMaps = {
1216                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1217                      "AlwaysOn",
1218                      "AlwaysOn"},
1219                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1220                      "AlwaysOff",
1221                      "AlwaysOff"},
1222                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1223                      "Restore",
1224                      "LastState"}};
1225 
1226             const std::string* policyPtr = std::get_if<std::string>(&policy);
1227 
1228             if (!policyPtr)
1229             {
1230                 messages::internalError(aResp->res);
1231                 return;
1232             }
1233 
1234             auto policyMapsIt = policyMaps.find(*policyPtr);
1235             if (policyMapsIt == policyMaps.end())
1236             {
1237                 messages::internalError(aResp->res);
1238                 return;
1239             }
1240 
1241             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1242         },
1243         "xyz.openbmc_project.Settings",
1244         "/xyz/openbmc_project/control/host0/power_restore_policy",
1245         "org.freedesktop.DBus.Properties", "Get",
1246         "xyz.openbmc_project.Control.Power.RestorePolicy",
1247         "PowerRestorePolicy");
1248 }
1249 
1250 /**
1251  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1252  * TPM is required for booting the host.
1253  *
1254  * @param[in] aResp     Shared pointer for generating response message.
1255  *
1256  * @return None.
1257  */
1258 inline void getTrustedModuleRequiredToBoot(
1259     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1260 {
1261     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1262 
1263     crow::connections::systemBus->async_method_call(
1264         [aResp](
1265             const boost::system::error_code ec,
1266             std::vector<std::pair<
1267                 std::string,
1268                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1269                 subtree) {
1270             if (ec)
1271             {
1272                 BMCWEB_LOG_DEBUG
1273                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1274                 // This is an optional D-Bus object so just return if
1275                 // error occurs
1276                 return;
1277             }
1278             if (subtree.size() == 0)
1279             {
1280                 // As noted above, this is an optional interface so just return
1281                 // if there is no instance found
1282                 return;
1283             }
1284 
1285             /* When there is more than one TPMEnable object... */
1286             if (subtree.size() > 1)
1287             {
1288                 BMCWEB_LOG_DEBUG
1289                     << "DBUS response has more than 1 TPM Enable object:"
1290                     << subtree.size();
1291                 // Throw an internal Error and return
1292                 messages::internalError(aResp->res);
1293                 return;
1294             }
1295 
1296             // Make sure the Dbus response map has a service and objectPath
1297             // field
1298             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1299             {
1300                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1301                 messages::internalError(aResp->res);
1302                 return;
1303             }
1304 
1305             const std::string& path = subtree[0].first;
1306             const std::string& serv = subtree[0].second.begin()->first;
1307 
1308             // Valid TPM Enable object found, now reading the current value
1309             crow::connections::systemBus->async_method_call(
1310                 [aResp](const boost::system::error_code ec,
1311                         std::variant<bool>& tpmRequired) {
1312                     if (ec)
1313                     {
1314                         BMCWEB_LOG_DEBUG
1315                             << "D-BUS response error on TPM.Policy Get" << ec;
1316                         messages::internalError(aResp->res);
1317                         return;
1318                     }
1319 
1320                     const bool* tpmRequiredVal =
1321                         std::get_if<bool>(&tpmRequired);
1322 
1323                     if (!tpmRequiredVal)
1324                     {
1325                         messages::internalError(aResp->res);
1326                         return;
1327                     }
1328 
1329                     if (*tpmRequiredVal == true)
1330                     {
1331                         aResp->res
1332                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1333                             "Required";
1334                     }
1335                     else
1336                     {
1337                         aResp->res
1338                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1339                             "Disabled";
1340                     }
1341                 },
1342                 serv, path, "org.freedesktop.DBus.Properties", "Get",
1343                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable");
1344         },
1345         "xyz.openbmc_project.ObjectMapper",
1346         "/xyz/openbmc_project/object_mapper",
1347         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1348         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1349 }
1350 
1351 /**
1352  * @brief Sets boot properties into DBUS object(s).
1353  *
1354  * @param[in] aResp           Shared pointer for generating response message.
1355  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
1356  * @param[in] bootSource      The boot source to set.
1357  * @param[in] bootEnable      The source override "enable" to set.
1358  *
1359  * @return Integer error code.
1360  */
1361 inline void setBootModeOrSource(std::shared_ptr<bmcweb::AsyncResp> aResp,
1362                                 bool oneTimeEnabled,
1363                                 const std::optional<std::string>& bootSource,
1364                                 const std::optional<std::string>& bootEnable)
1365 {
1366     std::string bootSourceStr =
1367         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1368     std::string bootModeStr =
1369         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1370     bool oneTimeSetting = oneTimeEnabled;
1371     bool useBootSource = true;
1372 
1373     // Validate incoming parameters
1374     if (bootEnable)
1375     {
1376         if (*bootEnable == "Once")
1377         {
1378             oneTimeSetting = true;
1379         }
1380         else if (*bootEnable == "Continuous")
1381         {
1382             oneTimeSetting = false;
1383         }
1384         else if (*bootEnable == "Disabled")
1385         {
1386             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1387             oneTimeSetting = false;
1388             useBootSource = false;
1389         }
1390         else
1391         {
1392             BMCWEB_LOG_DEBUG << "Unsupported value for "
1393                                 "BootSourceOverrideEnabled: "
1394                              << *bootEnable;
1395             messages::propertyValueNotInList(aResp->res, *bootEnable,
1396                                              "BootSourceOverrideEnabled");
1397             return;
1398         }
1399     }
1400 
1401     if (bootSource && useBootSource)
1402     {
1403         // Source target specified
1404         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1405         // Figure out which DBUS interface and property to use
1406         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1407                                  bootModeStr))
1408         {
1409             BMCWEB_LOG_DEBUG
1410                 << "Invalid property value for BootSourceOverrideTarget: "
1411                 << *bootSource;
1412             messages::propertyValueNotInList(aResp->res, *bootSource,
1413                                              "BootSourceTargetOverride");
1414             return;
1415         }
1416     }
1417 
1418     // Act on validated parameters
1419     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1420     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1421     const char* bootObj =
1422         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1423                        : "/xyz/openbmc_project/control/host0/boot";
1424 
1425     crow::connections::systemBus->async_method_call(
1426         [aResp](const boost::system::error_code ec) {
1427             if (ec)
1428             {
1429                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1430                 messages::internalError(aResp->res);
1431                 return;
1432             }
1433             BMCWEB_LOG_DEBUG << "Boot source update done.";
1434         },
1435         "xyz.openbmc_project.Settings", bootObj,
1436         "org.freedesktop.DBus.Properties", "Set",
1437         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1438         std::variant<std::string>(bootSourceStr));
1439 
1440     crow::connections::systemBus->async_method_call(
1441         [aResp](const boost::system::error_code ec) {
1442             if (ec)
1443             {
1444                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1445                 messages::internalError(aResp->res);
1446                 return;
1447             }
1448             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1449         },
1450         "xyz.openbmc_project.Settings", bootObj,
1451         "org.freedesktop.DBus.Properties", "Set",
1452         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1453         std::variant<std::string>(bootModeStr));
1454 
1455     crow::connections::systemBus->async_method_call(
1456         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1457             if (ec)
1458             {
1459                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1460                 messages::internalError(aResp->res);
1461                 return;
1462             }
1463             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1464         },
1465         "xyz.openbmc_project.Settings",
1466         "/xyz/openbmc_project/control/host0/boot/one_time",
1467         "org.freedesktop.DBus.Properties", "Set",
1468         "xyz.openbmc_project.Object.Enable", "Enabled",
1469         std::variant<bool>(oneTimeSetting));
1470 }
1471 
1472 /**
1473  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1474  * set boot source/boot mode properties.
1475  *
1476  * @param[in] aResp      Shared pointer for generating response message.
1477  * @param[in] bootSource The boot source from incoming RF request.
1478  * @param[in] bootEnable The boot override enable from incoming RF request.
1479  *
1480  * @return Integer error code.
1481  */
1482 inline void
1483     setBootSourceProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1484                             std::optional<std::string> bootSource,
1485                             std::optional<std::string> bootEnable)
1486 {
1487     BMCWEB_LOG_DEBUG << "Set boot information.";
1488 
1489     crow::connections::systemBus->async_method_call(
1490         [aResp, bootSource{std::move(bootSource)},
1491          bootEnable{std::move(bootEnable)}](const boost::system::error_code ec,
1492                                             const std::variant<bool>& oneTime) {
1493             if (ec)
1494             {
1495                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1496                 messages::internalError(aResp->res);
1497                 return;
1498             }
1499 
1500             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1501 
1502             if (!oneTimePtr)
1503             {
1504                 messages::internalError(aResp->res);
1505                 return;
1506             }
1507 
1508             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1509 
1510             setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable);
1511         },
1512         "xyz.openbmc_project.Settings",
1513         "/xyz/openbmc_project/control/host0/boot/one_time",
1514         "org.freedesktop.DBus.Properties", "Get",
1515         "xyz.openbmc_project.Object.Enable", "Enabled");
1516 }
1517 
1518 /**
1519  * @brief Sets AssetTag
1520  *
1521  * @param[in] aResp   Shared pointer for generating response message.
1522  * @param[in] assetTag  "AssetTag" from request.
1523  *
1524  * @return None.
1525  */
1526 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1527                         const std::string& assetTag)
1528 {
1529     crow::connections::systemBus->async_method_call(
1530         [aResp, assetTag](
1531             const boost::system::error_code ec,
1532             const std::vector<std::pair<
1533                 std::string,
1534                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1535                 subtree) {
1536             if (ec)
1537             {
1538                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1539                 messages::internalError(aResp->res);
1540                 return;
1541             }
1542             if (subtree.size() == 0)
1543             {
1544                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1545                 messages::internalError(aResp->res);
1546                 return;
1547             }
1548             // Assume only 1 system D-Bus object
1549             // Throw an error if there is more than 1
1550             if (subtree.size() > 1)
1551             {
1552                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1553                 messages::internalError(aResp->res);
1554                 return;
1555             }
1556             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1557             {
1558                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1559                 messages::internalError(aResp->res);
1560                 return;
1561             }
1562 
1563             const std::string& path = subtree[0].first;
1564             const std::string& service = subtree[0].second.begin()->first;
1565 
1566             if (service.empty())
1567             {
1568                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1569                 messages::internalError(aResp->res);
1570                 return;
1571             }
1572 
1573             crow::connections::systemBus->async_method_call(
1574                 [aResp](const boost::system::error_code ec2) {
1575                     if (ec2)
1576                     {
1577                         BMCWEB_LOG_DEBUG
1578                             << "D-Bus response error on AssetTag Set " << ec2;
1579                         messages::internalError(aResp->res);
1580                         return;
1581                     }
1582                 },
1583                 service, path, "org.freedesktop.DBus.Properties", "Set",
1584                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1585                 std::variant<std::string>(assetTag));
1586         },
1587         "xyz.openbmc_project.ObjectMapper",
1588         "/xyz/openbmc_project/object_mapper",
1589         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1590         "/xyz/openbmc_project/inventory", int32_t(0),
1591         std::array<const char*, 1>{
1592             "xyz.openbmc_project.Inventory.Item.System"});
1593 }
1594 
1595 /**
1596  * @brief Sets automaticRetry (Auto Reboot)
1597  *
1598  * @param[in] aResp   Shared pointer for generating response message.
1599  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1600  *
1601  * @return None.
1602  */
1603 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1604                               const std::string& automaticRetryConfig)
1605 {
1606     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1607 
1608     // OpenBMC only supports "Disabled" and "RetryAttempts".
1609     bool autoRebootEnabled;
1610 
1611     if (automaticRetryConfig == "Disabled")
1612     {
1613         autoRebootEnabled = false;
1614     }
1615     else if (automaticRetryConfig == "RetryAttempts")
1616     {
1617         autoRebootEnabled = true;
1618     }
1619     else
1620     {
1621         BMCWEB_LOG_DEBUG << "Invalid property value for "
1622                             "AutomaticRetryConfig: "
1623                          << automaticRetryConfig;
1624         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1625                                          "AutomaticRetryConfig");
1626         return;
1627     }
1628 
1629     crow::connections::systemBus->async_method_call(
1630         [aResp](const boost::system::error_code ec) {
1631             if (ec)
1632             {
1633                 messages::internalError(aResp->res);
1634                 return;
1635             }
1636         },
1637         "xyz.openbmc_project.Settings",
1638         "/xyz/openbmc_project/control/host0/auto_reboot",
1639         "org.freedesktop.DBus.Properties", "Set",
1640         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1641         std::variant<bool>(autoRebootEnabled));
1642 }
1643 
1644 /**
1645  * @brief Sets power restore policy properties.
1646  *
1647  * @param[in] aResp   Shared pointer for generating response message.
1648  * @param[in] policy  power restore policy properties from request.
1649  *
1650  * @return None.
1651  */
1652 inline void
1653     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1654                           const std::string& policy)
1655 {
1656     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1657 
1658     const boost::container::flat_map<std::string, std::string> policyMaps = {
1659         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1660                      "AlwaysOn"},
1661         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1662                       "AlwaysOff"},
1663         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1664                       "Restore"}};
1665 
1666     std::string powerRestorPolicy;
1667 
1668     auto policyMapsIt = policyMaps.find(policy);
1669     if (policyMapsIt == policyMaps.end())
1670     {
1671         messages::propertyValueNotInList(aResp->res, policy,
1672                                          "PowerRestorePolicy");
1673         return;
1674     }
1675 
1676     powerRestorPolicy = policyMapsIt->second;
1677 
1678     crow::connections::systemBus->async_method_call(
1679         [aResp](const boost::system::error_code ec) {
1680             if (ec)
1681             {
1682                 messages::internalError(aResp->res);
1683                 return;
1684             }
1685         },
1686         "xyz.openbmc_project.Settings",
1687         "/xyz/openbmc_project/control/host0/power_restore_policy",
1688         "org.freedesktop.DBus.Properties", "Set",
1689         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1690         std::variant<std::string>(powerRestorPolicy));
1691 }
1692 
1693 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1694 /**
1695  * @brief Retrieves provisioning status
1696  *
1697  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1698  *
1699  * @return None.
1700  */
1701 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1702 {
1703     BMCWEB_LOG_DEBUG << "Get OEM information.";
1704     crow::connections::systemBus->async_method_call(
1705         [aResp](const boost::system::error_code ec,
1706                 const std::vector<std::pair<std::string, VariantType>>&
1707                     propertiesList) {
1708             nlohmann::json& oemPFR =
1709                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1710             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1711                 "#OemComputerSystem.OpenBmc";
1712             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1713 
1714             if (ec)
1715             {
1716                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1717                 // not an error, don't have to have the interface
1718                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1719                 return;
1720             }
1721 
1722             const bool* provState = nullptr;
1723             const bool* lockState = nullptr;
1724             for (const std::pair<std::string, VariantType>& property :
1725                  propertiesList)
1726             {
1727                 if (property.first == "UfmProvisioned")
1728                 {
1729                     provState = std::get_if<bool>(&property.second);
1730                 }
1731                 else if (property.first == "UfmLocked")
1732                 {
1733                     lockState = std::get_if<bool>(&property.second);
1734                 }
1735             }
1736 
1737             if ((provState == nullptr) || (lockState == nullptr))
1738             {
1739                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1740                 messages::internalError(aResp->res);
1741                 return;
1742             }
1743 
1744             if (*provState == true)
1745             {
1746                 if (*lockState == true)
1747                 {
1748                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1749                 }
1750                 else
1751                 {
1752                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1753                 }
1754             }
1755             else
1756             {
1757                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1758             }
1759         },
1760         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1761         "org.freedesktop.DBus.Properties", "GetAll",
1762         "xyz.openbmc_project.PFR.Attributes");
1763 }
1764 #endif
1765 
1766 /**
1767  * @brief Translate the PowerMode to a response message.
1768  *
1769  * @param[in] aResp  Shared pointer for generating response message.
1770  * @param[in] modeValue  PowerMode value to be translated
1771  *
1772  * @return None.
1773  */
1774 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1775                                const std::string& modeValue)
1776 {
1777     std::string modeString;
1778 
1779     if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1780                      "PowerMode.Static")
1781     {
1782         aResp->res.jsonValue["PowerMode"] = "Static";
1783     }
1784     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1785                           "PowerMode.MaximumPerformance")
1786     {
1787         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
1788     }
1789     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1790                           "PowerMode.PowerSaving")
1791     {
1792         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
1793     }
1794     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1795                           "PowerMode.OEM")
1796     {
1797         aResp->res.jsonValue["PowerMode"] = "OEM";
1798     }
1799     else
1800     {
1801         // Any other values would be invalid
1802         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
1803         messages::internalError(aResp->res);
1804     }
1805 }
1806 
1807 /**
1808  * @brief Retrieves system power mode
1809  *
1810  * @param[in] aResp  Shared pointer for generating response message.
1811  *
1812  * @return None.
1813  */
1814 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1815 {
1816     BMCWEB_LOG_DEBUG << "Get power mode.";
1817 
1818     // Get Power Mode object path:
1819     crow::connections::systemBus->async_method_call(
1820         [aResp](
1821             const boost::system::error_code ec,
1822             const std::vector<std::pair<
1823                 std::string,
1824                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1825                 subtree) {
1826             if (ec)
1827             {
1828                 BMCWEB_LOG_DEBUG
1829                     << "DBUS response error on Power.Mode GetSubTree " << ec;
1830                 // This is an optional D-Bus object so just return if
1831                 // error occurs
1832                 return;
1833             }
1834             if (subtree.empty())
1835             {
1836                 // As noted above, this is an optional interface so just return
1837                 // if there is no instance found
1838                 return;
1839             }
1840             if (subtree.size() > 1)
1841             {
1842                 // More then one PowerMode object is not supported and is an
1843                 // error
1844                 BMCWEB_LOG_DEBUG
1845                     << "Found more than 1 system D-Bus Power.Mode objects: "
1846                     << subtree.size();
1847                 messages::internalError(aResp->res);
1848                 return;
1849             }
1850             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
1851             {
1852                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
1853                 messages::internalError(aResp->res);
1854                 return;
1855             }
1856             const std::string& path = subtree[0].first;
1857             const std::string& service = subtree[0].second.begin()->first;
1858             if (service.empty())
1859             {
1860                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
1861                 messages::internalError(aResp->res);
1862                 return;
1863             }
1864             // Valid Power Mode object found, now read the current value
1865             crow::connections::systemBus->async_method_call(
1866                 [aResp](const boost::system::error_code ec,
1867                         const std::variant<std::string>& pmode) {
1868                     if (ec)
1869                     {
1870                         BMCWEB_LOG_DEBUG
1871                             << "DBUS response error on PowerMode Get: " << ec;
1872                         messages::internalError(aResp->res);
1873                         return;
1874                     }
1875 
1876                     const std::string* s = std::get_if<std::string>(&pmode);
1877                     if (s == nullptr)
1878                     {
1879                         BMCWEB_LOG_DEBUG << "Unable to get PowerMode value";
1880                         messages::internalError(aResp->res);
1881                         return;
1882                     }
1883 
1884                     aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] =
1885                         {"Static", "MaximumPerformance", "PowerSaving"};
1886 
1887                     BMCWEB_LOG_DEBUG << "Current power mode: " << *s;
1888                     translatePowerMode(aResp, *s);
1889                 },
1890                 service, path, "org.freedesktop.DBus.Properties", "Get",
1891                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode");
1892         },
1893         "xyz.openbmc_project.ObjectMapper",
1894         "/xyz/openbmc_project/object_mapper",
1895         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1896         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
1897 }
1898 
1899 /**
1900  * @brief Validate the specified mode is valid and return the PowerMode
1901  * name associated with that string
1902  *
1903  * @param[in] aResp   Shared pointer for generating response message.
1904  * @param[in] modeString  String representing the desired PowerMode
1905  *
1906  * @return PowerMode value or empty string if mode is not valid
1907  */
1908 inline std::string
1909     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1910                       const std::string& modeString)
1911 {
1912     std::string mode;
1913 
1914     if (modeString == "Static")
1915     {
1916         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
1917     }
1918     else if (modeString == "MaximumPerformance")
1919     {
1920         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode."
1921                "MaximumPerformance";
1922     }
1923     else if (modeString == "PowerSaving")
1924     {
1925         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
1926     }
1927     else
1928     {
1929         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
1930     }
1931     return mode;
1932 }
1933 
1934 /**
1935  * @brief Sets system power mode.
1936  *
1937  * @param[in] aResp   Shared pointer for generating response message.
1938  * @param[in] pmode   System power mode from request.
1939  *
1940  * @return None.
1941  */
1942 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1943                          const std::string& pmode)
1944 {
1945     BMCWEB_LOG_DEBUG << "Set power mode.";
1946 
1947     std::string powerMode = validatePowerMode(aResp, pmode);
1948     if (powerMode.empty())
1949     {
1950         return;
1951     }
1952 
1953     // Get Power Mode object path:
1954     crow::connections::systemBus->async_method_call(
1955         [aResp, powerMode](
1956             const boost::system::error_code ec,
1957             const std::vector<std::pair<
1958                 std::string,
1959                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1960                 subtree) {
1961             if (ec)
1962             {
1963                 BMCWEB_LOG_DEBUG
1964                     << "DBUS response error on Power.Mode GetSubTree " << ec;
1965                 // This is an optional D-Bus object, but user attempted to patch
1966                 messages::internalError(aResp->res);
1967                 return;
1968             }
1969             if (subtree.empty())
1970             {
1971                 // This is an optional D-Bus object, but user attempted to patch
1972                 messages::resourceNotFound(aResp->res, "ComputerSystem",
1973                                            "PowerMode");
1974                 return;
1975             }
1976             if (subtree.size() > 1)
1977             {
1978                 // More then one PowerMode object is not supported and is an
1979                 // error
1980                 BMCWEB_LOG_DEBUG
1981                     << "Found more than 1 system D-Bus Power.Mode objects: "
1982                     << subtree.size();
1983                 messages::internalError(aResp->res);
1984                 return;
1985             }
1986             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
1987             {
1988                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
1989                 messages::internalError(aResp->res);
1990                 return;
1991             }
1992             const std::string& path = subtree[0].first;
1993             const std::string& service = subtree[0].second.begin()->first;
1994             if (service.empty())
1995             {
1996                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
1997                 messages::internalError(aResp->res);
1998                 return;
1999             }
2000 
2001             BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2002                              << path;
2003 
2004             // Set the Power Mode property
2005             crow::connections::systemBus->async_method_call(
2006                 [aResp](const boost::system::error_code ec) {
2007                     if (ec)
2008                     {
2009                         messages::internalError(aResp->res);
2010                         return;
2011                     }
2012                 },
2013                 service, path, "org.freedesktop.DBus.Properties", "Set",
2014                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2015                 std::variant<std::string>(powerMode));
2016         },
2017         "xyz.openbmc_project.ObjectMapper",
2018         "/xyz/openbmc_project/object_mapper",
2019         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2020         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2021 }
2022 
2023 /**
2024  * @brief Translates watchdog timeout action DBUS property value to redfish.
2025  *
2026  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2027  *
2028  * @return Returns as a string, the timeout action in Redfish terms. If
2029  * translation cannot be done, returns an empty string.
2030  */
2031 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2032 {
2033     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2034     {
2035         return "None";
2036     }
2037     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2038     {
2039         return "ResetSystem";
2040     }
2041     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2042     {
2043         return "PowerDown";
2044     }
2045     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2046     {
2047         return "PowerCycle";
2048     }
2049 
2050     return "";
2051 }
2052 
2053 /**
2054  *@brief Translates timeout action from Redfish to DBUS property value.
2055  *
2056  *@param[in] rfAction The timeout action in Redfish.
2057  *
2058  *@return Returns as a string, the time_out action as expected by DBUS.
2059  *If translation cannot be done, returns an empty string.
2060  */
2061 
2062 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2063 {
2064     if (rfAction == "None")
2065     {
2066         return "xyz.openbmc_project.State.Watchdog.Action.None";
2067     }
2068     if (rfAction == "PowerCycle")
2069     {
2070         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2071     }
2072     if (rfAction == "PowerDown")
2073     {
2074         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2075     }
2076     if (rfAction == "ResetSystem")
2077     {
2078         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2079     }
2080 
2081     return "";
2082 }
2083 
2084 /**
2085  * @brief Retrieves host watchdog timer properties over DBUS
2086  *
2087  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2088  *
2089  * @return None.
2090  */
2091 inline void
2092     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2093 {
2094     BMCWEB_LOG_DEBUG << "Get host watchodg";
2095     crow::connections::systemBus->async_method_call(
2096         [aResp](const boost::system::error_code ec,
2097                 PropertiesType& properties) {
2098             if (ec)
2099             {
2100                 // watchdog service is stopped
2101                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2102                 return;
2103             }
2104 
2105             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2106 
2107             nlohmann::json& hostWatchdogTimer =
2108                 aResp->res.jsonValue["HostWatchdogTimer"];
2109 
2110             // watchdog service is running/enabled
2111             hostWatchdogTimer["Status"]["State"] = "Enabled";
2112 
2113             for (const auto& property : properties)
2114             {
2115                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
2116                 if (property.first == "Enabled")
2117                 {
2118                     const bool* state = std::get_if<bool>(&property.second);
2119 
2120                     if (!state)
2121                     {
2122                         messages::internalError(aResp->res);
2123                         return;
2124                     }
2125 
2126                     hostWatchdogTimer["FunctionEnabled"] = *state;
2127                 }
2128                 else if (property.first == "ExpireAction")
2129                 {
2130                     const std::string* s =
2131                         std::get_if<std::string>(&property.second);
2132                     if (!s)
2133                     {
2134                         messages::internalError(aResp->res);
2135                         return;
2136                     }
2137 
2138                     std::string action = dbusToRfWatchdogAction(*s);
2139                     if (action.empty())
2140                     {
2141                         messages::internalError(aResp->res);
2142                         return;
2143                     }
2144                     hostWatchdogTimer["TimeoutAction"] = action;
2145                 }
2146             }
2147         },
2148         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2149         "org.freedesktop.DBus.Properties", "GetAll",
2150         "xyz.openbmc_project.State.Watchdog");
2151 }
2152 
2153 /**
2154  * @brief Sets Host WatchDog Timer properties.
2155  *
2156  * @param[in] aResp      Shared pointer for generating response message.
2157  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2158  *                       RF request.
2159  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2160  *
2161  * @return None.
2162  */
2163 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2164                              const std::optional<bool> wdtEnable,
2165                              const std::optional<std::string>& wdtTimeOutAction)
2166 {
2167     BMCWEB_LOG_DEBUG << "Set host watchdog";
2168 
2169     if (wdtTimeOutAction)
2170     {
2171         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2172         // check if TimeOut Action is Valid
2173         if (wdtTimeOutActStr.empty())
2174         {
2175             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2176                              << *wdtTimeOutAction;
2177             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2178                                              "TimeoutAction");
2179             return;
2180         }
2181 
2182         crow::connections::systemBus->async_method_call(
2183             [aResp](const boost::system::error_code ec) {
2184                 if (ec)
2185                 {
2186                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2187                     messages::internalError(aResp->res);
2188                     return;
2189                 }
2190             },
2191             "xyz.openbmc_project.Watchdog",
2192             "/xyz/openbmc_project/watchdog/host0",
2193             "org.freedesktop.DBus.Properties", "Set",
2194             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2195             std::variant<std::string>(wdtTimeOutActStr));
2196     }
2197 
2198     if (wdtEnable)
2199     {
2200         crow::connections::systemBus->async_method_call(
2201             [aResp](const boost::system::error_code ec) {
2202                 if (ec)
2203                 {
2204                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2205                     messages::internalError(aResp->res);
2206                     return;
2207                 }
2208             },
2209             "xyz.openbmc_project.Watchdog",
2210             "/xyz/openbmc_project/watchdog/host0",
2211             "org.freedesktop.DBus.Properties", "Set",
2212             "xyz.openbmc_project.State.Watchdog", "Enabled",
2213             std::variant<bool>(*wdtEnable));
2214     }
2215 }
2216 
2217 /**
2218  * SystemsCollection derived class for delivering ComputerSystems Collection
2219  * Schema
2220  */
2221 inline void requestRoutesSystemsCollection(App& app)
2222 {
2223     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2224         .privileges(redfish::privileges::getComputerSystemCollection)
2225         .methods(boost::beast::http::verb::get)(
2226             [](const crow::Request& /*req*/,
2227                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2228                 asyncResp->res.jsonValue["@odata.type"] =
2229                     "#ComputerSystemCollection.ComputerSystemCollection";
2230                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2231                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2232 
2233                 crow::connections::systemBus->async_method_call(
2234                     [asyncResp](const boost::system::error_code ec,
2235                                 const std::variant<std::string>& /*hostName*/) {
2236                         nlohmann::json& ifaceArray =
2237                             asyncResp->res.jsonValue["Members"];
2238                         ifaceArray = nlohmann::json::array();
2239                         auto& count =
2240                             asyncResp->res.jsonValue["Members@odata.count"];
2241                         ifaceArray.push_back(
2242                             {{"@odata.id", "/redfish/v1/Systems/system"}});
2243                         count = ifaceArray.size();
2244                         if (!ec)
2245                         {
2246                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
2247                             ifaceArray.push_back(
2248                                 {{"@odata.id",
2249                                   "/redfish/v1/Systems/hypervisor"}});
2250                             count = ifaceArray.size();
2251                         }
2252                     },
2253                     "xyz.openbmc_project.Settings",
2254                     "/xyz/openbmc_project/network/hypervisor",
2255                     "org.freedesktop.DBus.Properties", "Get",
2256                     "xyz.openbmc_project.Network.SystemConfiguration",
2257                     "HostName");
2258             });
2259 }
2260 
2261 /**
2262  * Function transceives data with dbus directly.
2263  */
2264 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2265 {
2266     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2267     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2268     constexpr char const* interfaceName =
2269         "xyz.openbmc_project.Control.Host.NMI";
2270     constexpr char const* method = "NMI";
2271 
2272     crow::connections::systemBus->async_method_call(
2273         [asyncResp](const boost::system::error_code ec) {
2274             if (ec)
2275             {
2276                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2277                 messages::internalError(asyncResp->res);
2278                 return;
2279             }
2280             messages::success(asyncResp->res);
2281         },
2282         serviceName, objectPath, interfaceName, method);
2283 }
2284 
2285 /**
2286  * SystemActionsReset class supports handle POST method for Reset action.
2287  * The class retrieves and sends data directly to D-Bus.
2288  */
2289 inline void requestRoutesSystemActionsReset(App& app)
2290 {
2291     /**
2292      * Function handles POST method request.
2293      * Analyzes POST body message before sends Reset request data to D-Bus.
2294      */
2295     BMCWEB_ROUTE(app,
2296                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2297         .privileges(redfish::privileges::postComputerSystem)
2298         .methods(
2299             boost::beast::http::verb::
2300                 post)([](const crow::Request& req,
2301                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2302             std::string resetType;
2303             if (!json_util::readJson(req, asyncResp->res, "ResetType",
2304                                      resetType))
2305             {
2306                 return;
2307             }
2308 
2309             // Get the command and host vs. chassis
2310             std::string command;
2311             bool hostCommand;
2312             if ((resetType == "On") || (resetType == "ForceOn"))
2313             {
2314                 command = "xyz.openbmc_project.State.Host.Transition.On";
2315                 hostCommand = true;
2316             }
2317             else if (resetType == "ForceOff")
2318             {
2319                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2320                 hostCommand = false;
2321             }
2322             else if (resetType == "ForceRestart")
2323             {
2324                 command =
2325                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2326                 hostCommand = true;
2327             }
2328             else if (resetType == "GracefulShutdown")
2329             {
2330                 command = "xyz.openbmc_project.State.Host.Transition.Off";
2331                 hostCommand = true;
2332             }
2333             else if (resetType == "GracefulRestart")
2334             {
2335                 command = "xyz.openbmc_project.State.Host.Transition."
2336                           "GracefulWarmReboot";
2337                 hostCommand = true;
2338             }
2339             else if (resetType == "PowerCycle")
2340             {
2341                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2342                 hostCommand = true;
2343             }
2344             else if (resetType == "Nmi")
2345             {
2346                 doNMI(asyncResp);
2347                 return;
2348             }
2349             else
2350             {
2351                 messages::actionParameterUnknown(asyncResp->res, "Reset",
2352                                                  resetType);
2353                 return;
2354             }
2355 
2356             if (hostCommand)
2357             {
2358                 crow::connections::systemBus->async_method_call(
2359                     [asyncResp, resetType](const boost::system::error_code ec) {
2360                         if (ec)
2361                         {
2362                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2363                             if (ec.value() ==
2364                                 boost::asio::error::invalid_argument)
2365                             {
2366                                 messages::actionParameterNotSupported(
2367                                     asyncResp->res, resetType, "Reset");
2368                             }
2369                             else
2370                             {
2371                                 messages::internalError(asyncResp->res);
2372                             }
2373                             return;
2374                         }
2375                         messages::success(asyncResp->res);
2376                     },
2377                     "xyz.openbmc_project.State.Host",
2378                     "/xyz/openbmc_project/state/host0",
2379                     "org.freedesktop.DBus.Properties", "Set",
2380                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2381                     std::variant<std::string>{command});
2382             }
2383             else
2384             {
2385                 crow::connections::systemBus->async_method_call(
2386                     [asyncResp, resetType](const boost::system::error_code ec) {
2387                         if (ec)
2388                         {
2389                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2390                             if (ec.value() ==
2391                                 boost::asio::error::invalid_argument)
2392                             {
2393                                 messages::actionParameterNotSupported(
2394                                     asyncResp->res, resetType, "Reset");
2395                             }
2396                             else
2397                             {
2398                                 messages::internalError(asyncResp->res);
2399                             }
2400                             return;
2401                         }
2402                         messages::success(asyncResp->res);
2403                     },
2404                     "xyz.openbmc_project.State.Chassis",
2405                     "/xyz/openbmc_project/state/chassis0",
2406                     "org.freedesktop.DBus.Properties", "Set",
2407                     "xyz.openbmc_project.State.Chassis",
2408                     "RequestedPowerTransition",
2409                     std::variant<std::string>{command});
2410             }
2411         });
2412 }
2413 
2414 /**
2415  * Systems derived class for delivering Computer Systems Schema.
2416  */
2417 inline void requestRoutesSystems(App& app)
2418 {
2419 
2420     /**
2421      * Functions triggers appropriate requests on DBus
2422      */
2423     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2424         .privileges(redfish::privileges::getComputerSystem)
2425         .methods(
2426             boost::beast::http::verb::
2427                 get)([](const crow::Request&,
2428                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2429             asyncResp->res.jsonValue["@odata.type"] =
2430                 "#ComputerSystem.v1_15_0.ComputerSystem";
2431             asyncResp->res.jsonValue["Name"] = "system";
2432             asyncResp->res.jsonValue["Id"] = "system";
2433             asyncResp->res.jsonValue["SystemType"] = "Physical";
2434             asyncResp->res.jsonValue["Description"] = "Computer System";
2435             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2436             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2437                 "Disabled";
2438             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2439                 uint64_t(0);
2440             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2441                 "Disabled";
2442             asyncResp->res.jsonValue["@odata.id"] =
2443                 "/redfish/v1/Systems/system";
2444 
2445             asyncResp->res.jsonValue["Processors"] = {
2446                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2447             asyncResp->res.jsonValue["Memory"] = {
2448                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2449             asyncResp->res.jsonValue["Storage"] = {
2450                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2451 
2452             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2453                 {"target",
2454                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2455                 {"@Redfish.ActionInfo",
2456                  "/redfish/v1/Systems/system/ResetActionInfo"}};
2457 
2458             asyncResp->res.jsonValue["LogServices"] = {
2459                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2460 
2461             asyncResp->res.jsonValue["Bios"] = {
2462                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2463 
2464             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
2465                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2466 
2467             asyncResp->res.jsonValue["Status"] = {
2468                 {"Health", "OK"},
2469                 {"State", "Enabled"},
2470             };
2471 
2472             // Fill in SerialConsole info
2473             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2474                 15;
2475             asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = {
2476                 {"ServiceEnabled", true},
2477             };
2478             // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
2479             asyncResp->res.jsonValue["SerialConsole"]["SSH"] = {
2480                 {"ServiceEnabled", true},
2481                 {"Port", 2200},
2482                 // https://github.com/openbmc/docs/blob/master/console.md
2483                 {"HotKeySequenceDisplay", "Press ~. to exit console"},
2484             };
2485 
2486 #ifdef BMCWEB_ENABLE_KVM
2487             // Fill in GraphicalConsole info
2488             asyncResp->res.jsonValue["GraphicalConsole"] = {
2489                 {"ServiceEnabled", true},
2490                 {"MaxConcurrentSessions", 4},
2491                 {"ConnectTypesSupported", {"KVMIP"}},
2492             };
2493 #endif // BMCWEB_ENABLE_KVM
2494             constexpr const std::array<const char*, 4> inventoryForSystems = {
2495                 "xyz.openbmc_project.Inventory.Item.Dimm",
2496                 "xyz.openbmc_project.Inventory.Item.Cpu",
2497                 "xyz.openbmc_project.Inventory.Item.Drive",
2498                 "xyz.openbmc_project.Inventory.Item.StorageController"};
2499 
2500             auto health = std::make_shared<HealthPopulate>(asyncResp);
2501             crow::connections::systemBus->async_method_call(
2502                 [health](const boost::system::error_code ec,
2503                          std::vector<std::string>& resp) {
2504                     if (ec)
2505                     {
2506                         // no inventory
2507                         return;
2508                     }
2509 
2510                     health->inventory = std::move(resp);
2511                 },
2512                 "xyz.openbmc_project.ObjectMapper",
2513                 "/xyz/openbmc_project/object_mapper",
2514                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2515                 int32_t(0), inventoryForSystems);
2516 
2517             health->populate();
2518 
2519             getMainChassisId(
2520                 asyncResp, [](const std::string& chassisId,
2521                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2522                     aRsp->res.jsonValue["Links"]["Chassis"] = {
2523                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2524                 });
2525 
2526             getLocationIndicatorActive(asyncResp);
2527             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2528             getIndicatorLedState(asyncResp);
2529             getComputerSystem(asyncResp, health);
2530             getHostState(asyncResp);
2531             getBootProperties(asyncResp);
2532             getBootProgress(asyncResp);
2533             getPCIeDeviceList(asyncResp, "PCIeDevices");
2534             getHostWatchdogTimer(asyncResp);
2535             getPowerRestorePolicy(asyncResp);
2536             getAutomaticRetry(asyncResp);
2537             getLastResetTime(asyncResp);
2538 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2539             getProvisioningStatus(asyncResp);
2540 #endif
2541             getTrustedModuleRequiredToBoot(asyncResp);
2542             getPowerMode(asyncResp);
2543         });
2544     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2545         .privileges(redfish::privileges::patchComputerSystem)
2546         .methods(boost::beast::http::verb::patch)(
2547             [](const crow::Request& req,
2548                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2549                 std::optional<bool> locationIndicatorActive;
2550                 std::optional<std::string> indicatorLed;
2551                 std::optional<nlohmann::json> bootProps;
2552                 std::optional<nlohmann::json> wdtTimerProps;
2553                 std::optional<std::string> assetTag;
2554                 std::optional<std::string> powerRestorePolicy;
2555                 std::optional<std::string> powerMode;
2556 
2557                 if (!json_util::readJson(
2558                         req, asyncResp->res, "IndicatorLED", indicatorLed,
2559                         "LocationIndicatorActive", locationIndicatorActive,
2560                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
2561                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
2562                         assetTag, "PowerMode", powerMode))
2563                 {
2564                     return;
2565                 }
2566 
2567                 asyncResp->res.result(boost::beast::http::status::no_content);
2568 
2569                 if (assetTag)
2570                 {
2571                     setAssetTag(asyncResp, *assetTag);
2572                 }
2573 
2574                 if (wdtTimerProps)
2575                 {
2576                     std::optional<bool> wdtEnable;
2577                     std::optional<std::string> wdtTimeOutAction;
2578 
2579                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2580                                              "FunctionEnabled", wdtEnable,
2581                                              "TimeoutAction", wdtTimeOutAction))
2582                     {
2583                         return;
2584                     }
2585                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2586                 }
2587 
2588                 if (bootProps)
2589                 {
2590                     std::optional<std::string> bootSource;
2591                     std::optional<std::string> bootEnable;
2592                     std::optional<std::string> automaticRetryConfig;
2593 
2594                     if (!json_util::readJson(
2595                             *bootProps, asyncResp->res,
2596                             "BootSourceOverrideTarget", bootSource,
2597                             "BootSourceOverrideEnabled", bootEnable,
2598                             "AutomaticRetryConfig", automaticRetryConfig))
2599                     {
2600                         return;
2601                     }
2602                     if (bootSource || bootEnable)
2603                     {
2604                         setBootSourceProperties(asyncResp,
2605                                                 std::move(bootSource),
2606                                                 std::move(bootEnable));
2607                     }
2608                     if (automaticRetryConfig)
2609                     {
2610                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
2611                     }
2612                 }
2613 
2614                 if (locationIndicatorActive)
2615                 {
2616                     setLocationIndicatorActive(asyncResp,
2617                                                *locationIndicatorActive);
2618                 }
2619 
2620                 // TODO (Gunnar): Remove IndicatorLED after enough time has
2621                 // passed
2622                 if (indicatorLed)
2623                 {
2624                     setIndicatorLedState(asyncResp, *indicatorLed);
2625                     asyncResp->res.addHeader(
2626                         boost::beast::http::field::warning,
2627                         "299 - \"IndicatorLED is deprecated. Use "
2628                         "LocationIndicatorActive instead.\"");
2629                 }
2630 
2631                 if (powerRestorePolicy)
2632                 {
2633                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
2634                 }
2635 
2636                 if (powerMode)
2637                 {
2638                     setPowerMode(asyncResp, *powerMode);
2639                 }
2640             });
2641 }
2642 
2643 /**
2644  * SystemResetActionInfo derived class for delivering Computer Systems
2645  * ResetType AllowableValues using ResetInfo schema.
2646  */
2647 inline void requestRoutesSystemResetActionInfo(App& app)
2648 {
2649 
2650     /**
2651      * Functions triggers appropriate requests on DBus
2652      */
2653     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2654         .privileges(redfish::privileges::getActionInfo)
2655         .methods(boost::beast::http::verb::get)(
2656             [](const crow::Request&,
2657                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2658                 asyncResp->res.jsonValue = {
2659                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2660                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2661                     {"Name", "Reset Action Info"},
2662                     {"Id", "ResetActionInfo"},
2663                     {"Parameters",
2664                      {{{"Name", "ResetType"},
2665                        {"Required", true},
2666                        {"DataType", "String"},
2667                        {"AllowableValues",
2668                         {"On", "ForceOff", "ForceOn", "ForceRestart",
2669                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
2670                          "Nmi"}}}}}};
2671             });
2672 }
2673 } // namespace redfish
2674