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