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