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