xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 1c05dae3011628e5726eefc3ec4dbe7733fbb4d5)
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 Set TrustedModuleRequiredToBoot property. Determines whether or not
1480  * TPM is required for booting the host.
1481  *
1482  * @param[in] aResp         Shared pointer for generating response message.
1483  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1484  *
1485  * @return None.
1486  */
1487 inline void setTrustedModuleRequiredToBoot(
1488     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1489 {
1490     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1491 
1492     crow::connections::systemBus->async_method_call(
1493         [aResp, tpmRequired](
1494             const boost::system::error_code ec,
1495             std::vector<std::pair<
1496                 std::string,
1497                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1498                 subtree) {
1499             if (ec)
1500             {
1501                 BMCWEB_LOG_DEBUG
1502                     << "DBUS response error on TPM.Policy GetSubTree" << ec;
1503                 messages::internalError(aResp->res);
1504                 return;
1505             }
1506             if (subtree.size() == 0)
1507             {
1508                 messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1509                                                  "TrustedModuleRequiredToBoot");
1510                 return;
1511             }
1512 
1513             /* When there is more than one TPMEnable object... */
1514             if (subtree.size() > 1)
1515             {
1516                 BMCWEB_LOG_DEBUG
1517                     << "DBUS response has more than 1 TPM Enable object:"
1518                     << subtree.size();
1519                 // Throw an internal Error and return
1520                 messages::internalError(aResp->res);
1521                 return;
1522             }
1523 
1524             // Make sure the Dbus response map has a service and objectPath
1525             // field
1526             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1527             {
1528                 BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1529                 messages::internalError(aResp->res);
1530                 return;
1531             }
1532 
1533             const std::string& path = subtree[0].first;
1534             const std::string& serv = subtree[0].second.begin()->first;
1535 
1536             if (serv.empty())
1537             {
1538                 BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1539                 messages::internalError(aResp->res);
1540                 return;
1541             }
1542 
1543             // Valid TPM Enable object found, now setting the value
1544             crow::connections::systemBus->async_method_call(
1545                 [aResp](const boost::system::error_code ec) {
1546                     if (ec)
1547                     {
1548                         BMCWEB_LOG_DEBUG << "DBUS response error: Set "
1549                                             "TrustedModuleRequiredToBoot"
1550                                          << ec;
1551                         messages::internalError(aResp->res);
1552                         return;
1553                     }
1554                     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1555                 },
1556                 serv, path, "org.freedesktop.DBus.Properties", "Set",
1557                 "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1558                 std::variant<bool>(tpmRequired));
1559         },
1560         "xyz.openbmc_project.ObjectMapper",
1561         "/xyz/openbmc_project/object_mapper",
1562         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
1563         std::array<const char*, 1>{"xyz.openbmc_project.Control.TPM.Policy"});
1564 }
1565 
1566 /**
1567  * @brief Sets boot properties into DBUS object(s).
1568  *
1569  * @param[in] aResp           Shared pointer for generating response message.
1570  * @param[in] bootType        The boot type to set.
1571  * @return Integer error code.
1572  */
1573 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1574                         const std::optional<std::string>& bootType)
1575 {
1576     std::string bootTypeStr;
1577 
1578     if (!bootType)
1579     {
1580         return;
1581     }
1582 
1583     // Source target specified
1584     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1585     // Figure out which DBUS interface and property to use
1586     if (*bootType == "Legacy")
1587     {
1588         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1589     }
1590     else if (*bootType == "UEFI")
1591     {
1592         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1593     }
1594     else
1595     {
1596         BMCWEB_LOG_DEBUG << "Invalid property value for "
1597                             "BootSourceOverrideMode: "
1598                          << *bootType;
1599         messages::propertyValueNotInList(aResp->res, *bootType,
1600                                          "BootSourceOverrideMode");
1601         return;
1602     }
1603 
1604     // Act on validated parameters
1605     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1606 
1607     crow::connections::systemBus->async_method_call(
1608         [aResp](const boost::system::error_code ec) {
1609             if (ec)
1610             {
1611                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1612                 if (ec.value() == boost::asio::error::host_unreachable)
1613                 {
1614                     messages::resourceNotFound(aResp->res, "Set", "BootType");
1615                     return;
1616                 }
1617                 messages::internalError(aResp->res);
1618                 return;
1619             }
1620             BMCWEB_LOG_DEBUG << "Boot type update done.";
1621         },
1622         "xyz.openbmc_project.Settings",
1623         "/xyz/openbmc_project/control/host0/boot",
1624         "org.freedesktop.DBus.Properties", "Set",
1625         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1626         std::variant<std::string>(bootTypeStr));
1627 }
1628 
1629 /**
1630  * @brief Sets boot properties into DBUS object(s).
1631  *
1632  * @param[in] aResp           Shared pointer for generating response message.
1633  * @param[in] bootType        The boot type to set.
1634  * @return Integer error code.
1635  */
1636 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1637                           const std::optional<std::string>& bootEnable)
1638 {
1639     if (!bootEnable)
1640     {
1641         return;
1642     }
1643     // Source target specified
1644     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1645 
1646     bool bootOverrideEnable = false;
1647     bool bootOverridePersistent = false;
1648     // Figure out which DBUS interface and property to use
1649     if (*bootEnable == "Disabled")
1650     {
1651         bootOverrideEnable = false;
1652     }
1653     else if (*bootEnable == "Once")
1654     {
1655         bootOverrideEnable = true;
1656         bootOverridePersistent = false;
1657     }
1658     else if (*bootEnable == "Continuous")
1659     {
1660         bootOverrideEnable = true;
1661         bootOverridePersistent = true;
1662     }
1663     else
1664     {
1665         BMCWEB_LOG_DEBUG << "Invalid property value for "
1666                             "BootSourceOverrideEnabled: "
1667                          << *bootEnable;
1668         messages::propertyValueNotInList(aResp->res, *bootEnable,
1669                                          "BootSourceOverrideEnabled");
1670         return;
1671     }
1672 
1673     // Act on validated parameters
1674     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1675 
1676     crow::connections::systemBus->async_method_call(
1677         [aResp](const boost::system::error_code ec) {
1678             if (ec)
1679             {
1680                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1681                 messages::internalError(aResp->res);
1682                 return;
1683             }
1684             BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1685         },
1686         "xyz.openbmc_project.Settings",
1687         "/xyz/openbmc_project/control/host0/boot",
1688         "org.freedesktop.DBus.Properties", "Set",
1689         "xyz.openbmc_project.Object.Enable", "Enabled",
1690         std::variant<bool>(bootOverrideEnable));
1691 
1692     if (!bootOverrideEnable)
1693     {
1694         return;
1695     }
1696 
1697     // In case boot override is enabled we need to set correct value for the
1698     // 'one_time' enable DBus interface
1699     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1700                      << bootOverridePersistent;
1701 
1702     crow::connections::systemBus->async_method_call(
1703         [aResp](const boost::system::error_code ec) {
1704             if (ec)
1705             {
1706                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1707                 messages::internalError(aResp->res);
1708                 return;
1709             }
1710             BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1711         },
1712         "xyz.openbmc_project.Settings",
1713         "/xyz/openbmc_project/control/host0/boot/one_time",
1714         "org.freedesktop.DBus.Properties", "Set",
1715         "xyz.openbmc_project.Object.Enable", "Enabled",
1716         std::variant<bool>(!bootOverridePersistent));
1717 }
1718 
1719 /**
1720  * @brief Sets boot properties into DBUS object(s).
1721  *
1722  * @param[in] aResp           Shared pointer for generating response message.
1723  * @param[in] bootSource      The boot source to set.
1724  *
1725  * @return Integer error code.
1726  */
1727 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1728                                 const std::optional<std::string>& bootSource)
1729 {
1730     std::string bootSourceStr;
1731     std::string bootModeStr;
1732 
1733     if (!bootSource)
1734     {
1735         return;
1736     }
1737 
1738     // Source target specified
1739     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1740     // Figure out which DBUS interface and property to use
1741     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr))
1742     {
1743         BMCWEB_LOG_DEBUG
1744             << "Invalid property value for BootSourceOverrideTarget: "
1745             << *bootSource;
1746         messages::propertyValueNotInList(aResp->res, *bootSource,
1747                                          "BootSourceTargetOverride");
1748         return;
1749     }
1750 
1751     // Act on validated parameters
1752     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1753     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1754 
1755     crow::connections::systemBus->async_method_call(
1756         [aResp](const boost::system::error_code ec) {
1757             if (ec)
1758             {
1759                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1760                 messages::internalError(aResp->res);
1761                 return;
1762             }
1763             BMCWEB_LOG_DEBUG << "Boot source update done.";
1764         },
1765         "xyz.openbmc_project.Settings",
1766         "/xyz/openbmc_project/control/host0/boot",
1767         "org.freedesktop.DBus.Properties", "Set",
1768         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1769         std::variant<std::string>(bootSourceStr));
1770 
1771     crow::connections::systemBus->async_method_call(
1772         [aResp](const boost::system::error_code ec) {
1773             if (ec)
1774             {
1775                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1776                 messages::internalError(aResp->res);
1777                 return;
1778             }
1779             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1780         },
1781         "xyz.openbmc_project.Settings",
1782         "/xyz/openbmc_project/control/host0/boot",
1783         "org.freedesktop.DBus.Properties", "Set",
1784         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1785         std::variant<std::string>(bootModeStr));
1786 }
1787 
1788 /**
1789  * @brief Sets Boot source override properties.
1790  *
1791  * @param[in] aResp      Shared pointer for generating response message.
1792  * @param[in] bootSource The boot source from incoming RF request.
1793  * @param[in] bootType   The boot type from incoming RF request.
1794  * @param[in] bootEnable The boot override enable from incoming RF request.
1795  *
1796  * @return Integer error code.
1797  */
1798 
1799 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1800                               const std::optional<std::string>& bootSource,
1801                               const std::optional<std::string>& bootType,
1802                               const std::optional<std::string>& bootEnable)
1803 {
1804     BMCWEB_LOG_DEBUG << "Set boot information.";
1805 
1806     setBootModeOrSource(aResp, bootSource);
1807     setBootType(aResp, bootType);
1808     setBootEnable(aResp, bootEnable);
1809 }
1810 
1811 /**
1812  * @brief Sets AssetTag
1813  *
1814  * @param[in] aResp   Shared pointer for generating response message.
1815  * @param[in] assetTag  "AssetTag" from request.
1816  *
1817  * @return None.
1818  */
1819 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1820                         const std::string& assetTag)
1821 {
1822     crow::connections::systemBus->async_method_call(
1823         [aResp, assetTag](
1824             const boost::system::error_code ec,
1825             const std::vector<std::pair<
1826                 std::string,
1827                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1828                 subtree) {
1829             if (ec)
1830             {
1831                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1832                 messages::internalError(aResp->res);
1833                 return;
1834             }
1835             if (subtree.size() == 0)
1836             {
1837                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1838                 messages::internalError(aResp->res);
1839                 return;
1840             }
1841             // Assume only 1 system D-Bus object
1842             // Throw an error if there is more than 1
1843             if (subtree.size() > 1)
1844             {
1845                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1846                 messages::internalError(aResp->res);
1847                 return;
1848             }
1849             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1850             {
1851                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1852                 messages::internalError(aResp->res);
1853                 return;
1854             }
1855 
1856             const std::string& path = subtree[0].first;
1857             const std::string& service = subtree[0].second.begin()->first;
1858 
1859             if (service.empty())
1860             {
1861                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1862                 messages::internalError(aResp->res);
1863                 return;
1864             }
1865 
1866             crow::connections::systemBus->async_method_call(
1867                 [aResp](const boost::system::error_code ec2) {
1868                     if (ec2)
1869                     {
1870                         BMCWEB_LOG_DEBUG
1871                             << "D-Bus response error on AssetTag Set " << ec2;
1872                         messages::internalError(aResp->res);
1873                         return;
1874                     }
1875                 },
1876                 service, path, "org.freedesktop.DBus.Properties", "Set",
1877                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1878                 std::variant<std::string>(assetTag));
1879         },
1880         "xyz.openbmc_project.ObjectMapper",
1881         "/xyz/openbmc_project/object_mapper",
1882         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1883         "/xyz/openbmc_project/inventory", int32_t(0),
1884         std::array<const char*, 1>{
1885             "xyz.openbmc_project.Inventory.Item.System"});
1886 }
1887 
1888 /**
1889  * @brief Sets automaticRetry (Auto Reboot)
1890  *
1891  * @param[in] aResp   Shared pointer for generating response message.
1892  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1893  *
1894  * @return None.
1895  */
1896 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1897                               const std::string& automaticRetryConfig)
1898 {
1899     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1900 
1901     // OpenBMC only supports "Disabled" and "RetryAttempts".
1902     bool autoRebootEnabled;
1903 
1904     if (automaticRetryConfig == "Disabled")
1905     {
1906         autoRebootEnabled = false;
1907     }
1908     else if (automaticRetryConfig == "RetryAttempts")
1909     {
1910         autoRebootEnabled = true;
1911     }
1912     else
1913     {
1914         BMCWEB_LOG_DEBUG << "Invalid property value for "
1915                             "AutomaticRetryConfig: "
1916                          << automaticRetryConfig;
1917         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1918                                          "AutomaticRetryConfig");
1919         return;
1920     }
1921 
1922     crow::connections::systemBus->async_method_call(
1923         [aResp](const boost::system::error_code ec) {
1924             if (ec)
1925             {
1926                 messages::internalError(aResp->res);
1927                 return;
1928             }
1929         },
1930         "xyz.openbmc_project.Settings",
1931         "/xyz/openbmc_project/control/host0/auto_reboot",
1932         "org.freedesktop.DBus.Properties", "Set",
1933         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1934         std::variant<bool>(autoRebootEnabled));
1935 }
1936 
1937 /**
1938  * @brief Sets power restore policy properties.
1939  *
1940  * @param[in] aResp   Shared pointer for generating response message.
1941  * @param[in] policy  power restore policy properties from request.
1942  *
1943  * @return None.
1944  */
1945 inline void
1946     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1947                           const std::string& policy)
1948 {
1949     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1950 
1951     const boost::container::flat_map<std::string, std::string> policyMaps = {
1952         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1953                      "AlwaysOn"},
1954         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1955                       "AlwaysOff"},
1956         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1957                       "Restore"}};
1958 
1959     std::string powerRestorPolicy;
1960 
1961     auto policyMapsIt = policyMaps.find(policy);
1962     if (policyMapsIt == policyMaps.end())
1963     {
1964         messages::propertyValueNotInList(aResp->res, policy,
1965                                          "PowerRestorePolicy");
1966         return;
1967     }
1968 
1969     powerRestorPolicy = policyMapsIt->second;
1970 
1971     crow::connections::systemBus->async_method_call(
1972         [aResp](const boost::system::error_code ec) {
1973             if (ec)
1974             {
1975                 messages::internalError(aResp->res);
1976                 return;
1977             }
1978         },
1979         "xyz.openbmc_project.Settings",
1980         "/xyz/openbmc_project/control/host0/power_restore_policy",
1981         "org.freedesktop.DBus.Properties", "Set",
1982         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1983         std::variant<std::string>(powerRestorPolicy));
1984 }
1985 
1986 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1987 /**
1988  * @brief Retrieves provisioning status
1989  *
1990  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1991  *
1992  * @return None.
1993  */
1994 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1995 {
1996     BMCWEB_LOG_DEBUG << "Get OEM information.";
1997     crow::connections::systemBus->async_method_call(
1998         [aResp](const boost::system::error_code ec,
1999                 const std::vector<std::pair<std::string, VariantType>>&
2000                     propertiesList) {
2001             nlohmann::json& oemPFR =
2002                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
2003             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
2004                 "#OemComputerSystem.OpenBmc";
2005             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
2006 
2007             if (ec)
2008             {
2009                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2010                 // not an error, don't have to have the interface
2011                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
2012                 return;
2013             }
2014 
2015             const bool* provState = nullptr;
2016             const bool* lockState = nullptr;
2017             for (const std::pair<std::string, VariantType>& property :
2018                  propertiesList)
2019             {
2020                 if (property.first == "UfmProvisioned")
2021                 {
2022                     provState = std::get_if<bool>(&property.second);
2023                 }
2024                 else if (property.first == "UfmLocked")
2025                 {
2026                     lockState = std::get_if<bool>(&property.second);
2027                 }
2028             }
2029 
2030             if ((provState == nullptr) || (lockState == nullptr))
2031             {
2032                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
2033                 messages::internalError(aResp->res);
2034                 return;
2035             }
2036 
2037             if (*provState == true)
2038             {
2039                 if (*lockState == true)
2040                 {
2041                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
2042                 }
2043                 else
2044                 {
2045                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
2046                 }
2047             }
2048             else
2049             {
2050                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
2051             }
2052         },
2053         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
2054         "org.freedesktop.DBus.Properties", "GetAll",
2055         "xyz.openbmc_project.PFR.Attributes");
2056 }
2057 #endif
2058 
2059 /**
2060  * @brief Translate the PowerMode to a response message.
2061  *
2062  * @param[in] aResp  Shared pointer for generating response message.
2063  * @param[in] modeValue  PowerMode value to be translated
2064  *
2065  * @return None.
2066  */
2067 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2068                                const std::string& modeValue)
2069 {
2070     std::string modeString;
2071 
2072     if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
2073                      "PowerMode.Static")
2074     {
2075         aResp->res.jsonValue["PowerMode"] = "Static";
2076     }
2077     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
2078                           "PowerMode.MaximumPerformance")
2079     {
2080         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
2081     }
2082     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
2083                           "PowerMode.PowerSaving")
2084     {
2085         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
2086     }
2087     else if (modeValue == "xyz.openbmc_project.Control.Power.Mode."
2088                           "PowerMode.OEM")
2089     {
2090         aResp->res.jsonValue["PowerMode"] = "OEM";
2091     }
2092     else
2093     {
2094         // Any other values would be invalid
2095         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
2096         messages::internalError(aResp->res);
2097     }
2098 }
2099 
2100 /**
2101  * @brief Retrieves system power mode
2102  *
2103  * @param[in] aResp  Shared pointer for generating response message.
2104  *
2105  * @return None.
2106  */
2107 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2108 {
2109     BMCWEB_LOG_DEBUG << "Get power mode.";
2110 
2111     // Get Power Mode object path:
2112     crow::connections::systemBus->async_method_call(
2113         [aResp](
2114             const boost::system::error_code ec,
2115             const std::vector<std::pair<
2116                 std::string,
2117                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2118                 subtree) {
2119             if (ec)
2120             {
2121                 BMCWEB_LOG_DEBUG
2122                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2123                 // This is an optional D-Bus object so just return if
2124                 // error occurs
2125                 return;
2126             }
2127             if (subtree.empty())
2128             {
2129                 // As noted above, this is an optional interface so just return
2130                 // if there is no instance found
2131                 return;
2132             }
2133             if (subtree.size() > 1)
2134             {
2135                 // More then one PowerMode object is not supported and is an
2136                 // error
2137                 BMCWEB_LOG_DEBUG
2138                     << "Found more than 1 system D-Bus Power.Mode objects: "
2139                     << subtree.size();
2140                 messages::internalError(aResp->res);
2141                 return;
2142             }
2143             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2144             {
2145                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2146                 messages::internalError(aResp->res);
2147                 return;
2148             }
2149             const std::string& path = subtree[0].first;
2150             const std::string& service = subtree[0].second.begin()->first;
2151             if (service.empty())
2152             {
2153                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2154                 messages::internalError(aResp->res);
2155                 return;
2156             }
2157             // Valid Power Mode object found, now read the current value
2158             crow::connections::systemBus->async_method_call(
2159                 [aResp](const boost::system::error_code ec,
2160                         const std::variant<std::string>& pmode) {
2161                     if (ec)
2162                     {
2163                         BMCWEB_LOG_DEBUG
2164                             << "DBUS response error on PowerMode Get: " << ec;
2165                         messages::internalError(aResp->res);
2166                         return;
2167                     }
2168 
2169                     const std::string* s = std::get_if<std::string>(&pmode);
2170                     if (s == nullptr)
2171                     {
2172                         BMCWEB_LOG_DEBUG << "Unable to get PowerMode value";
2173                         messages::internalError(aResp->res);
2174                         return;
2175                     }
2176 
2177                     aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] =
2178                         {"Static", "MaximumPerformance", "PowerSaving"};
2179 
2180                     BMCWEB_LOG_DEBUG << "Current power mode: " << *s;
2181                     translatePowerMode(aResp, *s);
2182                 },
2183                 service, path, "org.freedesktop.DBus.Properties", "Get",
2184                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode");
2185         },
2186         "xyz.openbmc_project.ObjectMapper",
2187         "/xyz/openbmc_project/object_mapper",
2188         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2189         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2190 }
2191 
2192 /**
2193  * @brief Validate the specified mode is valid and return the PowerMode
2194  * name associated with that string
2195  *
2196  * @param[in] aResp   Shared pointer for generating response message.
2197  * @param[in] modeString  String representing the desired PowerMode
2198  *
2199  * @return PowerMode value or empty string if mode is not valid
2200  */
2201 inline std::string
2202     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2203                       const std::string& modeString)
2204 {
2205     std::string mode;
2206 
2207     if (modeString == "Static")
2208     {
2209         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2210     }
2211     else if (modeString == "MaximumPerformance")
2212     {
2213         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode."
2214                "MaximumPerformance";
2215     }
2216     else if (modeString == "PowerSaving")
2217     {
2218         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2219     }
2220     else
2221     {
2222         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2223     }
2224     return mode;
2225 }
2226 
2227 /**
2228  * @brief Sets system power mode.
2229  *
2230  * @param[in] aResp   Shared pointer for generating response message.
2231  * @param[in] pmode   System power mode from request.
2232  *
2233  * @return None.
2234  */
2235 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2236                          const std::string& pmode)
2237 {
2238     BMCWEB_LOG_DEBUG << "Set power mode.";
2239 
2240     std::string powerMode = validatePowerMode(aResp, pmode);
2241     if (powerMode.empty())
2242     {
2243         return;
2244     }
2245 
2246     // Get Power Mode object path:
2247     crow::connections::systemBus->async_method_call(
2248         [aResp, powerMode](
2249             const boost::system::error_code ec,
2250             const std::vector<std::pair<
2251                 std::string,
2252                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
2253                 subtree) {
2254             if (ec)
2255             {
2256                 BMCWEB_LOG_DEBUG
2257                     << "DBUS response error on Power.Mode GetSubTree " << ec;
2258                 // This is an optional D-Bus object, but user attempted to patch
2259                 messages::internalError(aResp->res);
2260                 return;
2261             }
2262             if (subtree.empty())
2263             {
2264                 // This is an optional D-Bus object, but user attempted to patch
2265                 messages::resourceNotFound(aResp->res, "ComputerSystem",
2266                                            "PowerMode");
2267                 return;
2268             }
2269             if (subtree.size() > 1)
2270             {
2271                 // More then one PowerMode object is not supported and is an
2272                 // error
2273                 BMCWEB_LOG_DEBUG
2274                     << "Found more than 1 system D-Bus Power.Mode objects: "
2275                     << subtree.size();
2276                 messages::internalError(aResp->res);
2277                 return;
2278             }
2279             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2280             {
2281                 BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2282                 messages::internalError(aResp->res);
2283                 return;
2284             }
2285             const std::string& path = subtree[0].first;
2286             const std::string& service = subtree[0].second.begin()->first;
2287             if (service.empty())
2288             {
2289                 BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2290                 messages::internalError(aResp->res);
2291                 return;
2292             }
2293 
2294             BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2295                              << path;
2296 
2297             // Set the Power Mode property
2298             crow::connections::systemBus->async_method_call(
2299                 [aResp](const boost::system::error_code ec) {
2300                     if (ec)
2301                     {
2302                         messages::internalError(aResp->res);
2303                         return;
2304                     }
2305                 },
2306                 service, path, "org.freedesktop.DBus.Properties", "Set",
2307                 "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2308                 std::variant<std::string>(powerMode));
2309         },
2310         "xyz.openbmc_project.ObjectMapper",
2311         "/xyz/openbmc_project/object_mapper",
2312         "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0),
2313         std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"});
2314 }
2315 
2316 /**
2317  * @brief Translates watchdog timeout action DBUS property value to redfish.
2318  *
2319  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2320  *
2321  * @return Returns as a string, the timeout action in Redfish terms. If
2322  * translation cannot be done, returns an empty string.
2323  */
2324 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2325 {
2326     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2327     {
2328         return "None";
2329     }
2330     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2331     {
2332         return "ResetSystem";
2333     }
2334     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2335     {
2336         return "PowerDown";
2337     }
2338     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2339     {
2340         return "PowerCycle";
2341     }
2342 
2343     return "";
2344 }
2345 
2346 /**
2347  *@brief Translates timeout action from Redfish to DBUS property value.
2348  *
2349  *@param[in] rfAction The timeout action in Redfish.
2350  *
2351  *@return Returns as a string, the time_out action as expected by DBUS.
2352  *If translation cannot be done, returns an empty string.
2353  */
2354 
2355 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2356 {
2357     if (rfAction == "None")
2358     {
2359         return "xyz.openbmc_project.State.Watchdog.Action.None";
2360     }
2361     if (rfAction == "PowerCycle")
2362     {
2363         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2364     }
2365     if (rfAction == "PowerDown")
2366     {
2367         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2368     }
2369     if (rfAction == "ResetSystem")
2370     {
2371         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2372     }
2373 
2374     return "";
2375 }
2376 
2377 /**
2378  * @brief Retrieves host watchdog timer properties over DBUS
2379  *
2380  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2381  *
2382  * @return None.
2383  */
2384 inline void
2385     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2386 {
2387     BMCWEB_LOG_DEBUG << "Get host watchodg";
2388     crow::connections::systemBus->async_method_call(
2389         [aResp](const boost::system::error_code ec,
2390                 PropertiesType& properties) {
2391             if (ec)
2392             {
2393                 // watchdog service is stopped
2394                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2395                 return;
2396             }
2397 
2398             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2399 
2400             nlohmann::json& hostWatchdogTimer =
2401                 aResp->res.jsonValue["HostWatchdogTimer"];
2402 
2403             // watchdog service is running/enabled
2404             hostWatchdogTimer["Status"]["State"] = "Enabled";
2405 
2406             for (const auto& property : properties)
2407             {
2408                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
2409                 if (property.first == "Enabled")
2410                 {
2411                     const bool* state = std::get_if<bool>(&property.second);
2412 
2413                     if (!state)
2414                     {
2415                         messages::internalError(aResp->res);
2416                         return;
2417                     }
2418 
2419                     hostWatchdogTimer["FunctionEnabled"] = *state;
2420                 }
2421                 else if (property.first == "ExpireAction")
2422                 {
2423                     const std::string* s =
2424                         std::get_if<std::string>(&property.second);
2425                     if (!s)
2426                     {
2427                         messages::internalError(aResp->res);
2428                         return;
2429                     }
2430 
2431                     std::string action = dbusToRfWatchdogAction(*s);
2432                     if (action.empty())
2433                     {
2434                         messages::internalError(aResp->res);
2435                         return;
2436                     }
2437                     hostWatchdogTimer["TimeoutAction"] = action;
2438                 }
2439             }
2440         },
2441         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2442         "org.freedesktop.DBus.Properties", "GetAll",
2443         "xyz.openbmc_project.State.Watchdog");
2444 }
2445 
2446 /**
2447  * @brief Sets Host WatchDog Timer properties.
2448  *
2449  * @param[in] aResp      Shared pointer for generating response message.
2450  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2451  *                       RF request.
2452  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2453  *
2454  * @return None.
2455  */
2456 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2457                              const std::optional<bool> wdtEnable,
2458                              const std::optional<std::string>& wdtTimeOutAction)
2459 {
2460     BMCWEB_LOG_DEBUG << "Set host watchdog";
2461 
2462     if (wdtTimeOutAction)
2463     {
2464         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2465         // check if TimeOut Action is Valid
2466         if (wdtTimeOutActStr.empty())
2467         {
2468             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2469                              << *wdtTimeOutAction;
2470             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2471                                              "TimeoutAction");
2472             return;
2473         }
2474 
2475         crow::connections::systemBus->async_method_call(
2476             [aResp](const boost::system::error_code ec) {
2477                 if (ec)
2478                 {
2479                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2480                     messages::internalError(aResp->res);
2481                     return;
2482                 }
2483             },
2484             "xyz.openbmc_project.Watchdog",
2485             "/xyz/openbmc_project/watchdog/host0",
2486             "org.freedesktop.DBus.Properties", "Set",
2487             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2488             std::variant<std::string>(wdtTimeOutActStr));
2489     }
2490 
2491     if (wdtEnable)
2492     {
2493         crow::connections::systemBus->async_method_call(
2494             [aResp](const boost::system::error_code ec) {
2495                 if (ec)
2496                 {
2497                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2498                     messages::internalError(aResp->res);
2499                     return;
2500                 }
2501             },
2502             "xyz.openbmc_project.Watchdog",
2503             "/xyz/openbmc_project/watchdog/host0",
2504             "org.freedesktop.DBus.Properties", "Set",
2505             "xyz.openbmc_project.State.Watchdog", "Enabled",
2506             std::variant<bool>(*wdtEnable));
2507     }
2508 }
2509 
2510 /**
2511  * SystemsCollection derived class for delivering ComputerSystems Collection
2512  * Schema
2513  */
2514 inline void requestRoutesSystemsCollection(App& app)
2515 {
2516     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2517         .privileges(redfish::privileges::getComputerSystemCollection)
2518         .methods(boost::beast::http::verb::get)(
2519             [](const crow::Request& /*req*/,
2520                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2521                 asyncResp->res.jsonValue["@odata.type"] =
2522                     "#ComputerSystemCollection.ComputerSystemCollection";
2523                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2524                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2525 
2526                 crow::connections::systemBus->async_method_call(
2527                     [asyncResp](const boost::system::error_code ec,
2528                                 const std::variant<std::string>& /*hostName*/) {
2529                         nlohmann::json& ifaceArray =
2530                             asyncResp->res.jsonValue["Members"];
2531                         ifaceArray = nlohmann::json::array();
2532                         auto& count =
2533                             asyncResp->res.jsonValue["Members@odata.count"];
2534                         ifaceArray.push_back(
2535                             {{"@odata.id", "/redfish/v1/Systems/system"}});
2536                         count = ifaceArray.size();
2537                         if (!ec)
2538                         {
2539                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
2540                             ifaceArray.push_back(
2541                                 {{"@odata.id",
2542                                   "/redfish/v1/Systems/hypervisor"}});
2543                             count = ifaceArray.size();
2544                         }
2545                     },
2546                     "xyz.openbmc_project.Settings",
2547                     "/xyz/openbmc_project/network/hypervisor",
2548                     "org.freedesktop.DBus.Properties", "Get",
2549                     "xyz.openbmc_project.Network.SystemConfiguration",
2550                     "HostName");
2551             });
2552 }
2553 
2554 /**
2555  * Function transceives data with dbus directly.
2556  */
2557 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2558 {
2559     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2560     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2561     constexpr char const* interfaceName =
2562         "xyz.openbmc_project.Control.Host.NMI";
2563     constexpr char const* method = "NMI";
2564 
2565     crow::connections::systemBus->async_method_call(
2566         [asyncResp](const boost::system::error_code ec) {
2567             if (ec)
2568             {
2569                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2570                 messages::internalError(asyncResp->res);
2571                 return;
2572             }
2573             messages::success(asyncResp->res);
2574         },
2575         serviceName, objectPath, interfaceName, method);
2576 }
2577 
2578 /**
2579  * SystemActionsReset class supports handle POST method for Reset action.
2580  * The class retrieves and sends data directly to D-Bus.
2581  */
2582 inline void requestRoutesSystemActionsReset(App& app)
2583 {
2584     /**
2585      * Function handles POST method request.
2586      * Analyzes POST body message before sends Reset request data to D-Bus.
2587      */
2588     BMCWEB_ROUTE(app,
2589                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2590         .privileges(redfish::privileges::postComputerSystem)
2591         .methods(
2592             boost::beast::http::verb::
2593                 post)([](const crow::Request& req,
2594                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2595             std::string resetType;
2596             if (!json_util::readJson(req, asyncResp->res, "ResetType",
2597                                      resetType))
2598             {
2599                 return;
2600             }
2601 
2602             // Get the command and host vs. chassis
2603             std::string command;
2604             bool hostCommand;
2605             if ((resetType == "On") || (resetType == "ForceOn"))
2606             {
2607                 command = "xyz.openbmc_project.State.Host.Transition.On";
2608                 hostCommand = true;
2609             }
2610             else if (resetType == "ForceOff")
2611             {
2612                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2613                 hostCommand = false;
2614             }
2615             else if (resetType == "ForceRestart")
2616             {
2617                 command =
2618                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2619                 hostCommand = true;
2620             }
2621             else if (resetType == "GracefulShutdown")
2622             {
2623                 command = "xyz.openbmc_project.State.Host.Transition.Off";
2624                 hostCommand = true;
2625             }
2626             else if (resetType == "GracefulRestart")
2627             {
2628                 command = "xyz.openbmc_project.State.Host.Transition."
2629                           "GracefulWarmReboot";
2630                 hostCommand = true;
2631             }
2632             else if (resetType == "PowerCycle")
2633             {
2634                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2635                 hostCommand = true;
2636             }
2637             else if (resetType == "Nmi")
2638             {
2639                 doNMI(asyncResp);
2640                 return;
2641             }
2642             else
2643             {
2644                 messages::actionParameterUnknown(asyncResp->res, "Reset",
2645                                                  resetType);
2646                 return;
2647             }
2648 
2649             if (hostCommand)
2650             {
2651                 crow::connections::systemBus->async_method_call(
2652                     [asyncResp, resetType](const boost::system::error_code ec) {
2653                         if (ec)
2654                         {
2655                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2656                             if (ec.value() ==
2657                                 boost::asio::error::invalid_argument)
2658                             {
2659                                 messages::actionParameterNotSupported(
2660                                     asyncResp->res, resetType, "Reset");
2661                             }
2662                             else
2663                             {
2664                                 messages::internalError(asyncResp->res);
2665                             }
2666                             return;
2667                         }
2668                         messages::success(asyncResp->res);
2669                     },
2670                     "xyz.openbmc_project.State.Host",
2671                     "/xyz/openbmc_project/state/host0",
2672                     "org.freedesktop.DBus.Properties", "Set",
2673                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2674                     std::variant<std::string>{command});
2675             }
2676             else
2677             {
2678                 crow::connections::systemBus->async_method_call(
2679                     [asyncResp, resetType](const boost::system::error_code ec) {
2680                         if (ec)
2681                         {
2682                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2683                             if (ec.value() ==
2684                                 boost::asio::error::invalid_argument)
2685                             {
2686                                 messages::actionParameterNotSupported(
2687                                     asyncResp->res, resetType, "Reset");
2688                             }
2689                             else
2690                             {
2691                                 messages::internalError(asyncResp->res);
2692                             }
2693                             return;
2694                         }
2695                         messages::success(asyncResp->res);
2696                     },
2697                     "xyz.openbmc_project.State.Chassis",
2698                     "/xyz/openbmc_project/state/chassis0",
2699                     "org.freedesktop.DBus.Properties", "Set",
2700                     "xyz.openbmc_project.State.Chassis",
2701                     "RequestedPowerTransition",
2702                     std::variant<std::string>{command});
2703             }
2704         });
2705 }
2706 
2707 /**
2708  * Systems derived class for delivering Computer Systems Schema.
2709  */
2710 inline void requestRoutesSystems(App& app)
2711 {
2712 
2713     /**
2714      * Functions triggers appropriate requests on DBus
2715      */
2716     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2717         .privileges(redfish::privileges::getComputerSystem)
2718         .methods(
2719             boost::beast::http::verb::
2720                 get)([](const crow::Request&,
2721                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2722             asyncResp->res.jsonValue["@odata.type"] =
2723                 "#ComputerSystem.v1_15_0.ComputerSystem";
2724             asyncResp->res.jsonValue["Name"] = "system";
2725             asyncResp->res.jsonValue["Id"] = "system";
2726             asyncResp->res.jsonValue["SystemType"] = "Physical";
2727             asyncResp->res.jsonValue["Description"] = "Computer System";
2728             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2729             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2730                 "Disabled";
2731             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2732                 uint64_t(0);
2733             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2734                 "Disabled";
2735             asyncResp->res.jsonValue["@odata.id"] =
2736                 "/redfish/v1/Systems/system";
2737 
2738             asyncResp->res.jsonValue["Processors"] = {
2739                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2740             asyncResp->res.jsonValue["Memory"] = {
2741                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2742             asyncResp->res.jsonValue["Storage"] = {
2743                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2744 
2745             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2746                 {"target",
2747                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2748                 {"@Redfish.ActionInfo",
2749                  "/redfish/v1/Systems/system/ResetActionInfo"}};
2750 
2751             asyncResp->res.jsonValue["LogServices"] = {
2752                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2753 
2754             asyncResp->res.jsonValue["Bios"] = {
2755                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2756 
2757             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
2758                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2759 
2760             asyncResp->res.jsonValue["Status"] = {
2761                 {"Health", "OK"},
2762                 {"State", "Enabled"},
2763             };
2764 
2765             // Fill in SerialConsole info
2766             asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] =
2767                 15;
2768             asyncResp->res.jsonValue["SerialConsole"]["IPMI"] = {
2769                 {"ServiceEnabled", true},
2770             };
2771             // TODO (Gunnar): Should look for obmc-console-ssh@2200.service
2772             asyncResp->res.jsonValue["SerialConsole"]["SSH"] = {
2773                 {"ServiceEnabled", true},
2774                 {"Port", 2200},
2775                 // https://github.com/openbmc/docs/blob/master/console.md
2776                 {"HotKeySequenceDisplay", "Press ~. to exit console"},
2777             };
2778 
2779 #ifdef BMCWEB_ENABLE_KVM
2780             // Fill in GraphicalConsole info
2781             asyncResp->res.jsonValue["GraphicalConsole"] = {
2782                 {"ServiceEnabled", true},
2783                 {"MaxConcurrentSessions", 4},
2784                 {"ConnectTypesSupported", {"KVMIP"}},
2785             };
2786 #endif // BMCWEB_ENABLE_KVM
2787             constexpr const std::array<const char*, 4> inventoryForSystems = {
2788                 "xyz.openbmc_project.Inventory.Item.Dimm",
2789                 "xyz.openbmc_project.Inventory.Item.Cpu",
2790                 "xyz.openbmc_project.Inventory.Item.Drive",
2791                 "xyz.openbmc_project.Inventory.Item.StorageController"};
2792 
2793             auto health = std::make_shared<HealthPopulate>(asyncResp);
2794             crow::connections::systemBus->async_method_call(
2795                 [health](const boost::system::error_code ec,
2796                          std::vector<std::string>& resp) {
2797                     if (ec)
2798                     {
2799                         // no inventory
2800                         return;
2801                     }
2802 
2803                     health->inventory = std::move(resp);
2804                 },
2805                 "xyz.openbmc_project.ObjectMapper",
2806                 "/xyz/openbmc_project/object_mapper",
2807                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2808                 int32_t(0), inventoryForSystems);
2809 
2810             health->populate();
2811 
2812             getMainChassisId(
2813                 asyncResp, [](const std::string& chassisId,
2814                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2815                     aRsp->res.jsonValue["Links"]["Chassis"] = {
2816                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2817                 });
2818 
2819             getLocationIndicatorActive(asyncResp);
2820             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2821             getIndicatorLedState(asyncResp);
2822             getComputerSystem(asyncResp, health);
2823             getHostState(asyncResp);
2824             getBootProperties(asyncResp);
2825             getBootProgress(asyncResp);
2826             getPCIeDeviceList(asyncResp, "PCIeDevices");
2827             getHostWatchdogTimer(asyncResp);
2828             getPowerRestorePolicy(asyncResp);
2829             getAutomaticRetry(asyncResp);
2830             getLastResetTime(asyncResp);
2831 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2832             getProvisioningStatus(asyncResp);
2833 #endif
2834             getTrustedModuleRequiredToBoot(asyncResp);
2835             getPowerMode(asyncResp);
2836         });
2837     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2838         .privileges(redfish::privileges::patchComputerSystem)
2839         .methods(boost::beast::http::verb::patch)(
2840             [](const crow::Request& req,
2841                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2842                 std::optional<bool> locationIndicatorActive;
2843                 std::optional<std::string> indicatorLed;
2844                 std::optional<nlohmann::json> bootProps;
2845                 std::optional<nlohmann::json> wdtTimerProps;
2846                 std::optional<std::string> assetTag;
2847                 std::optional<std::string> powerRestorePolicy;
2848                 std::optional<std::string> powerMode;
2849                 std::optional<bool> trustedModuleRequiredToBoot;
2850                 if (!json_util::readJson(
2851                         req, asyncResp->res, "IndicatorLED", indicatorLed,
2852                         "LocationIndicatorActive", locationIndicatorActive,
2853                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
2854                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
2855                         assetTag, "PowerMode", powerMode,
2856                         "TrustedModuleRequiredToBoot",
2857                         trustedModuleRequiredToBoot))
2858                 {
2859                     return;
2860                 }
2861 
2862                 asyncResp->res.result(boost::beast::http::status::no_content);
2863 
2864                 if (assetTag)
2865                 {
2866                     setAssetTag(asyncResp, *assetTag);
2867                 }
2868 
2869                 if (wdtTimerProps)
2870                 {
2871                     std::optional<bool> wdtEnable;
2872                     std::optional<std::string> wdtTimeOutAction;
2873 
2874                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2875                                              "FunctionEnabled", wdtEnable,
2876                                              "TimeoutAction", wdtTimeOutAction))
2877                     {
2878                         return;
2879                     }
2880                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2881                 }
2882 
2883                 if (bootProps)
2884                 {
2885                     std::optional<std::string> bootSource;
2886                     std::optional<std::string> bootType;
2887                     std::optional<std::string> bootEnable;
2888                     std::optional<std::string> automaticRetryConfig;
2889 
2890                     if (!json_util::readJson(
2891                             *bootProps, asyncResp->res,
2892                             "BootSourceOverrideTarget", bootSource,
2893                             "BootSourceOverrideMode", bootType,
2894                             "BootSourceOverrideEnabled", bootEnable,
2895                             "AutomaticRetryConfig", automaticRetryConfig))
2896                     {
2897                         return;
2898                     }
2899 
2900                     if (bootSource || bootType || bootEnable)
2901                     {
2902                         setBootProperties(asyncResp, bootSource, bootType,
2903                                           bootEnable);
2904                     }
2905                     if (automaticRetryConfig)
2906                     {
2907                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
2908                     }
2909                 }
2910 
2911                 if (locationIndicatorActive)
2912                 {
2913                     setLocationIndicatorActive(asyncResp,
2914                                                *locationIndicatorActive);
2915                 }
2916 
2917                 // TODO (Gunnar): Remove IndicatorLED after enough time has
2918                 // passed
2919                 if (indicatorLed)
2920                 {
2921                     setIndicatorLedState(asyncResp, *indicatorLed);
2922                     asyncResp->res.addHeader(
2923                         boost::beast::http::field::warning,
2924                         "299 - \"IndicatorLED is deprecated. Use "
2925                         "LocationIndicatorActive instead.\"");
2926                 }
2927 
2928                 if (powerRestorePolicy)
2929                 {
2930                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
2931                 }
2932 
2933                 if (powerMode)
2934                 {
2935                     setPowerMode(asyncResp, *powerMode);
2936                 }
2937 
2938                 if (trustedModuleRequiredToBoot)
2939                 {
2940                     setTrustedModuleRequiredToBoot(
2941                         asyncResp, *trustedModuleRequiredToBoot);
2942                 }
2943             });
2944 }
2945 
2946 /**
2947  * SystemResetActionInfo derived class for delivering Computer Systems
2948  * ResetType AllowableValues using ResetInfo schema.
2949  */
2950 inline void requestRoutesSystemResetActionInfo(App& app)
2951 {
2952 
2953     /**
2954      * Functions triggers appropriate requests on DBus
2955      */
2956     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2957         .privileges(redfish::privileges::getActionInfo)
2958         .methods(boost::beast::http::verb::get)(
2959             [](const crow::Request&,
2960                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2961                 asyncResp->res.jsonValue = {
2962                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2963                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2964                     {"Name", "Reset Action Info"},
2965                     {"Id", "ResetActionInfo"},
2966                     {"Parameters",
2967                      {{{"Name", "ResetType"},
2968                        {"Required", true},
2969                        {"DataType", "String"},
2970                        {"AllowableValues",
2971                         {"On", "ForceOff", "ForceOn", "ForceRestart",
2972                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
2973                          "Nmi"}}}}}};
2974             });
2975 }
2976 } // namespace redfish
2977