xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 735ef6d8)
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     bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
773     bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
774 
775     if (rfSource == "None")
776     {
777         return 0;
778     }
779     if (rfSource == "Pxe")
780     {
781         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
782     }
783     else if (rfSource == "Hdd")
784     {
785         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
786     }
787     else if (rfSource == "Diags")
788     {
789         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
790     }
791     else if (rfSource == "Cd")
792     {
793         bootSource =
794             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
795     }
796     else if (rfSource == "BiosSetup")
797     {
798         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
799     }
800     else if (rfSource == "Usb")
801     {
802         bootSource =
803             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
804     }
805     else
806     {
807         BMCWEB_LOG_DEBUG << "Invalid property value for "
808                             "BootSourceOverrideTarget: "
809                          << bootSource;
810         messages::propertyValueNotInList(aResp->res, rfSource,
811                                          "BootSourceTargetOverride");
812         return -1;
813     }
814     return 0;
815 }
816 
817 /**
818  * @brief Retrieves boot progress of the system
819  *
820  * @param[in] aResp  Shared pointer for generating response message.
821  *
822  * @return None.
823  */
824 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
825 {
826     crow::connections::systemBus->async_method_call(
827         [aResp](const boost::system::error_code ec,
828                 const std::variant<std::string>& bootProgress) {
829             if (ec)
830             {
831                 // BootProgress is an optional object so just do nothing if
832                 // not found
833                 return;
834             }
835 
836             const std::string* bootProgressStr =
837                 std::get_if<std::string>(&bootProgress);
838 
839             if (!bootProgressStr)
840             {
841                 // Interface implemented but property not found, return error
842                 // for that
843                 messages::internalError(aResp->res);
844                 return;
845             }
846 
847             BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
848 
849             // Now convert the D-Bus BootProgress to the appropriate Redfish
850             // enum
851             std::string rfBpLastState = "None";
852             if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress."
853                                     "ProgressStages.Unspecified")
854             {
855                 rfBpLastState = "None";
856             }
857             else if (*bootProgressStr ==
858                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
859                      "PrimaryProcInit")
860             {
861                 rfBpLastState = "PrimaryProcessorInitializationStarted";
862             }
863             else if (*bootProgressStr ==
864                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
865                      "BusInit")
866             {
867                 rfBpLastState = "BusInitializationStarted";
868             }
869             else if (*bootProgressStr ==
870                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
871                      "MemoryInit")
872             {
873                 rfBpLastState = "MemoryInitializationStarted";
874             }
875             else if (*bootProgressStr ==
876                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
877                      "SecondaryProcInit")
878             {
879                 rfBpLastState = "SecondaryProcessorInitializationStarted";
880             }
881             else if (*bootProgressStr ==
882                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
883                      "PCIInit")
884             {
885                 rfBpLastState = "PCIResourceConfigStarted";
886             }
887             else if (*bootProgressStr ==
888                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
889                      "SystemInitComplete")
890             {
891                 rfBpLastState = "SystemHardwareInitializationComplete";
892             }
893             else if (*bootProgressStr ==
894                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
895                      "OSStart")
896             {
897                 rfBpLastState = "OSBootStarted";
898             }
899             else if (*bootProgressStr ==
900                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
901                      "OSRunning")
902             {
903                 rfBpLastState = "OSRunning";
904             }
905             else
906             {
907                 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
908                                  << *bootProgressStr;
909                 // Just return the default
910             }
911 
912             aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
913         },
914         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
915         "org.freedesktop.DBus.Properties", "Get",
916         "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
917 }
918 
919 /**
920  * @brief Retrieves boot override type over DBUS and fills out the response
921  *
922  * @param[in] aResp         Shared pointer for generating response message.
923  *
924  * @return None.
925  */
926 
927 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
928 {
929     crow::connections::systemBus->async_method_call(
930         [aResp](const boost::system::error_code ec,
931                 const std::variant<std::string>& bootType) {
932             if (ec)
933             {
934                 // not an error, don't have to have the interface
935                 return;
936             }
937 
938             const std::string* bootTypeStr =
939                 std::get_if<std::string>(&bootType);
940 
941             if (!bootTypeStr)
942             {
943                 messages::internalError(aResp->res);
944                 return;
945             }
946 
947             BMCWEB_LOG_DEBUG << "Boot type: " << *bootTypeStr;
948 
949             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode@Redfish."
950                                          "AllowableValues"] = {"Legacy",
951                                                                "UEFI"};
952 
953             auto rfType = dbusToRfBootType(*bootTypeStr);
954             if (rfType.empty())
955             {
956                 messages::internalError(aResp->res);
957                 return;
958             }
959 
960             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType;
961         },
962         "xyz.openbmc_project.Settings",
963         "/xyz/openbmc_project/control/host0/boot",
964         "org.freedesktop.DBus.Properties", "Get",
965         "xyz.openbmc_project.Control.Boot.Type", "BootType");
966 }
967 
968 /**
969  * @brief Retrieves boot override mode over DBUS and fills out the response
970  *
971  * @param[in] aResp         Shared pointer for generating response message.
972  *
973  * @return None.
974  */
975 
976 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
977 {
978     crow::connections::systemBus->async_method_call(
979         [aResp](const boost::system::error_code ec,
980                 const std::variant<std::string>& bootMode) {
981             if (ec)
982             {
983                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
984                 messages::internalError(aResp->res);
985                 return;
986             }
987 
988             const std::string* bootModeStr =
989                 std::get_if<std::string>(&bootMode);
990 
991             if (!bootModeStr)
992             {
993                 messages::internalError(aResp->res);
994                 return;
995             }
996 
997             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
998 
999             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
1000                                          "AllowableValues"] = {
1001                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
1002 
1003             if (*bootModeStr !=
1004                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
1005             {
1006                 auto rfMode = dbusToRfBootMode(*bootModeStr);
1007                 if (!rfMode.empty())
1008                 {
1009                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1010                         rfMode;
1011                 }
1012             }
1013         },
1014         "xyz.openbmc_project.Settings",
1015         "/xyz/openbmc_project/control/host0/boot",
1016         "org.freedesktop.DBus.Properties", "Get",
1017         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
1018 }
1019 
1020 /**
1021  * @brief Retrieves boot override source over DBUS
1022  *
1023  * @param[in] aResp         Shared pointer for generating response message.
1024  *
1025  * @return None.
1026  */
1027 
1028 inline void
1029     getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1030 {
1031     crow::connections::systemBus->async_method_call(
1032         [aResp](const boost::system::error_code ec,
1033                 const std::variant<std::string>& bootSource) {
1034             if (ec)
1035             {
1036                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1037                 messages::internalError(aResp->res);
1038                 return;
1039             }
1040 
1041             const std::string* bootSourceStr =
1042                 std::get_if<std::string>(&bootSource);
1043 
1044             if (!bootSourceStr)
1045             {
1046                 messages::internalError(aResp->res);
1047                 return;
1048             }
1049             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
1050 
1051             auto rfSource = dbusToRfBootSource(*bootSourceStr);
1052             if (!rfSource.empty())
1053             {
1054                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1055                     rfSource;
1056             }
1057 
1058             // Get BootMode as BootSourceOverrideTarget is constructed
1059             // from both BootSource and BootMode
1060             getBootOverrideMode(aResp);
1061         },
1062         "xyz.openbmc_project.Settings",
1063         "/xyz/openbmc_project/control/host0/boot",
1064         "org.freedesktop.DBus.Properties", "Get",
1065         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
1066 }
1067 
1068 /**
1069  * @brief This functions abstracts all the logic behind getting a
1070  * "BootSourceOverrideEnabled" property from an overall boot override enable
1071  * state
1072  *
1073  * @param[in] aResp     Shared pointer for generating response message.
1074  *
1075  * @return None.
1076  */
1077 
1078 inline void
1079     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1080                               const bool bootOverrideEnableSetting)
1081 {
1082     if (!bootOverrideEnableSetting)
1083     {
1084         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled";
1085         return;
1086     }
1087 
1088     // If boot source override is enabled, we need to check 'one_time'
1089     // property to set a correct value for the "BootSourceOverrideEnabled"
1090     crow::connections::systemBus->async_method_call(
1091         [aResp](const boost::system::error_code ec,
1092                 const std::variant<bool>& oneTime) {
1093             if (ec)
1094             {
1095                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1096                 messages::internalError(aResp->res);
1097                 return;
1098             }
1099 
1100             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1101 
1102             if (!oneTimePtr)
1103             {
1104                 messages::internalError(aResp->res);
1105                 return;
1106             }
1107 
1108             bool oneTimeSetting = *oneTimePtr;
1109 
1110             if (oneTimeSetting)
1111             {
1112                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1113                     "Once";
1114             }
1115             else
1116             {
1117                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1118                     "Continuous";
1119             }
1120         },
1121         "xyz.openbmc_project.Settings",
1122         "/xyz/openbmc_project/control/host0/boot/one_time",
1123         "org.freedesktop.DBus.Properties", "Get",
1124         "xyz.openbmc_project.Object.Enable", "Enabled");
1125 }
1126 
1127 /**
1128  * @brief Retrieves boot override enable over DBUS
1129  *
1130  * @param[in] aResp     Shared pointer for generating response message.
1131  *
1132  * @return None.
1133  */
1134 
1135 inline void
1136     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1137 {
1138     crow::connections::systemBus->async_method_call(
1139         [aResp](const boost::system::error_code ec,
1140                 const std::variant<bool>& bootOverrideEnable) {
1141             if (ec)
1142             {
1143                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1144                 messages::internalError(aResp->res);
1145                 return;
1146             }
1147 
1148             const bool* bootOverrideEnablePtr =
1149                 std::get_if<bool>(&bootOverrideEnable);
1150 
1151             if (!bootOverrideEnablePtr)
1152             {
1153                 messages::internalError(aResp->res);
1154                 return;
1155             }
1156 
1157             processBootOverrideEnable(aResp, *bootOverrideEnablePtr);
1158         },
1159         "xyz.openbmc_project.Settings",
1160         "/xyz/openbmc_project/control/host0/boot",
1161         "org.freedesktop.DBus.Properties", "Get",
1162         "xyz.openbmc_project.Object.Enable", "Enabled");
1163 }
1164 
1165 /**
1166  * @brief Retrieves boot source override properties
1167  *
1168  * @param[in] aResp     Shared pointer for generating response message.
1169  *
1170  * @return None.
1171  */
1172 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1173 {
1174     BMCWEB_LOG_DEBUG << "Get boot information.";
1175 
1176     getBootOverrideSource(aResp);
1177     getBootOverrideType(aResp);
1178     getBootOverrideEnable(aResp);
1179 }
1180 
1181 /**
1182  * @brief Retrieves the Last Reset Time
1183  *
1184  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1185  * and power off. Even though this is the "system" Redfish object look at the
1186  * chassis D-Bus interface for the LastStateChangeTime since this has the
1187  * last power operation time.
1188  *
1189  * @param[in] aResp     Shared pointer for generating response message.
1190  *
1191  * @return None.
1192  */
1193 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1194 {
1195     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1196 
1197     crow::connections::systemBus->async_method_call(
1198         [aResp](const boost::system::error_code ec,
1199                 std::variant<uint64_t>& lastResetTime) {
1200             if (ec)
1201             {
1202                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1203                 return;
1204             }
1205 
1206             const uint64_t* lastResetTimePtr =
1207                 std::get_if<uint64_t>(&lastResetTime);
1208 
1209             if (!lastResetTimePtr)
1210             {
1211                 messages::internalError(aResp->res);
1212                 return;
1213             }
1214             // LastStateChangeTime is epoch time, in milliseconds
1215             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1216             time_t lastResetTimeStamp =
1217                 static_cast<time_t>(*lastResetTimePtr / 1000);
1218 
1219             // Convert to ISO 8601 standard
1220             aResp->res.jsonValue["LastResetTime"] =
1221                 crow::utility::getDateTime(lastResetTimeStamp);
1222         },
1223         "xyz.openbmc_project.State.Chassis",
1224         "/xyz/openbmc_project/state/chassis0",
1225         "org.freedesktop.DBus.Properties", "Get",
1226         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1227 }
1228 
1229 /**
1230  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1231  *
1232  * @param[in] aResp     Shared pointer for generating response message.
1233  *
1234  * @return None.
1235  */
1236 inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1237 {
1238     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1239 
1240     crow::connections::systemBus->async_method_call(
1241         [aResp](const boost::system::error_code ec,
1242                 std::variant<bool>& autoRebootEnabled) {
1243             if (ec)
1244             {
1245                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1246                 return;
1247             }
1248 
1249             const bool* autoRebootEnabledPtr =
1250                 std::get_if<bool>(&autoRebootEnabled);
1251 
1252             if (!autoRebootEnabledPtr)
1253             {
1254                 messages::internalError(aResp->res);
1255                 return;
1256             }
1257 
1258             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1259             if (*autoRebootEnabledPtr == true)
1260             {
1261                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1262                     "RetryAttempts";
1263                 // If AutomaticRetry (AutoReboot) is enabled see how many
1264                 // attempts are left
1265                 crow::connections::systemBus->async_method_call(
1266                     [aResp](const boost::system::error_code ec2,
1267                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1268                         if (ec2)
1269                         {
1270                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1271                             return;
1272                         }
1273 
1274                         const uint32_t* autoRebootAttemptsLeftPtr =
1275                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1276 
1277                         if (!autoRebootAttemptsLeftPtr)
1278                         {
1279                             messages::internalError(aResp->res);
1280                             return;
1281                         }
1282 
1283                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1284                                          << *autoRebootAttemptsLeftPtr;
1285 
1286                         aResp->res
1287                             .jsonValue["Boot"]
1288                                       ["RemainingAutomaticRetryAttempts"] =
1289                             *autoRebootAttemptsLeftPtr;
1290                     },
1291                     "xyz.openbmc_project.State.Host",
1292                     "/xyz/openbmc_project/state/host0",
1293                     "org.freedesktop.DBus.Properties", "Get",
1294                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1295                     "AttemptsLeft");
1296             }
1297             else
1298             {
1299                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1300                     "Disabled";
1301             }
1302 
1303             // Not on D-Bus. Hardcoded here:
1304             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1305             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1306 
1307             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1308             // and RetryAttempts. OpenBMC only supports Disabled and
1309             // RetryAttempts.
1310             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1311                                          "AllowableValues"] = {"Disabled",
1312                                                                "RetryAttempts"};
1313         },
1314         "xyz.openbmc_project.Settings",
1315         "/xyz/openbmc_project/control/host0/auto_reboot",
1316         "org.freedesktop.DBus.Properties", "Get",
1317         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1318 }
1319 
1320 /**
1321  * @brief Retrieves power restore policy over DBUS.
1322  *
1323  * @param[in] aResp     Shared pointer for generating response message.
1324  *
1325  * @return None.
1326  */
1327 inline void
1328     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1329 {
1330     BMCWEB_LOG_DEBUG << "Get power restore policy";
1331 
1332     crow::connections::systemBus->async_method_call(
1333         [aResp](const boost::system::error_code ec,
1334                 std::variant<std::string>& policy) {
1335             if (ec)
1336             {
1337                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1338                 return;
1339             }
1340 
1341             const boost::container::flat_map<std::string, std::string>
1342                 policyMaps = {
1343                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1344                      "AlwaysOn",
1345                      "AlwaysOn"},
1346                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1347                      "AlwaysOff",
1348                      "AlwaysOff"},
1349                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1350                      "Restore",
1351                      "LastState"}};
1352 
1353             const std::string* policyPtr = std::get_if<std::string>(&policy);
1354 
1355             if (!policyPtr)
1356             {
1357                 messages::internalError(aResp->res);
1358                 return;
1359             }
1360 
1361             auto policyMapsIt = policyMaps.find(*policyPtr);
1362             if (policyMapsIt == policyMaps.end())
1363             {
1364                 messages::internalError(aResp->res);
1365                 return;
1366             }
1367 
1368             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1369         },
1370         "xyz.openbmc_project.Settings",
1371         "/xyz/openbmc_project/control/host0/power_restore_policy",
1372         "org.freedesktop.DBus.Properties", "Get",
1373         "xyz.openbmc_project.Control.Power.RestorePolicy",
1374         "PowerRestorePolicy");
1375 }
1376 
1377 /**
1378  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1379  * TPM is required for booting the host.
1380  *
1381  * @param[in] aResp     Shared pointer for generating response message.
1382  *
1383  * @return None.
1384  */
1385 inline void getTrustedModuleRequiredToBoot(
1386     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1387 {
1388     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1389 
1390     crow::connections::systemBus->async_method_call(
1391         [aResp](
1392             const boost::system::error_code ec,
1393             std::vector<std::pair<
1394                 std::string,
1395                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1396                 subtree) {
1397             if (ec)
1398             {
1399                 BMCWEB_LOG_DEBUG
1400                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1401                 // This is an optional D-Bus object so just return if
1402                 // error occurs
1403                 return;
1404             }
1405             if (subtree.size() == 0)
1406             {
1407                 // As noted above, this is an optional interface so just return
1408                 // if there is no instance found
1409                 return;
1410             }
1411 
1412             /* When there is more than one TPMEnable object... */
1413             if (subtree.size() > 1)
1414             {
1415                 BMCWEB_LOG_DEBUG
1416                     << "DBUS response has more than 1 TPM Enable object:"
1417                     << subtree.size();
1418                 // Throw an internal Error and return
1419                 messages::internalError(aResp->res);
1420                 return;
1421             }
1422 
1423             // Make sure the Dbus response map has a service and objectPath
1424             // field
1425             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1426             {
1427                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1428                 messages::internalError(aResp->res);
1429                 return;
1430             }
1431 
1432             const std::string& path = subtree[0].first;
1433             const std::string& serv = subtree[0].second.begin()->first;
1434 
1435             // Valid TPM Enable object found, now reading the current value
1436             crow::connections::systemBus->async_method_call(
1437                 [aResp](const boost::system::error_code ec,
1438                         std::variant<bool>& tpmRequired) {
1439                     if (ec)
1440                     {
1441                         BMCWEB_LOG_DEBUG
1442                             << "D-BUS response error on TPM.Policy Get" << ec;
1443                         messages::internalError(aResp->res);
1444                         return;
1445                     }
1446 
1447                     const bool* tpmRequiredVal =
1448                         std::get_if<bool>(&tpmRequired);
1449 
1450                     if (!tpmRequiredVal)
1451                     {
1452                         messages::internalError(aResp->res);
1453                         return;
1454                     }
1455 
1456                     if (*tpmRequiredVal == true)
1457                     {
1458                         aResp->res
1459                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1460                             "Required";
1461                     }
1462                     else
1463                     {
1464                         aResp->res
1465                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1466                             "Disabled";
1467                     }
1468                 },
1469                 serv, path, "org.freedesktop.DBus.Properties", "Get",
1470                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable");
1471         },
1472         "xyz.openbmc_project.ObjectMapper",
1473         "/xyz/openbmc_project/object_mapper",
1474         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1475         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1476 }
1477 
1478 /**
1479  * @brief Sets boot properties into DBUS object(s).
1480  *
1481  * @param[in] aResp           Shared pointer for generating response message.
1482  * @param[in] bootType        The boot type to set.
1483  * @return Integer error code.
1484  */
1485 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1486                         const std::optional<std::string>& bootType)
1487 {
1488     std::string bootTypeStr;
1489 
1490     if (!bootType)
1491     {
1492         return;
1493     }
1494 
1495     // Source target specified
1496     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1497     // Figure out which DBUS interface and property to use
1498     if (*bootType == "Legacy")
1499     {
1500         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1501     }
1502     else if (*bootType == "UEFI")
1503     {
1504         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1505     }
1506     else
1507     {
1508         BMCWEB_LOG_DEBUG << "Invalid property value for "
1509                             "BootSourceOverrideMode: "
1510                          << *bootType;
1511         messages::propertyValueNotInList(aResp->res, *bootType,
1512                                          "BootSourceOverrideMode");
1513         return;
1514     }
1515 
1516     // Act on validated parameters
1517     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1518 
1519     crow::connections::systemBus->async_method_call(
1520         [aResp](const boost::system::error_code ec) {
1521             if (ec)
1522             {
1523                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1524                 if (ec.value() == boost::asio::error::host_unreachable)
1525                 {
1526                     messages::resourceNotFound(aResp->res, "Set", "BootType");
1527                     return;
1528                 }
1529                 messages::internalError(aResp->res);
1530                 return;
1531             }
1532             BMCWEB_LOG_DEBUG << "Boot type update done.";
1533         },
1534         "xyz.openbmc_project.Settings",
1535         "/xyz/openbmc_project/control/host0/boot",
1536         "org.freedesktop.DBus.Properties", "Set",
1537         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1538         std::variant<std::string>(bootTypeStr));
1539 }
1540 
1541 /**
1542  * @brief Sets boot properties into DBUS object(s).
1543  *
1544  * @param[in] aResp           Shared pointer for generating response message.
1545  * @param[in] bootType        The boot type to set.
1546  * @return Integer error code.
1547  */
1548 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1549                           const std::optional<std::string>& bootEnable)
1550 {
1551     if (!bootEnable)
1552     {
1553         return;
1554     }
1555     // Source target specified
1556     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1557 
1558     bool bootOverrideEnable = false;
1559     bool bootOverridePersistent = false;
1560     // Figure out which DBUS interface and property to use
1561     if (*bootEnable == "Disabled")
1562     {
1563         bootOverrideEnable = false;
1564     }
1565     else if (*bootEnable == "Once")
1566     {
1567         bootOverrideEnable = true;
1568         bootOverridePersistent = false;
1569     }
1570     else if (*bootEnable == "Continuous")
1571     {
1572         bootOverrideEnable = true;
1573         bootOverridePersistent = true;
1574     }
1575     else
1576     {
1577         BMCWEB_LOG_DEBUG << "Invalid property value for "
1578                             "BootSourceOverrideEnabled: "
1579                          << *bootEnable;
1580         messages::propertyValueNotInList(aResp->res, *bootEnable,
1581                                          "BootSourceOverrideEnabled");
1582         return;
1583     }
1584 
1585     // Act on validated parameters
1586     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
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 override enable update done.";
1597         },
1598         "xyz.openbmc_project.Settings",
1599         "/xyz/openbmc_project/control/host0/boot",
1600         "org.freedesktop.DBus.Properties", "Set",
1601         "xyz.openbmc_project.Object.Enable", "Enabled",
1602         std::variant<bool>(bootOverrideEnable));
1603 
1604     if (!bootOverrideEnable)
1605     {
1606         return;
1607     }
1608 
1609     // In case boot override is enabled we need to set correct value for the
1610     // 'one_time' enable DBus interface
1611     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1612                      << bootOverridePersistent;
1613 
1614     crow::connections::systemBus->async_method_call(
1615         [aResp](const boost::system::error_code ec) {
1616             if (ec)
1617             {
1618                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1619                 messages::internalError(aResp->res);
1620                 return;
1621             }
1622             BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1623         },
1624         "xyz.openbmc_project.Settings",
1625         "/xyz/openbmc_project/control/host0/boot/one_time",
1626         "org.freedesktop.DBus.Properties", "Set",
1627         "xyz.openbmc_project.Object.Enable", "Enabled",
1628         std::variant<bool>(!bootOverridePersistent));
1629 }
1630 
1631 /**
1632  * @brief Sets boot properties into DBUS object(s).
1633  *
1634  * @param[in] aResp           Shared pointer for generating response message.
1635  * @param[in] bootSource      The boot source to set.
1636  *
1637  * @return Integer error code.
1638  */
1639 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1640                                 const std::optional<std::string>& bootSource)
1641 {
1642     std::string bootSourceStr;
1643     std::string bootModeStr;
1644 
1645     if (!bootSource)
1646     {
1647         return;
1648     }
1649 
1650     // Source target specified
1651     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1652     // Figure out which DBUS interface and property to use
1653     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr))
1654     {
1655         BMCWEB_LOG_DEBUG
1656             << "Invalid property value for BootSourceOverrideTarget: "
1657             << *bootSource;
1658         messages::propertyValueNotInList(aResp->res, *bootSource,
1659                                          "BootSourceTargetOverride");
1660         return;
1661     }
1662 
1663     // Act on validated parameters
1664     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1665     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1666 
1667     crow::connections::systemBus->async_method_call(
1668         [aResp](const boost::system::error_code ec) {
1669             if (ec)
1670             {
1671                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1672                 messages::internalError(aResp->res);
1673                 return;
1674             }
1675             BMCWEB_LOG_DEBUG << "Boot source update done.";
1676         },
1677         "xyz.openbmc_project.Settings",
1678         "/xyz/openbmc_project/control/host0/boot",
1679         "org.freedesktop.DBus.Properties", "Set",
1680         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1681         std::variant<std::string>(bootSourceStr));
1682 
1683     crow::connections::systemBus->async_method_call(
1684         [aResp](const boost::system::error_code ec) {
1685             if (ec)
1686             {
1687                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1688                 messages::internalError(aResp->res);
1689                 return;
1690             }
1691             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1692         },
1693         "xyz.openbmc_project.Settings",
1694         "/xyz/openbmc_project/control/host0/boot",
1695         "org.freedesktop.DBus.Properties", "Set",
1696         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1697         std::variant<std::string>(bootModeStr));
1698 }
1699 
1700 /**
1701  * @brief Sets Boot source override properties.
1702  *
1703  * @param[in] aResp      Shared pointer for generating response message.
1704  * @param[in] bootSource The boot source from incoming RF request.
1705  * @param[in] bootType   The boot type from incoming RF request.
1706  * @param[in] bootEnable The boot override enable from incoming RF request.
1707  *
1708  * @return Integer error code.
1709  */
1710 
1711 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1712                               const std::optional<std::string>& bootSource,
1713                               const std::optional<std::string>& bootType,
1714                               const std::optional<std::string>& bootEnable)
1715 {
1716     BMCWEB_LOG_DEBUG << "Set boot information.";
1717 
1718     setBootModeOrSource(aResp, bootSource);
1719     setBootType(aResp, bootType);
1720     setBootEnable(aResp, bootEnable);
1721 }
1722 
1723 /**
1724  * @brief Sets AssetTag
1725  *
1726  * @param[in] aResp   Shared pointer for generating response message.
1727  * @param[in] assetTag  "AssetTag" from request.
1728  *
1729  * @return None.
1730  */
1731 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1732                         const std::string& assetTag)
1733 {
1734     crow::connections::systemBus->async_method_call(
1735         [aResp, assetTag](
1736             const boost::system::error_code ec,
1737             const std::vector<std::pair<
1738                 std::string,
1739                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1740                 subtree) {
1741             if (ec)
1742             {
1743                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1744                 messages::internalError(aResp->res);
1745                 return;
1746             }
1747             if (subtree.size() == 0)
1748             {
1749                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1750                 messages::internalError(aResp->res);
1751                 return;
1752             }
1753             // Assume only 1 system D-Bus object
1754             // Throw an error if there is more than 1
1755             if (subtree.size() > 1)
1756             {
1757                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1758                 messages::internalError(aResp->res);
1759                 return;
1760             }
1761             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1762             {
1763                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1764                 messages::internalError(aResp->res);
1765                 return;
1766             }
1767 
1768             const std::string& path = subtree[0].first;
1769             const std::string& service = subtree[0].second.begin()->first;
1770 
1771             if (service.empty())
1772             {
1773                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1774                 messages::internalError(aResp->res);
1775                 return;
1776             }
1777 
1778             crow::connections::systemBus->async_method_call(
1779                 [aResp](const boost::system::error_code ec2) {
1780                     if (ec2)
1781                     {
1782                         BMCWEB_LOG_DEBUG
1783                             << "D-Bus response error on AssetTag Set " << ec2;
1784                         messages::internalError(aResp->res);
1785                         return;
1786                     }
1787                 },
1788                 service, path, "org.freedesktop.DBus.Properties", "Set",
1789                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1790                 std::variant<std::string>(assetTag));
1791         },
1792         "xyz.openbmc_project.ObjectMapper",
1793         "/xyz/openbmc_project/object_mapper",
1794         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1795         "/xyz/openbmc_project/inventory", int32_t(0),
1796         std::array<const char*, 1>{
1797             "xyz.openbmc_project.Inventory.Item.System"});
1798 }
1799 
1800 /**
1801  * @brief Sets automaticRetry (Auto Reboot)
1802  *
1803  * @param[in] aResp   Shared pointer for generating response message.
1804  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1805  *
1806  * @return None.
1807  */
1808 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1809                               const std::string& automaticRetryConfig)
1810 {
1811     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1812 
1813     // OpenBMC only supports "Disabled" and "RetryAttempts".
1814     bool autoRebootEnabled;
1815 
1816     if (automaticRetryConfig == "Disabled")
1817     {
1818         autoRebootEnabled = false;
1819     }
1820     else if (automaticRetryConfig == "RetryAttempts")
1821     {
1822         autoRebootEnabled = true;
1823     }
1824     else
1825     {
1826         BMCWEB_LOG_DEBUG << "Invalid property value for "
1827                             "AutomaticRetryConfig: "
1828                          << automaticRetryConfig;
1829         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1830                                          "AutomaticRetryConfig");
1831         return;
1832     }
1833 
1834     crow::connections::systemBus->async_method_call(
1835         [aResp](const boost::system::error_code ec) {
1836             if (ec)
1837             {
1838                 messages::internalError(aResp->res);
1839                 return;
1840             }
1841         },
1842         "xyz.openbmc_project.Settings",
1843         "/xyz/openbmc_project/control/host0/auto_reboot",
1844         "org.freedesktop.DBus.Properties", "Set",
1845         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1846         std::variant<bool>(autoRebootEnabled));
1847 }
1848 
1849 /**
1850  * @brief Sets power restore policy properties.
1851  *
1852  * @param[in] aResp   Shared pointer for generating response message.
1853  * @param[in] policy  power restore policy properties from request.
1854  *
1855  * @return None.
1856  */
1857 inline void
1858     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1859                           const std::string& policy)
1860 {
1861     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1862 
1863     const boost::container::flat_map<std::string, std::string> policyMaps = {
1864         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1865                      "AlwaysOn"},
1866         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1867                       "AlwaysOff"},
1868         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1869                       "Restore"}};
1870 
1871     std::string powerRestorPolicy;
1872 
1873     auto policyMapsIt = policyMaps.find(policy);
1874     if (policyMapsIt == policyMaps.end())
1875     {
1876         messages::propertyValueNotInList(aResp->res, policy,
1877                                          "PowerRestorePolicy");
1878         return;
1879     }
1880 
1881     powerRestorPolicy = policyMapsIt->second;
1882 
1883     crow::connections::systemBus->async_method_call(
1884         [aResp](const boost::system::error_code ec) {
1885             if (ec)
1886             {
1887                 messages::internalError(aResp->res);
1888                 return;
1889             }
1890         },
1891         "xyz.openbmc_project.Settings",
1892         "/xyz/openbmc_project/control/host0/power_restore_policy",
1893         "org.freedesktop.DBus.Properties", "Set",
1894         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1895         std::variant<std::string>(powerRestorPolicy));
1896 }
1897 
1898 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1899 /**
1900  * @brief Retrieves provisioning status
1901  *
1902  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1903  *
1904  * @return None.
1905  */
1906 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1907 {
1908     BMCWEB_LOG_DEBUG << "Get OEM information.";
1909     crow::connections::systemBus->async_method_call(
1910         [aResp](const boost::system::error_code ec,
1911                 const std::vector<std::pair<std::string, VariantType>>&
1912                     propertiesList) {
1913             nlohmann::json& oemPFR =
1914                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1915             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1916                 "#OemComputerSystem.OpenBmc";
1917             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1918 
1919             if (ec)
1920             {
1921                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1922                 // not an error, don't have to have the interface
1923                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1924                 return;
1925             }
1926 
1927             const bool* provState = nullptr;
1928             const bool* lockState = nullptr;
1929             for (const std::pair<std::string, VariantType>& property :
1930                  propertiesList)
1931             {
1932                 if (property.first == "UfmProvisioned")
1933                 {
1934                     provState = std::get_if<bool>(&property.second);
1935                 }
1936                 else if (property.first == "UfmLocked")
1937                 {
1938                     lockState = std::get_if<bool>(&property.second);
1939                 }
1940             }
1941 
1942             if ((provState == nullptr) || (lockState == nullptr))
1943             {
1944                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1945                 messages::internalError(aResp->res);
1946                 return;
1947             }
1948 
1949             if (*provState == true)
1950             {
1951                 if (*lockState == true)
1952                 {
1953                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1954                 }
1955                 else
1956                 {
1957                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1958                 }
1959             }
1960             else
1961             {
1962                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1963             }
1964         },
1965         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1966         "org.freedesktop.DBus.Properties", "GetAll",
1967         "xyz.openbmc_project.PFR.Attributes");
1968 }
1969 #endif
1970 
1971 /**
1972  * @brief Translate the PowerMode to a response message.
1973  *
1974  * @param[in] aResp  Shared pointer for generating response message.
1975  * @param[in] modeValue  PowerMode value to be translated
1976  *
1977  * @return None.
1978  */
1979 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1980                                const std::string& modeValue)
1981 {
1982     std::string modeString;
1983 
1984     if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1985                      "PowerMode.Static")
1986     {
1987         aResp->res.jsonValue["PowerMode"] = "Static";
1988     }
1989     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1990                           "PowerMode.MaximumPerformance")
1991     {
1992         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
1993     }
1994     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
1995                           "PowerMode.PowerSaving")
1996     {
1997         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
1998     }
1999     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
2000                           "PowerMode.OEM")
2001     {
2002         aResp->res.jsonValue["PowerMode"] = "OEM";
2003     }
2004     else
2005     {
2006         // Any other values would be invalid
2007         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
2008         messages::internalError(aResp->res);
2009     }
2010 }
2011 
2012 /**
2013  * @brief Retrieves system power mode
2014  *
2015  * @param[in] aResp  Shared pointer for generating response message.
2016  *
2017  * @return None.
2018  */
2019 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2020 {
2021     BMCWEB_LOG_DEBUG << "Get power mode.";
2022 
2023     // Get Power Mode object path:
2024     crow::connections::systemBus->async_method_call(
2025         [aResp](
2026             const boost::system::error_code ec,
2027             const std::vector<std::pair<
2028                 std::string,
2029                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2030                 subtree) {
2031             if (ec)
2032             {
2033                 BMCWEB_LOG_DEBUG
2034                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2035                 // This is an optional D-Bus object so just return if
2036                 // error occurs
2037                 return;
2038             }
2039             if (subtree.empty())
2040             {
2041                 // As noted above, this is an optional interface so just return
2042                 // if there is no instance found
2043                 return;
2044             }
2045             if (subtree.size() > 1)
2046             {
2047                 // More then one PowerMode object is not supported and is an
2048                 // error
2049                 BMCWEB_LOG_DEBUG
2050                     << "Found more than 1 system D-Bus Power.Mode objects: "
2051                     << subtree.size();
2052                 messages::internalError(aResp->res);
2053                 return;
2054             }
2055             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2056             {
2057                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2058                 messages::internalError(aResp->res);
2059                 return;
2060             }
2061             const std::string& path = subtree[0].first;
2062             const std::string& service = subtree[0].second.begin()->first;
2063             if (service.empty())
2064             {
2065                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2066                 messages::internalError(aResp->res);
2067                 return;
2068             }
2069             // Valid Power Mode object found, now read the current value
2070             crow::connections::systemBus->async_method_call(
2071                 [aResp](const boost::system::error_code ec,
2072                         const std::variant<std::string>& pmode) {
2073                     if (ec)
2074                     {
2075                         BMCWEB_LOG_DEBUG
2076                             << "DBUS response error on PowerMode Get: " << ec;
2077                         messages::internalError(aResp->res);
2078                         return;
2079                     }
2080 
2081                     const std::string* s = std::get_if<std::string>(&pmode);
2082                     if (s == nullptr)
2083                     {
2084                         BMCWEB_LOG_DEBUG << "Unable to get PowerMode value";
2085                         messages::internalError(aResp->res);
2086                         return;
2087                     }
2088 
2089                     aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] =
2090                         {"Static", "MaximumPerformance", "PowerSaving"};
2091 
2092                     BMCWEB_LOG_DEBUG << "Current power mode: " << *s;
2093                     translatePowerMode(aResp, *s);
2094                 },
2095                 service, path, "org.freedesktop.DBus.Properties", "Get",
2096                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode");
2097         },
2098         "xyz.openbmc_project.ObjectMapper",
2099         "/xyz/openbmc_project/object_mapper",
2100         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2101         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2102 }
2103 
2104 /**
2105  * @brief Validate the specified mode is valid and return the PowerMode
2106  * name associated with that string
2107  *
2108  * @param[in] aResp   Shared pointer for generating response message.
2109  * @param[in] modeString  String representing the desired PowerMode
2110  *
2111  * @return PowerMode value or empty string if mode is not valid
2112  */
2113 inline std::string
2114     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2115                       const std::string& modeString)
2116 {
2117     std::string mode;
2118 
2119     if (modeString == "Static")
2120     {
2121         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2122     }
2123     else if (modeString == "MaximumPerformance")
2124     {
2125         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode."
2126                "MaximumPerformance";
2127     }
2128     else if (modeString == "PowerSaving")
2129     {
2130         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2131     }
2132     else
2133     {
2134         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2135     }
2136     return mode;
2137 }
2138 
2139 /**
2140  * @brief Sets system power mode.
2141  *
2142  * @param[in] aResp   Shared pointer for generating response message.
2143  * @param[in] pmode   System power mode from request.
2144  *
2145  * @return None.
2146  */
2147 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2148                          const std::string& pmode)
2149 {
2150     BMCWEB_LOG_DEBUG << "Set power mode.";
2151 
2152     std::string powerMode = validatePowerMode(aResp, pmode);
2153     if (powerMode.empty())
2154     {
2155         return;
2156     }
2157 
2158     // Get Power Mode object path:
2159     crow::connections::systemBus->async_method_call(
2160         [aResp, powerMode](
2161             const boost::system::error_code ec,
2162             const std::vector<std::pair<
2163                 std::string,
2164                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2165                 subtree) {
2166             if (ec)
2167             {
2168                 BMCWEB_LOG_DEBUG
2169                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2170                 // This is an optional D-Bus object, but user attempted to patch
2171                 messages::internalError(aResp->res);
2172                 return;
2173             }
2174             if (subtree.empty())
2175             {
2176                 // This is an optional D-Bus object, but user attempted to patch
2177                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2178                                            "PowerMode");
2179                 return;
2180             }
2181             if (subtree.size() > 1)
2182             {
2183                 // More then one PowerMode object is not supported and is an
2184                 // error
2185                 BMCWEB_LOG_DEBUG
2186                     << "Found more than 1 system D-Bus Power.Mode objects: "
2187                     << subtree.size();
2188                 messages::internalError(aResp->res);
2189                 return;
2190             }
2191             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2192             {
2193                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2194                 messages::internalError(aResp->res);
2195                 return;
2196             }
2197             const std::string& path = subtree[0].first;
2198             const std::string& service = subtree[0].second.begin()->first;
2199             if (service.empty())
2200             {
2201                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2202                 messages::internalError(aResp->res);
2203                 return;
2204             }
2205 
2206             BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2207                              << path;
2208 
2209             // Set the Power Mode property
2210             crow::connections::systemBus->async_method_call(
2211                 [aResp](const boost::system::error_code ec) {
2212                     if (ec)
2213                     {
2214                         messages::internalError(aResp->res);
2215                         return;
2216                     }
2217                 },
2218                 service, path, "org.freedesktop.DBus.Properties", "Set",
2219                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2220                 std::variant<std::string>(powerMode));
2221         },
2222         "xyz.openbmc_project.ObjectMapper",
2223         "/xyz/openbmc_project/object_mapper",
2224         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2225         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2226 }
2227 
2228 /**
2229  * @brief Translates watchdog timeout action DBUS property value to redfish.
2230  *
2231  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2232  *
2233  * @return Returns as a string, the timeout action in Redfish terms. If
2234  * translation cannot be done, returns an empty string.
2235  */
2236 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2237 {
2238     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2239     {
2240         return "None";
2241     }
2242     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2243     {
2244         return "ResetSystem";
2245     }
2246     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2247     {
2248         return "PowerDown";
2249     }
2250     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2251     {
2252         return "PowerCycle";
2253     }
2254 
2255     return "";
2256 }
2257 
2258 /**
2259  *@brief Translates timeout action from Redfish to DBUS property value.
2260  *
2261  *@param[in] rfAction The timeout action in Redfish.
2262  *
2263  *@return Returns as a string, the time_out action as expected by DBUS.
2264  *If translation cannot be done, returns an empty string.
2265  */
2266 
2267 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2268 {
2269     if (rfAction == "None")
2270     {
2271         return "xyz.openbmc_project.State.Watchdog.Action.None";
2272     }
2273     if (rfAction == "PowerCycle")
2274     {
2275         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2276     }
2277     if (rfAction == "PowerDown")
2278     {
2279         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2280     }
2281     if (rfAction == "ResetSystem")
2282     {
2283         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2284     }
2285 
2286     return "";
2287 }
2288 
2289 /**
2290  * @brief Retrieves host watchdog timer properties over DBUS
2291  *
2292  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2293  *
2294  * @return None.
2295  */
2296 inline void
2297     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2298 {
2299     BMCWEB_LOG_DEBUG << "Get host watchodg";
2300     crow::connections::systemBus->async_method_call(
2301         [aResp](const boost::system::error_code ec,
2302                 PropertiesType& properties) {
2303             if (ec)
2304             {
2305                 // watchdog service is stopped
2306                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2307                 return;
2308             }
2309 
2310             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2311 
2312             nlohmann::json& hostWatchdogTimer =
2313                 aResp->res.jsonValue["HostWatchdogTimer"];
2314 
2315             // watchdog service is running/enabled
2316             hostWatchdogTimer["Status"]["State"] = "Enabled";
2317 
2318             for (const auto& property : properties)
2319             {
2320                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
2321                 if (property.first == "Enabled")
2322                 {
2323                     const bool* state = std::get_if<bool>(&property.second);
2324 
2325                     if (!state)
2326                     {
2327                         messages::internalError(aResp->res);
2328                         return;
2329                     }
2330 
2331                     hostWatchdogTimer["FunctionEnabled"] = *state;
2332                 }
2333                 else if (property.first == "ExpireAction")
2334                 {
2335                     const std::string* s =
2336                         std::get_if<std::string>(&property.second);
2337                     if (!s)
2338                     {
2339                         messages::internalError(aResp->res);
2340                         return;
2341                     }
2342 
2343                     std::string action = dbusToRfWatchdogAction(*s);
2344                     if (action.empty())
2345                     {
2346                         messages::internalError(aResp->res);
2347                         return;
2348                     }
2349                     hostWatchdogTimer["TimeoutAction"] = action;
2350                 }
2351             }
2352         },
2353         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2354         "org.freedesktop.DBus.Properties", "GetAll",
2355         "xyz.openbmc_project.State.Watchdog");
2356 }
2357 
2358 /**
2359  * @brief Sets Host WatchDog Timer properties.
2360  *
2361  * @param[in] aResp      Shared pointer for generating response message.
2362  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2363  *                       RF request.
2364  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2365  *
2366  * @return None.
2367  */
2368 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2369                              const std::optional<bool> wdtEnable,
2370                              const std::optional<std::string>& wdtTimeOutAction)
2371 {
2372     BMCWEB_LOG_DEBUG << "Set host watchdog";
2373 
2374     if (wdtTimeOutAction)
2375     {
2376         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2377         // check if TimeOut Action is Valid
2378         if (wdtTimeOutActStr.empty())
2379         {
2380             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2381                              << *wdtTimeOutAction;
2382             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2383                                              "TimeoutAction");
2384             return;
2385         }
2386 
2387         crow::connections::systemBus->async_method_call(
2388             [aResp](const boost::system::error_code ec) {
2389                 if (ec)
2390                 {
2391                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2392                     messages::internalError(aResp->res);
2393                     return;
2394                 }
2395             },
2396             "xyz.openbmc_project.Watchdog",
2397             "/xyz/openbmc_project/watchdog/host0",
2398             "org.freedesktop.DBus.Properties", "Set",
2399             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2400             std::variant<std::string>(wdtTimeOutActStr));
2401     }
2402 
2403     if (wdtEnable)
2404     {
2405         crow::connections::systemBus->async_method_call(
2406             [aResp](const boost::system::error_code ec) {
2407                 if (ec)
2408                 {
2409                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2410                     messages::internalError(aResp->res);
2411                     return;
2412                 }
2413             },
2414             "xyz.openbmc_project.Watchdog",
2415             "/xyz/openbmc_project/watchdog/host0",
2416             "org.freedesktop.DBus.Properties", "Set",
2417             "xyz.openbmc_project.State.Watchdog", "Enabled",
2418             std::variant<bool>(*wdtEnable));
2419     }
2420 }
2421 
2422 /**
2423  * SystemsCollection derived class for delivering ComputerSystems Collection
2424  * Schema
2425  */
2426 inline void requestRoutesSystemsCollection(App& app)
2427 {
2428     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2429         .privileges(redfish::privileges::getComputerSystemCollection)
2430         .methods(boost::beast::http::verb::get)(
2431             [](const crow::Request& /*req*/,
2432                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2433                 asyncResp->res.jsonValue["@odata.type"] =
2434                     "#ComputerSystemCollection.ComputerSystemCollection";
2435                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2436                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2437 
2438                 crow::connections::systemBus->async_method_call(
2439                     [asyncResp](const boost::system::error_code ec,
2440                                 const std::variant<std::string>& /*hostName*/) {
2441                         nlohmann::json& ifaceArray =
2442                             asyncResp->res.jsonValue["Members"];
2443                         ifaceArray = nlohmann::json::array();
2444                         auto& count =
2445                             asyncResp->res.jsonValue["Members@odata.count"];
2446                         ifaceArray.push_back(
2447                             {{"@odata.id", "/redfish/v1/Systems/system"}});
2448                         count = ifaceArray.size();
2449                         if (!ec)
2450                         {
2451                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
2452                             ifaceArray.push_back(
2453                                 {{"@odata.id",
2454                                   "/redfish/v1/Systems/hypervisor"}});
2455                             count = ifaceArray.size();
2456                         }
2457                     },
2458                     "xyz.openbmc_project.Settings",
2459                     "/xyz/openbmc_project/network/hypervisor",
2460                     "org.freedesktop.DBus.Properties", "Get",
2461                     "xyz.openbmc_project.Network.SystemConfiguration",
2462                     "HostName");
2463             });
2464 }
2465 
2466 /**
2467  * Function transceives data with dbus directly.
2468  */
2469 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2470 {
2471     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2472     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2473     constexpr char const* interfaceName =
2474         "xyz.openbmc_project.Control.Host.NMI";
2475     constexpr char const* method = "NMI";
2476 
2477     crow::connections::systemBus->async_method_call(
2478         [asyncResp](const boost::system::error_code ec) {
2479             if (ec)
2480             {
2481                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2482                 messages::internalError(asyncResp->res);
2483                 return;
2484             }
2485             messages::success(asyncResp->res);
2486         },
2487         serviceName, objectPath, interfaceName, method);
2488 }
2489 
2490 /**
2491  * SystemActionsReset class supports handle POST method for Reset action.
2492  * The class retrieves and sends data directly to D-Bus.
2493  */
2494 inline void requestRoutesSystemActionsReset(App& app)
2495 {
2496     /**
2497      * Function handles POST method request.
2498      * Analyzes POST body message before sends Reset request data to D-Bus.
2499      */
2500     BMCWEB_ROUTE(app,
2501                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2502         .privileges(redfish::privileges::postComputerSystem)
2503         .methods(
2504             boost::beast::http::verb::
2505                 post)([](const crow::Request& req,
2506                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2507             std::string resetType;
2508             if (!json_util::readJson(req, asyncResp->res, "ResetType",
2509                                      resetType))
2510             {
2511                 return;
2512             }
2513 
2514             // Get the command and host vs. chassis
2515             std::string command;
2516             bool hostCommand;
2517             if ((resetType == "On") || (resetType == "ForceOn"))
2518             {
2519                 command = "xyz.openbmc_project.State.Host.Transition.On";
2520                 hostCommand = true;
2521             }
2522             else if (resetType == "ForceOff")
2523             {
2524                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2525                 hostCommand = false;
2526             }
2527             else if (resetType == "ForceRestart")
2528             {
2529                 command =
2530                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2531                 hostCommand = true;
2532             }
2533             else if (resetType == "GracefulShutdown")
2534             {
2535                 command = "xyz.openbmc_project.State.Host.Transition.Off";
2536                 hostCommand = true;
2537             }
2538             else if (resetType == "GracefulRestart")
2539             {
2540                 command = "xyz.openbmc_project.State.Host.Transition."
2541                           "GracefulWarmReboot";
2542                 hostCommand = true;
2543             }
2544             else if (resetType == "PowerCycle")
2545             {
2546                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2547                 hostCommand = true;
2548             }
2549             else if (resetType == "Nmi")
2550             {
2551                 doNMI(asyncResp);
2552                 return;
2553             }
2554             else
2555             {
2556                 messages::actionParameterUnknown(asyncResp->res, "Reset",
2557                                                  resetType);
2558                 return;
2559             }
2560 
2561             if (hostCommand)
2562             {
2563                 crow::connections::systemBus->async_method_call(
2564                     [asyncResp, resetType](const boost::system::error_code ec) {
2565                         if (ec)
2566                         {
2567                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2568                             if (ec.value() ==
2569                                 boost::asio::error::invalid_argument)
2570                             {
2571                                 messages::actionParameterNotSupported(
2572                                     asyncResp->res, resetType, "Reset");
2573                             }
2574                             else
2575                             {
2576                                 messages::internalError(asyncResp->res);
2577                             }
2578                             return;
2579                         }
2580                         messages::success(asyncResp->res);
2581                     },
2582                     "xyz.openbmc_project.State.Host",
2583                     "/xyz/openbmc_project/state/host0",
2584                     "org.freedesktop.DBus.Properties", "Set",
2585                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2586                     std::variant<std::string>{command});
2587             }
2588             else
2589             {
2590                 crow::connections::systemBus->async_method_call(
2591                     [asyncResp, resetType](const boost::system::error_code ec) {
2592                         if (ec)
2593                         {
2594                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2595                             if (ec.value() ==
2596                                 boost::asio::error::invalid_argument)
2597                             {
2598                                 messages::actionParameterNotSupported(
2599                                     asyncResp->res, resetType, "Reset");
2600                             }
2601                             else
2602                             {
2603                                 messages::internalError(asyncResp->res);
2604                             }
2605                             return;
2606                         }
2607                         messages::success(asyncResp->res);
2608                     },
2609                     "xyz.openbmc_project.State.Chassis",
2610                     "/xyz/openbmc_project/state/chassis0",
2611                     "org.freedesktop.DBus.Properties", "Set",
2612                     "xyz.openbmc_project.State.Chassis",
2613                     "RequestedPowerTransition",
2614                     std::variant<std::string>{command});
2615             }
2616         });
2617 }
2618 
2619 /**
2620  * Systems derived class for delivering Computer Systems Schema.
2621  */
2622 inline void requestRoutesSystems(App& app)
2623 {
2624 
2625     /**
2626      * Functions triggers appropriate requests on DBus
2627      */
2628     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2629         .privileges(redfish::privileges::getComputerSystem)
2630         .methods(
2631             boost::beast::http::verb::
2632                 get)([](const crow::Request&,
2633                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2634             asyncResp->res.jsonValue["@odata.type"] =
2635                 "#ComputerSystem.v1_15_0.ComputerSystem";
2636             asyncResp->res.jsonValue["Name"] = "system";
2637             asyncResp->res.jsonValue["Id"] = "system";
2638             asyncResp->res.jsonValue["SystemType"] = "Physical";
2639             asyncResp->res.jsonValue["Description"] = "Computer System";
2640             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2641             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2642                 "Disabled";
2643             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2644                 uint64_t(0);
2645             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2646                 "Disabled";
2647             asyncResp->res.jsonValue["@odata.id"] =
2648                 "/redfish/v1/Systems/system";
2649 
2650             asyncResp->res.jsonValue["Processors"] = {
2651                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2652             asyncResp->res.jsonValue["Memory"] = {
2653                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2654             asyncResp->res.jsonValue["Storage"] = {
2655                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2656 
2657             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2658                 {"target",
2659                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2660                 {"@Redfish.ActionInfo",
2661                  "/redfish/v1/Systems/system/ResetActionInfo"}};
2662 
2663             asyncResp->res.jsonValue["LogServices"] = {
2664                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2665 
2666             asyncResp->res.jsonValue["Bios"] = {
2667                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2668 
2669             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
2670                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2671 
2672             asyncResp->res.jsonValue["Status"] = {
2673                 {"Health", "OK"},
2674                 {"State", "Enabled"},
2675             };
2676 
2677             // Fill in SerialConsole info
2678             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2679                 15;
2680             asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = {
2681                 {"ServiceEnabled", true},
2682             };
2683             // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
2684             asyncResp->res.jsonValue["SerialConsole"]["SSH"] = {
2685                 {"ServiceEnabled", true},
2686                 {"Port", 2200},
2687                 // https://github.com/openbmc/docs/blob/master/console.md
2688                 {"HotKeySequenceDisplay", "Press ~. to exit console"},
2689             };
2690 
2691 #ifdef BMCWEB_ENABLE_KVM
2692             // Fill in GraphicalConsole info
2693             asyncResp->res.jsonValue["GraphicalConsole"] = {
2694                 {"ServiceEnabled", true},
2695                 {"MaxConcurrentSessions", 4},
2696                 {"ConnectTypesSupported", {"KVMIP"}},
2697             };
2698 #endif // BMCWEB_ENABLE_KVM
2699             constexpr const std::array<const char*, 4> inventoryForSystems = {
2700                 "xyz.openbmc_project.Inventory.Item.Dimm",
2701                 "xyz.openbmc_project.Inventory.Item.Cpu",
2702                 "xyz.openbmc_project.Inventory.Item.Drive",
2703                 "xyz.openbmc_project.Inventory.Item.StorageController"};
2704 
2705             auto health = std::make_shared<HealthPopulate>(asyncResp);
2706             crow::connections::systemBus->async_method_call(
2707                 [health](const boost::system::error_code ec,
2708                          std::vector<std::string>& resp) {
2709                     if (ec)
2710                     {
2711                         // no inventory
2712                         return;
2713                     }
2714 
2715                     health->inventory = std::move(resp);
2716                 },
2717                 "xyz.openbmc_project.ObjectMapper",
2718                 "/xyz/openbmc_project/object_mapper",
2719                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2720                 int32_t(0), inventoryForSystems);
2721 
2722             health->populate();
2723 
2724             getMainChassisId(
2725                 asyncResp, [](const std::string& chassisId,
2726                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2727                     aRsp->res.jsonValue["Links"]["Chassis"] = {
2728                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2729                 });
2730 
2731             getLocationIndicatorActive(asyncResp);
2732             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2733             getIndicatorLedState(asyncResp);
2734             getComputerSystem(asyncResp, health);
2735             getHostState(asyncResp);
2736             getBootProperties(asyncResp);
2737             getBootProgress(asyncResp);
2738             getPCIeDeviceList(asyncResp, "PCIeDevices");
2739             getHostWatchdogTimer(asyncResp);
2740             getPowerRestorePolicy(asyncResp);
2741             getAutomaticRetry(asyncResp);
2742             getLastResetTime(asyncResp);
2743 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2744             getProvisioningStatus(asyncResp);
2745 #endif
2746             getTrustedModuleRequiredToBoot(asyncResp);
2747             getPowerMode(asyncResp);
2748         });
2749     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2750         .privileges(redfish::privileges::patchComputerSystem)
2751         .methods(boost::beast::http::verb::patch)(
2752             [](const crow::Request& req,
2753                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2754                 std::optional<bool> locationIndicatorActive;
2755                 std::optional<std::string> indicatorLed;
2756                 std::optional<nlohmann::json> bootProps;
2757                 std::optional<nlohmann::json> wdtTimerProps;
2758                 std::optional<std::string> assetTag;
2759                 std::optional<std::string> powerRestorePolicy;
2760                 std::optional<std::string> powerMode;
2761 
2762                 if (!json_util::readJson(
2763                         req, asyncResp->res, "IndicatorLED", indicatorLed,
2764                         "LocationIndicatorActive", locationIndicatorActive,
2765                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
2766                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
2767                         assetTag, "PowerMode", powerMode))
2768                 {
2769                     return;
2770                 }
2771 
2772                 asyncResp->res.result(boost::beast::http::status::no_content);
2773 
2774                 if (assetTag)
2775                 {
2776                     setAssetTag(asyncResp, *assetTag);
2777                 }
2778 
2779                 if (wdtTimerProps)
2780                 {
2781                     std::optional<bool> wdtEnable;
2782                     std::optional<std::string> wdtTimeOutAction;
2783 
2784                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2785                                              "FunctionEnabled", wdtEnable,
2786                                              "TimeoutAction", wdtTimeOutAction))
2787                     {
2788                         return;
2789                     }
2790                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2791                 }
2792 
2793                 if (bootProps)
2794                 {
2795                     std::optional<std::string> bootSource;
2796                     std::optional<std::string> bootType;
2797                     std::optional<std::string> bootEnable;
2798                     std::optional<std::string> automaticRetryConfig;
2799 
2800                     if (!json_util::readJson(
2801                             *bootProps, asyncResp->res,
2802                             "BootSourceOverrideTarget", bootSource,
2803                             "BootSourceOverrideMode", bootType,
2804                             "BootSourceOverrideEnabled", bootEnable,
2805                             "AutomaticRetryConfig", automaticRetryConfig))
2806                     {
2807                         return;
2808                     }
2809 
2810                     if (bootSource || bootType || bootEnable)
2811                     {
2812                         setBootProperties(asyncResp, bootSource, bootType,
2813                                           bootEnable);
2814                     }
2815                     if (automaticRetryConfig)
2816                     {
2817                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
2818                     }
2819                 }
2820 
2821                 if (locationIndicatorActive)
2822                 {
2823                     setLocationIndicatorActive(asyncResp,
2824                                                *locationIndicatorActive);
2825                 }
2826 
2827                 // TODO (Gunnar): Remove IndicatorLED after enough time has
2828                 // passed
2829                 if (indicatorLed)
2830                 {
2831                     setIndicatorLedState(asyncResp, *indicatorLed);
2832                     asyncResp->res.addHeader(
2833                         boost::beast::http::field::warning,
2834                         "299 - \"IndicatorLED is deprecated. Use "
2835                         "LocationIndicatorActive instead.\"");
2836                 }
2837 
2838                 if (powerRestorePolicy)
2839                 {
2840                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
2841                 }
2842 
2843                 if (powerMode)
2844                 {
2845                     setPowerMode(asyncResp, *powerMode);
2846                 }
2847             });
2848 }
2849 
2850 /**
2851  * SystemResetActionInfo derived class for delivering Computer Systems
2852  * ResetType AllowableValues using ResetInfo schema.
2853  */
2854 inline void requestRoutesSystemResetActionInfo(App& app)
2855 {
2856 
2857     /**
2858      * Functions triggers appropriate requests on DBus
2859      */
2860     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2861         .privileges(redfish::privileges::getActionInfo)
2862         .methods(boost::beast::http::verb::get)(
2863             [](const crow::Request&,
2864                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2865                 asyncResp->res.jsonValue = {
2866                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2867                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2868                     {"Name", "Reset Action Info"},
2869                     {"Id", "ResetActionInfo"},
2870                     {"Parameters",
2871                      {{{"Name", "ResetType"},
2872                        {"Required", true},
2873                        {"DataType", "String"},
2874                        {"AllowableValues",
2875                         {"On", "ForceOff", "ForceOn", "ForceRestart",
2876                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
2877                          "Nmi"}}}}}};
2878             });
2879 }
2880 } // namespace redfish
2881