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