xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision d6aa0093aa8736b36766df0197f7b3bb80fe4af7)
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 <boost/container/flat_map.hpp>
24 #include <node.hpp>
25 #include <utils/fw_utils.hpp>
26 #include <utils/json_utils.hpp>
27 
28 #include <variant>
29 
30 namespace redfish
31 {
32 
33 /**
34  * @brief Updates the Functional State of DIMMs
35  *
36  * @param[in] aResp Shared pointer for completing asynchronous calls
37  * @param[in] dimmState Dimm's Functional state, true/false
38  *
39  * @return None.
40  */
41 inline void updateDimmProperties(const std::shared_ptr<AsyncResp>& aResp,
42                                  const std::variant<bool>& dimmState)
43 {
44     const bool* isDimmFunctional = std::get_if<bool>(&dimmState);
45     if (isDimmFunctional == nullptr)
46     {
47         messages::internalError(aResp->res);
48         return;
49     }
50     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
51 
52     // Set it as Enabled if at least one DIMM is functional
53     // Update STATE only if previous State was DISABLED and current Dimm is
54     // ENABLED.
55     nlohmann::json& prevMemSummary =
56         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
57     if (prevMemSummary == "Disabled")
58     {
59         if (*isDimmFunctional == true)
60         {
61             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
62                 "Enabled";
63         }
64     }
65 }
66 
67 /*
68  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
69  *
70  * @param[in] aResp Shared pointer for completing asynchronous calls
71  * @param[in] cpuPresenceState CPU present or not
72  *
73  * @return None.
74  */
75 inline void modifyCpuPresenceState(const std::shared_ptr<AsyncResp>& aResp,
76                                    const std::variant<bool>& cpuPresenceState)
77 {
78     const bool* isCpuPresent = std::get_if<bool>(&cpuPresenceState);
79 
80     if (isCpuPresent == nullptr)
81     {
82         messages::internalError(aResp->res);
83         return;
84     }
85     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
86 
87     if (*isCpuPresent == true)
88     {
89         nlohmann::json& procCount =
90             aResp->res.jsonValue["ProcessorSummary"]["Count"];
91         auto procCountPtr =
92             procCount.get_ptr<nlohmann::json::number_integer_t*>();
93         if (procCountPtr != nullptr)
94         {
95             // shouldn't be possible to be nullptr
96             *procCountPtr += 1;
97         }
98     }
99 }
100 
101 /*
102  * @brief Update "ProcessorSummary" "Status" "State" based on
103  *        CPU Functional State
104  *
105  * @param[in] aResp Shared pointer for completing asynchronous calls
106  * @param[in] cpuFunctionalState is CPU functional true/false
107  *
108  * @return None.
109  */
110 inline void
111     modifyCpuFunctionalState(const std::shared_ptr<AsyncResp>& aResp,
112                              const std::variant<bool>& cpuFunctionalState)
113 {
114     const bool* isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
115 
116     if (isCpuFunctional == nullptr)
117     {
118         messages::internalError(aResp->res);
119         return;
120     }
121     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
122 
123     nlohmann::json& prevProcState =
124         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
125 
126     // Set it as Enabled if at least one CPU is functional
127     // Update STATE only if previous State was Non_Functional and current CPU is
128     // Functional.
129     if (prevProcState == "Disabled")
130     {
131         if (*isCpuFunctional == true)
132         {
133             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
134                 "Enabled";
135         }
136     }
137 }
138 
139 /*
140  * @brief Retrieves computer system properties over dbus
141  *
142  * @param[in] aResp Shared pointer for completing asynchronous calls
143  * @param[in] systemHealth  Shared HealthPopulate pointer
144  *
145  * @return None.
146  */
147 inline void
148     getComputerSystem(const std::shared_ptr<AsyncResp>& aResp,
149                       const std::shared_ptr<HealthPopulate>& systemHealth)
150 {
151     BMCWEB_LOG_DEBUG << "Get available system components.";
152 
153     crow::connections::systemBus->async_method_call(
154         [aResp, systemHealth](
155             const boost::system::error_code ec,
156             const std::vector<std::pair<
157                 std::string,
158                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
159                 subtree) {
160             if (ec)
161             {
162                 BMCWEB_LOG_DEBUG << "DBUS response error";
163                 messages::internalError(aResp->res);
164                 return;
165             }
166             // Iterate over all retrieved ObjectPaths.
167             for (const std::pair<std::string,
168                                  std::vector<std::pair<
169                                      std::string, std::vector<std::string>>>>&
170                      object : subtree)
171             {
172                 const std::string& path = object.first;
173                 BMCWEB_LOG_DEBUG << "Got path: " << path;
174                 const std::vector<
175                     std::pair<std::string, std::vector<std::string>>>&
176                     connectionNames = object.second;
177                 if (connectionNames.size() < 1)
178                 {
179                     continue;
180                 }
181 
182                 auto memoryHealth = std::make_shared<HealthPopulate>(
183                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
184 
185                 auto cpuHealth = std::make_shared<HealthPopulate>(
186                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
187 
188                 systemHealth->children.emplace_back(memoryHealth);
189                 systemHealth->children.emplace_back(cpuHealth);
190 
191                 // This is not system, so check if it's cpu, dimm, UUID or
192                 // BiosVer
193                 for (const auto& connection : connectionNames)
194                 {
195                     for (const auto& interfaceName : connection.second)
196                     {
197                         if (interfaceName ==
198                             "xyz.openbmc_project.Inventory.Item.Dimm")
199                         {
200                             BMCWEB_LOG_DEBUG
201                                 << "Found Dimm, now get its properties.";
202 
203                             crow::connections::systemBus->async_method_call(
204                                 [aResp, service{connection.first},
205                                  path](const boost::system::error_code ec2,
206                                        const std::vector<
207                                            std::pair<std::string, VariantType>>&
208                                            properties) {
209                                     if (ec2)
210                                     {
211                                         BMCWEB_LOG_ERROR
212                                             << "DBUS response error " << ec2;
213                                         messages::internalError(aResp->res);
214                                         return;
215                                     }
216                                     BMCWEB_LOG_DEBUG << "Got "
217                                                      << properties.size()
218                                                      << " Dimm properties.";
219 
220                                     if (properties.size() > 0)
221                                     {
222                                         for (const std::pair<std::string,
223                                                              VariantType>&
224                                                  property : properties)
225                                         {
226                                             if (property.first !=
227                                                 "MemorySizeInKB")
228                                             {
229                                                 continue;
230                                             }
231                                             const uint32_t* value =
232                                                 std::get_if<uint32_t>(
233                                                     &property.second);
234                                             if (value == nullptr)
235                                             {
236                                                 BMCWEB_LOG_DEBUG
237                                                     << "Find incorrect type of "
238                                                        "MemorySize";
239                                                 continue;
240                                             }
241                                             nlohmann::json& totalMemory =
242                                                 aResp->res
243                                                     .jsonValue["MemorySummar"
244                                                                "y"]
245                                                               ["TotalSystemMe"
246                                                                "moryGiB"];
247                                             uint64_t* preValue =
248                                                 totalMemory
249                                                     .get_ptr<uint64_t*>();
250                                             if (preValue == nullptr)
251                                             {
252                                                 continue;
253                                             }
254                                             aResp->res
255                                                 .jsonValue["MemorySummary"]
256                                                           ["TotalSystemMemoryGi"
257                                                            "B"] =
258                                                 *value / (1024 * 1024) +
259                                                 *preValue;
260                                             aResp->res
261                                                 .jsonValue["MemorySummary"]
262                                                           ["Status"]["State"] =
263                                                 "Enabled";
264                                         }
265                                     }
266                                     else
267                                     {
268                                         auto getDimmProperties =
269                                             [aResp](
270                                                 const boost::system::error_code
271                                                     ec3,
272                                                 const std::variant<bool>&
273                                                     dimmState) {
274                                                 if (ec3)
275                                                 {
276                                                     BMCWEB_LOG_ERROR
277                                                         << "DBUS response "
278                                                            "error "
279                                                         << ec3;
280                                                     return;
281                                                 }
282                                                 updateDimmProperties(aResp,
283                                                                      dimmState);
284                                             };
285                                         crow::connections::systemBus
286                                             ->async_method_call(
287                                                 std::move(getDimmProperties),
288                                                 service, path,
289                                                 "org.freedesktop.DBus."
290                                                 "Properties",
291                                                 "Get",
292                                                 "xyz.openbmc_project.State."
293                                                 "Decorator.OperationalStatus",
294                                                 "Functional");
295                                     }
296                                 },
297                                 connection.first, path,
298                                 "org.freedesktop.DBus.Properties", "GetAll",
299                                 "xyz.openbmc_project.Inventory.Item.Dimm");
300 
301                             memoryHealth->inventory.emplace_back(path);
302                         }
303                         else if (interfaceName ==
304                                  "xyz.openbmc_project.Inventory.Item.Cpu")
305                         {
306                             BMCWEB_LOG_DEBUG
307                                 << "Found Cpu, now get its properties.";
308 
309                             crow::connections::systemBus->async_method_call(
310                                 [aResp, service{connection.first},
311                                  path](const boost::system::error_code ec2,
312                                        const std::vector<
313                                            std::pair<std::string, VariantType>>&
314                                            properties) {
315                                     if (ec2)
316                                     {
317                                         BMCWEB_LOG_ERROR
318                                             << "DBUS response error " << ec2;
319                                         messages::internalError(aResp->res);
320                                         return;
321                                     }
322                                     BMCWEB_LOG_DEBUG << "Got "
323                                                      << properties.size()
324                                                      << " Cpu properties.";
325 
326                                     if (properties.size() > 0)
327                                     {
328                                         const uint64_t* processorId = nullptr;
329                                         const std::string* procFamily = nullptr;
330                                         nlohmann::json& procSummary =
331                                             aResp->res.jsonValue["ProcessorSumm"
332                                                                  "ary"];
333                                         nlohmann::json& procCount =
334                                             procSummary["Count"];
335 
336                                         auto procCountPtr = procCount.get_ptr<
337                                             nlohmann::json::
338                                                 number_integer_t*>();
339                                         if (procCountPtr == nullptr)
340                                         {
341                                             messages::internalError(aResp->res);
342                                             return;
343                                         }
344                                         for (const auto& property : properties)
345                                         {
346 
347                                             if (property.first == "Id")
348                                             {
349                                                 processorId =
350                                                     std::get_if<uint64_t>(
351                                                         &property.second);
352                                                 if (nullptr != procFamily)
353                                                 {
354                                                     break;
355                                                 }
356                                                 continue;
357                                             }
358 
359                                             if (property.first == "Family")
360                                             {
361                                                 procFamily =
362                                                     std::get_if<std::string>(
363                                                         &property.second);
364                                                 if (nullptr != processorId)
365                                                 {
366                                                     break;
367                                                 }
368                                                 continue;
369                                             }
370                                         }
371 
372                                         if (procFamily != nullptr &&
373                                             processorId != nullptr)
374                                         {
375                                             if (procCountPtr != nullptr &&
376                                                 *processorId != 0)
377                                             {
378                                                 *procCountPtr += 1;
379                                                 procSummary["Status"]["State"] =
380                                                     "Enabled";
381 
382                                                 procSummary["Model"] =
383                                                     *procFamily;
384                                             }
385                                         }
386                                     }
387                                     else
388                                     {
389                                         auto getCpuPresenceState =
390                                             [aResp](
391                                                 const boost::system::error_code
392                                                     ec3,
393                                                 const std::variant<bool>&
394                                                     cpuPresenceCheck) {
395                                                 if (ec3)
396                                                 {
397                                                     BMCWEB_LOG_ERROR
398                                                         << "DBUS response "
399                                                            "error "
400                                                         << ec3;
401                                                     return;
402                                                 }
403                                                 modifyCpuPresenceState(
404                                                     aResp, cpuPresenceCheck);
405                                             };
406 
407                                         auto getCpuFunctionalState =
408                                             [aResp](
409                                                 const boost::system::error_code
410                                                     ec3,
411                                                 const std::variant<bool>&
412                                                     cpuFunctionalCheck) {
413                                                 if (ec3)
414                                                 {
415                                                     BMCWEB_LOG_ERROR
416                                                         << "DBUS response "
417                                                            "error "
418                                                         << ec3;
419                                                     return;
420                                                 }
421                                                 modifyCpuFunctionalState(
422                                                     aResp, cpuFunctionalCheck);
423                                             };
424                                         // Get the Presence of CPU
425                                         crow::connections::systemBus
426                                             ->async_method_call(
427                                                 std::move(getCpuPresenceState),
428                                                 service, path,
429                                                 "org.freedesktop.DBus."
430                                                 "Properties",
431                                                 "Get",
432                                                 "xyz.openbmc_project.Inventory."
433                                                 "Item",
434                                                 "Present");
435 
436                                         // Get the Functional State
437                                         crow::connections::systemBus
438                                             ->async_method_call(
439                                                 std::move(
440                                                     getCpuFunctionalState),
441                                                 service, path,
442                                                 "org.freedesktop.DBus."
443                                                 "Properties",
444                                                 "Get",
445                                                 "xyz.openbmc_project.State."
446                                                 "Decorator."
447                                                 "OperationalStatus",
448                                                 "Functional");
449 
450                                         // Get the MODEL from
451                                         // xyz.openbmc_project.Inventory.Decorator.Asset
452                                         // support it later as Model  is Empty
453                                         // currently.
454                                     }
455                                 },
456                                 connection.first, path,
457                                 "org.freedesktop.DBus.Properties", "GetAll",
458                                 "xyz.openbmc_project.Inventory.Item.Cpu");
459 
460                             cpuHealth->inventory.emplace_back(path);
461                         }
462                         else if (interfaceName ==
463                                  "xyz.openbmc_project.Common.UUID")
464                         {
465                             BMCWEB_LOG_DEBUG
466                                 << "Found UUID, now get its properties.";
467                             crow::connections::systemBus->async_method_call(
468                                 [aResp](
469                                     const boost::system::error_code ec3,
470                                     const std::vector<
471                                         std::pair<std::string, VariantType>>&
472                                         properties) {
473                                     if (ec3)
474                                     {
475                                         BMCWEB_LOG_DEBUG
476                                             << "DBUS response error " << ec3;
477                                         messages::internalError(aResp->res);
478                                         return;
479                                     }
480                                     BMCWEB_LOG_DEBUG << "Got "
481                                                      << properties.size()
482                                                      << " UUID properties.";
483                                     for (const std::pair<std::string,
484                                                          VariantType>&
485                                              property : properties)
486                                     {
487                                         if (property.first == "UUID")
488                                         {
489                                             const std::string* value =
490                                                 std::get_if<std::string>(
491                                                     &property.second);
492 
493                                             if (value != nullptr)
494                                             {
495                                                 std::string valueStr = *value;
496                                                 if (valueStr.size() == 32)
497                                                 {
498                                                     valueStr.insert(8, 1, '-');
499                                                     valueStr.insert(13, 1, '-');
500                                                     valueStr.insert(18, 1, '-');
501                                                     valueStr.insert(23, 1, '-');
502                                                 }
503                                                 BMCWEB_LOG_DEBUG << "UUID = "
504                                                                  << valueStr;
505                                                 aResp->res.jsonValue["UUID"] =
506                                                     valueStr;
507                                             }
508                                         }
509                                     }
510                                 },
511                                 connection.first, path,
512                                 "org.freedesktop.DBus.Properties", "GetAll",
513                                 "xyz.openbmc_project.Common.UUID");
514                         }
515                         else if (interfaceName ==
516                                  "xyz.openbmc_project.Inventory.Item.System")
517                         {
518                             crow::connections::systemBus->async_method_call(
519                                 [aResp](
520                                     const boost::system::error_code ec2,
521                                     const std::vector<
522                                         std::pair<std::string, VariantType>>&
523                                         propertiesList) {
524                                     if (ec2)
525                                     {
526                                         // doesn't have to include this
527                                         // interface
528                                         return;
529                                     }
530                                     BMCWEB_LOG_DEBUG
531                                         << "Got " << propertiesList.size()
532                                         << " properties for system";
533                                     for (const std::pair<std::string,
534                                                          VariantType>&
535                                              property : propertiesList)
536                                     {
537                                         const std::string& propertyName =
538                                             property.first;
539                                         if ((propertyName == "PartNumber") ||
540                                             (propertyName == "SerialNumber") ||
541                                             (propertyName == "Manufacturer") ||
542                                             (propertyName == "Model") ||
543                                             (propertyName == "SubModel"))
544                                         {
545                                             const std::string* value =
546                                                 std::get_if<std::string>(
547                                                     &property.second);
548                                             if (value != nullptr)
549                                             {
550                                                 aResp->res
551                                                     .jsonValue[propertyName] =
552                                                     *value;
553                                             }
554                                         }
555                                     }
556 
557                                     // Grab the bios version
558                                     fw_util::populateFirmwareInformation(
559                                         aResp, fw_util::biosPurpose,
560                                         "BiosVersion", false);
561                                 },
562                                 connection.first, path,
563                                 "org.freedesktop.DBus.Properties", "GetAll",
564                                 "xyz.openbmc_project.Inventory.Decorator."
565                                 "Asset");
566 
567                             crow::connections::systemBus->async_method_call(
568                                 [aResp](
569                                     const boost::system::error_code ec2,
570                                     const std::variant<std::string>& property) {
571                                     if (ec2)
572                                     {
573                                         // doesn't have to include this
574                                         // interface
575                                         return;
576                                     }
577 
578                                     const std::string* value =
579                                         std::get_if<std::string>(&property);
580                                     if (value != nullptr)
581                                     {
582                                         aResp->res.jsonValue["AssetTag"] =
583                                             *value;
584                                     }
585                                 },
586                                 connection.first, path,
587                                 "org.freedesktop.DBus.Properties", "Get",
588                                 "xyz.openbmc_project.Inventory.Decorator."
589                                 "AssetTag",
590                                 "AssetTag");
591                         }
592                     }
593                 }
594             }
595         },
596         "xyz.openbmc_project.ObjectMapper",
597         "/xyz/openbmc_project/object_mapper",
598         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
599         "/xyz/openbmc_project/inventory", int32_t(0),
600         std::array<const char*, 5>{
601             "xyz.openbmc_project.Inventory.Decorator.Asset",
602             "xyz.openbmc_project.Inventory.Item.Cpu",
603             "xyz.openbmc_project.Inventory.Item.Dimm",
604             "xyz.openbmc_project.Inventory.Item.System",
605             "xyz.openbmc_project.Common.UUID",
606         });
607 }
608 
609 /**
610  * @brief Retrieves host state properties over dbus
611  *
612  * @param[in] aResp     Shared pointer for completing asynchronous calls.
613  *
614  * @return None.
615  */
616 inline void getHostState(const std::shared_ptr<AsyncResp>& aResp)
617 {
618     BMCWEB_LOG_DEBUG << "Get host information.";
619     crow::connections::systemBus->async_method_call(
620         [aResp](const boost::system::error_code ec,
621                 const std::variant<std::string>& hostState) {
622             if (ec)
623             {
624                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
625                 messages::internalError(aResp->res);
626                 return;
627             }
628 
629             const std::string* s = std::get_if<std::string>(&hostState);
630             BMCWEB_LOG_DEBUG << "Host state: " << *s;
631             if (s != nullptr)
632             {
633                 // Verify Host State
634                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
635                 {
636                     aResp->res.jsonValue["PowerState"] = "On";
637                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
638                 }
639                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
640                                "Quiesced")
641                 {
642                     aResp->res.jsonValue["PowerState"] = "On";
643                     aResp->res.jsonValue["Status"]["State"] = "Quiesced";
644                 }
645                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
646                                "DiagnosticMode")
647                 {
648                     aResp->res.jsonValue["PowerState"] = "On";
649                     aResp->res.jsonValue["Status"]["State"] = "InTest";
650                 }
651                 else
652                 {
653                     aResp->res.jsonValue["PowerState"] = "Off";
654                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
655                 }
656             }
657         },
658         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
659         "org.freedesktop.DBus.Properties", "Get",
660         "xyz.openbmc_project.State.Host", "CurrentHostState");
661 }
662 
663 /**
664  * @brief Translates boot source DBUS property value to redfish.
665  *
666  * @param[in] dbusSource    The boot source in DBUS speak.
667  *
668  * @return Returns as a string, the boot source in Redfish terms. If translation
669  * cannot be done, returns an empty string.
670  */
671 inline std::string dbusToRfBootSource(const std::string& dbusSource)
672 {
673     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
674     {
675         return "None";
676     }
677     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
678     {
679         return "Hdd";
680     }
681     if (dbusSource ==
682         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
683     {
684         return "Cd";
685     }
686     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
687     {
688         return "Pxe";
689     }
690     if (dbusSource ==
691         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
692     {
693         return "Usb";
694     }
695     return "";
696 }
697 
698 /**
699  * @brief Translates boot mode DBUS property value to redfish.
700  *
701  * @param[in] dbusMode    The boot mode in DBUS speak.
702  *
703  * @return Returns as a string, the boot mode in Redfish terms. If translation
704  * cannot be done, returns an empty string.
705  */
706 inline std::string dbusToRfBootMode(const std::string& dbusMode)
707 {
708     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
709     {
710         return "None";
711     }
712     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
713     {
714         return "Diags";
715     }
716     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
717     {
718         return "BiosSetup";
719     }
720     return "";
721 }
722 
723 /**
724  * @brief Translates boot source from Redfish to the DBus boot paths.
725  *
726  * @param[in] rfSource    The boot source in Redfish.
727  * @param[out] bootSource The DBus source
728  * @param[out] bootMode   the DBus boot mode
729  *
730  * @return Integer error code.
731  */
732 inline int assignBootParameters(const std::shared_ptr<AsyncResp>& aResp,
733                                 const std::string& rfSource,
734                                 std::string& bootSource, std::string& bootMode)
735 {
736     // The caller has initialized the bootSource and bootMode to:
737     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
738     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
739     // Only modify the bootSource/bootMode variable needed to achieve the
740     // desired boot action.
741 
742     if (rfSource == "None")
743     {
744         return 0;
745     }
746     if (rfSource == "Pxe")
747     {
748         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
749     }
750     else if (rfSource == "Hdd")
751     {
752         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
753     }
754     else if (rfSource == "Diags")
755     {
756         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
757     }
758     else if (rfSource == "Cd")
759     {
760         bootSource =
761             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
762     }
763     else if (rfSource == "BiosSetup")
764     {
765         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
766     }
767     else if (rfSource == "Usb")
768     {
769         bootSource =
770             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
771     }
772     else
773     {
774         BMCWEB_LOG_DEBUG << "Invalid property value for "
775                             "BootSourceOverrideTarget: "
776                          << bootSource;
777         messages::propertyValueNotInList(aResp->res, rfSource,
778                                          "BootSourceTargetOverride");
779         return -1;
780     }
781     return 0;
782 }
783 /**
784  * @brief Retrieves boot progress of the system
785  *
786  * @param[in] aResp  Shared pointer for generating response message.
787  *
788  * @return None.
789  */
790 inline void getBootProgress(const std::shared_ptr<AsyncResp>& aResp)
791 {
792     crow::connections::systemBus->async_method_call(
793         [aResp](const boost::system::error_code ec,
794                 const std::variant<std::string>& bootProgress) {
795             if (ec)
796             {
797                 // BootProgress is an optional object so just do nothing if
798                 // not found
799                 return;
800             }
801 
802             const std::string* bootProgressStr =
803                 std::get_if<std::string>(&bootProgress);
804 
805             if (!bootProgressStr)
806             {
807                 // Interface implemented but property not found, return error
808                 // for that
809                 messages::internalError(aResp->res);
810                 return;
811             }
812 
813             BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
814 
815             // Now convert the D-Bus BootProgress to the appropriate Redfish
816             // enum
817             std::string rfBpLastState = "None";
818             if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress."
819                                     "ProgressStages.Unspecified")
820             {
821                 rfBpLastState = "None";
822             }
823             else if (*bootProgressStr ==
824                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
825                      "PrimaryProcInit")
826             {
827                 rfBpLastState = "PrimaryProcessorInitializationStarted";
828             }
829             else if (*bootProgressStr ==
830                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
831                      "BusInit")
832             {
833                 rfBpLastState = "BusInitializationStarted";
834             }
835             else if (*bootProgressStr ==
836                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
837                      "MemoryInit")
838             {
839                 rfBpLastState = "MemoryInitializationStarted";
840             }
841             else if (*bootProgressStr ==
842                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
843                      "SecondaryProcInit")
844             {
845                 rfBpLastState = "SecondaryProcessorInitializationStarted";
846             }
847             else if (*bootProgressStr ==
848                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
849                      "PCIInit")
850             {
851                 rfBpLastState = "PCIResourceConfigStarted";
852             }
853             else if (*bootProgressStr ==
854                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
855                      "SystemInitComplete")
856             {
857                 rfBpLastState = "SystemHardwareInitializationComplete";
858             }
859             else if (*bootProgressStr ==
860                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
861                      "OSStart")
862             {
863                 rfBpLastState = "OSBootStarted";
864             }
865             else if (*bootProgressStr ==
866                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
867                      "OSRunning")
868             {
869                 rfBpLastState = "OSRunning";
870             }
871             else
872             {
873                 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
874                                  << *bootProgressStr;
875                 // Just return the default
876             }
877 
878             aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
879         },
880         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
881         "org.freedesktop.DBus.Properties", "Get",
882         "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
883 }
884 
885 /**
886  * @brief Retrieves boot mode over DBUS and fills out the response
887  *
888  * @param[in] aResp         Shared pointer for generating response message.
889  * @param[in] bootDbusObj   The dbus object to query for boot properties.
890  *
891  * @return None.
892  */
893 inline void getBootMode(const std::shared_ptr<AsyncResp>& aResp,
894                         const std::string& bootDbusObj)
895 {
896     crow::connections::systemBus->async_method_call(
897         [aResp](const boost::system::error_code ec,
898                 const std::variant<std::string>& bootMode) {
899             if (ec)
900             {
901                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
902                 messages::internalError(aResp->res);
903                 return;
904             }
905 
906             const std::string* bootModeStr =
907                 std::get_if<std::string>(&bootMode);
908 
909             if (!bootModeStr)
910             {
911                 messages::internalError(aResp->res);
912                 return;
913             }
914 
915             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
916 
917             // TODO (Santosh): Do we need to support override mode?
918             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
919             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
920                                          "AllowableValues"] = {
921                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
922 
923             if (*bootModeStr !=
924                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
925             {
926                 auto rfMode = dbusToRfBootMode(*bootModeStr);
927                 if (!rfMode.empty())
928                 {
929                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
930                         rfMode;
931                 }
932             }
933 
934             // If the BootSourceOverrideTarget is still "None" at the end,
935             // reset the BootSourceOverrideEnabled to indicate that
936             // overrides are disabled
937             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
938                 "None")
939             {
940                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
941                     "Disabled";
942             }
943         },
944         "xyz.openbmc_project.Settings", bootDbusObj,
945         "org.freedesktop.DBus.Properties", "Get",
946         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
947 }
948 
949 /**
950  * @brief Retrieves boot source over DBUS
951  *
952  * @param[in] aResp         Shared pointer for generating response message.
953  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
954  *
955  * @return None.
956  */
957 inline void getBootSource(const std::shared_ptr<AsyncResp>& aResp,
958                           bool oneTimeEnabled)
959 {
960     std::string bootDbusObj =
961         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
962                        : "/xyz/openbmc_project/control/host0/boot";
963 
964     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
965     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
966         (oneTimeEnabled) ? "Once" : "Continuous";
967 
968     crow::connections::systemBus->async_method_call(
969         [aResp, bootDbusObj](const boost::system::error_code ec,
970                              const std::variant<std::string>& bootSource) {
971             if (ec)
972             {
973                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
974                 messages::internalError(aResp->res);
975                 return;
976             }
977 
978             const std::string* bootSourceStr =
979                 std::get_if<std::string>(&bootSource);
980 
981             if (!bootSourceStr)
982             {
983                 messages::internalError(aResp->res);
984                 return;
985             }
986             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
987 
988             auto rfSource = dbusToRfBootSource(*bootSourceStr);
989             if (!rfSource.empty())
990             {
991                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
992                     rfSource;
993             }
994         },
995         "xyz.openbmc_project.Settings", bootDbusObj,
996         "org.freedesktop.DBus.Properties", "Get",
997         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
998     getBootMode(aResp, bootDbusObj);
999 }
1000 
1001 /**
1002  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1003  * get boot source and boot mode.
1004  *
1005  * @param[in] aResp     Shared pointer for generating response message.
1006  *
1007  * @return None.
1008  */
1009 inline void getBootProperties(const std::shared_ptr<AsyncResp>& aResp)
1010 {
1011     BMCWEB_LOG_DEBUG << "Get boot information.";
1012 
1013     crow::connections::systemBus->async_method_call(
1014         [aResp](const boost::system::error_code ec,
1015                 const std::variant<bool>& oneTime) {
1016             if (ec)
1017             {
1018                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1019                 // not an error, don't have to have the interface
1020                 return;
1021             }
1022 
1023             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1024 
1025             if (!oneTimePtr)
1026             {
1027                 messages::internalError(aResp->res);
1028                 return;
1029             }
1030             getBootSource(aResp, *oneTimePtr);
1031         },
1032         "xyz.openbmc_project.Settings",
1033         "/xyz/openbmc_project/control/host0/boot/one_time",
1034         "org.freedesktop.DBus.Properties", "Get",
1035         "xyz.openbmc_project.Object.Enable", "Enabled");
1036 }
1037 
1038 /**
1039  * @brief Retrieves the Last Reset Time
1040  *
1041  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1042  * and power off. Even though this is the "system" Redfish object look at the
1043  * chassis D-Bus interface for the LastStateChangeTime since this has the
1044  * last power operation time.
1045  *
1046  * @param[in] aResp     Shared pointer for generating response message.
1047  *
1048  * @return None.
1049  */
1050 inline void getLastResetTime(const std::shared_ptr<AsyncResp>& aResp)
1051 {
1052     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1053 
1054     crow::connections::systemBus->async_method_call(
1055         [aResp](const boost::system::error_code ec,
1056                 std::variant<uint64_t>& lastResetTime) {
1057             if (ec)
1058             {
1059                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1060                 return;
1061             }
1062 
1063             const uint64_t* lastResetTimePtr =
1064                 std::get_if<uint64_t>(&lastResetTime);
1065 
1066             if (!lastResetTimePtr)
1067             {
1068                 messages::internalError(aResp->res);
1069                 return;
1070             }
1071             // LastStateChangeTime is epoch time, in milliseconds
1072             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1073             time_t lastResetTimeStamp =
1074                 static_cast<time_t>(*lastResetTimePtr / 1000);
1075 
1076             // Convert to ISO 8601 standard
1077             aResp->res.jsonValue["LastResetTime"] =
1078                 crow::utility::getDateTime(lastResetTimeStamp);
1079         },
1080         "xyz.openbmc_project.State.Chassis",
1081         "/xyz/openbmc_project/state/chassis0",
1082         "org.freedesktop.DBus.Properties", "Get",
1083         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1084 }
1085 
1086 /**
1087  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1088  *
1089  * @param[in] aResp     Shared pointer for generating response message.
1090  *
1091  * @return None.
1092  */
1093 inline void getAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp)
1094 {
1095     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1096 
1097     crow::connections::systemBus->async_method_call(
1098         [aResp](const boost::system::error_code ec,
1099                 std::variant<bool>& autoRebootEnabled) {
1100             if (ec)
1101             {
1102                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1103                 return;
1104             }
1105 
1106             const bool* autoRebootEnabledPtr =
1107                 std::get_if<bool>(&autoRebootEnabled);
1108 
1109             if (!autoRebootEnabledPtr)
1110             {
1111                 messages::internalError(aResp->res);
1112                 return;
1113             }
1114 
1115             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1116             if (*autoRebootEnabledPtr == true)
1117             {
1118                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1119                     "RetryAttempts";
1120                 // If AutomaticRetry (AutoReboot) is enabled see how many
1121                 // attempts are left
1122                 crow::connections::systemBus->async_method_call(
1123                     [aResp](const boost::system::error_code ec2,
1124                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1125                         if (ec2)
1126                         {
1127                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1128                             return;
1129                         }
1130 
1131                         const uint32_t* autoRebootAttemptsLeftPtr =
1132                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1133 
1134                         if (!autoRebootAttemptsLeftPtr)
1135                         {
1136                             messages::internalError(aResp->res);
1137                             return;
1138                         }
1139 
1140                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1141                                          << *autoRebootAttemptsLeftPtr;
1142 
1143                         aResp->res
1144                             .jsonValue["Boot"]
1145                                       ["RemainingAutomaticRetryAttempts"] =
1146                             *autoRebootAttemptsLeftPtr;
1147                     },
1148                     "xyz.openbmc_project.State.Host",
1149                     "/xyz/openbmc_project/state/host0",
1150                     "org.freedesktop.DBus.Properties", "Get",
1151                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1152                     "AttemptsLeft");
1153             }
1154             else
1155             {
1156                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1157                     "Disabled";
1158             }
1159 
1160             // Not on D-Bus. Hardcoded here:
1161             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1162             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1163 
1164             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1165             // and RetryAttempts. OpenBMC only supports Disabled and
1166             // RetryAttempts.
1167             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1168                                          "AllowableValues"] = {"Disabled",
1169                                                                "RetryAttempts"};
1170         },
1171         "xyz.openbmc_project.Settings",
1172         "/xyz/openbmc_project/control/host0/auto_reboot",
1173         "org.freedesktop.DBus.Properties", "Get",
1174         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1175 }
1176 
1177 /**
1178  * @brief Retrieves power restore policy over DBUS.
1179  *
1180  * @param[in] aResp     Shared pointer for generating response message.
1181  *
1182  * @return None.
1183  */
1184 inline void getPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp)
1185 {
1186     BMCWEB_LOG_DEBUG << "Get power restore policy";
1187 
1188     crow::connections::systemBus->async_method_call(
1189         [aResp](const boost::system::error_code ec,
1190                 std::variant<std::string>& policy) {
1191             if (ec)
1192             {
1193                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1194                 return;
1195             }
1196 
1197             const boost::container::flat_map<std::string, std::string>
1198                 policyMaps = {
1199                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1200                      "AlwaysOn",
1201                      "AlwaysOn"},
1202                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1203                      "AlwaysOff",
1204                      "AlwaysOff"},
1205                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1206                      "LastState",
1207                      "LastState"}};
1208 
1209             const std::string* policyPtr = std::get_if<std::string>(&policy);
1210 
1211             if (!policyPtr)
1212             {
1213                 messages::internalError(aResp->res);
1214                 return;
1215             }
1216 
1217             auto policyMapsIt = policyMaps.find(*policyPtr);
1218             if (policyMapsIt == policyMaps.end())
1219             {
1220                 messages::internalError(aResp->res);
1221                 return;
1222             }
1223 
1224             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1225         },
1226         "xyz.openbmc_project.Settings",
1227         "/xyz/openbmc_project/control/host0/power_restore_policy",
1228         "org.freedesktop.DBus.Properties", "Get",
1229         "xyz.openbmc_project.Control.Power.RestorePolicy",
1230         "PowerRestorePolicy");
1231 }
1232 
1233 /**
1234  * @brief Sets boot properties into DBUS object(s).
1235  *
1236  * @param[in] aResp           Shared pointer for generating response message.
1237  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
1238  * @param[in] bootSource      The boot source to set.
1239  * @param[in] bootEnable      The source override "enable" to set.
1240  *
1241  * @return Integer error code.
1242  */
1243 inline void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
1244                                 bool oneTimeEnabled,
1245                                 const std::optional<std::string>& bootSource,
1246                                 const std::optional<std::string>& bootEnable)
1247 {
1248     std::string bootSourceStr =
1249         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1250     std::string bootModeStr =
1251         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1252     bool oneTimeSetting = oneTimeEnabled;
1253     bool useBootSource = true;
1254 
1255     // Validate incoming parameters
1256     if (bootEnable)
1257     {
1258         if (*bootEnable == "Once")
1259         {
1260             oneTimeSetting = true;
1261         }
1262         else if (*bootEnable == "Continuous")
1263         {
1264             oneTimeSetting = false;
1265         }
1266         else if (*bootEnable == "Disabled")
1267         {
1268             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1269             oneTimeSetting = false;
1270             useBootSource = false;
1271         }
1272         else
1273         {
1274             BMCWEB_LOG_DEBUG << "Unsupported value for "
1275                                 "BootSourceOverrideEnabled: "
1276                              << *bootEnable;
1277             messages::propertyValueNotInList(aResp->res, *bootEnable,
1278                                              "BootSourceOverrideEnabled");
1279             return;
1280         }
1281     }
1282 
1283     if (bootSource && useBootSource)
1284     {
1285         // Source target specified
1286         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1287         // Figure out which DBUS interface and property to use
1288         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1289                                  bootModeStr))
1290         {
1291             BMCWEB_LOG_DEBUG
1292                 << "Invalid property value for BootSourceOverrideTarget: "
1293                 << *bootSource;
1294             messages::propertyValueNotInList(aResp->res, *bootSource,
1295                                              "BootSourceTargetOverride");
1296             return;
1297         }
1298     }
1299 
1300     // Act on validated parameters
1301     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1302     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1303     const char* bootObj =
1304         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1305                        : "/xyz/openbmc_project/control/host0/boot";
1306 
1307     crow::connections::systemBus->async_method_call(
1308         [aResp](const boost::system::error_code ec) {
1309             if (ec)
1310             {
1311                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1312                 messages::internalError(aResp->res);
1313                 return;
1314             }
1315             BMCWEB_LOG_DEBUG << "Boot source update done.";
1316         },
1317         "xyz.openbmc_project.Settings", bootObj,
1318         "org.freedesktop.DBus.Properties", "Set",
1319         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1320         std::variant<std::string>(bootSourceStr));
1321 
1322     crow::connections::systemBus->async_method_call(
1323         [aResp](const boost::system::error_code ec) {
1324             if (ec)
1325             {
1326                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1327                 messages::internalError(aResp->res);
1328                 return;
1329             }
1330             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1331         },
1332         "xyz.openbmc_project.Settings", bootObj,
1333         "org.freedesktop.DBus.Properties", "Set",
1334         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1335         std::variant<std::string>(bootModeStr));
1336 
1337     crow::connections::systemBus->async_method_call(
1338         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1339             if (ec)
1340             {
1341                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1342                 messages::internalError(aResp->res);
1343                 return;
1344             }
1345             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1346         },
1347         "xyz.openbmc_project.Settings",
1348         "/xyz/openbmc_project/control/host0/boot/one_time",
1349         "org.freedesktop.DBus.Properties", "Set",
1350         "xyz.openbmc_project.Object.Enable", "Enabled",
1351         std::variant<bool>(oneTimeSetting));
1352 }
1353 
1354 /**
1355  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1356  * set boot source/boot mode properties.
1357  *
1358  * @param[in] aResp      Shared pointer for generating response message.
1359  * @param[in] bootSource The boot source from incoming RF request.
1360  * @param[in] bootEnable The boot override enable from incoming RF request.
1361  *
1362  * @return Integer error code.
1363  */
1364 inline void setBootSourceProperties(const std::shared_ptr<AsyncResp>& aResp,
1365                                     std::optional<std::string> bootSource,
1366                                     std::optional<std::string> bootEnable)
1367 {
1368     BMCWEB_LOG_DEBUG << "Set boot information.";
1369 
1370     crow::connections::systemBus->async_method_call(
1371         [aResp, bootSource{std::move(bootSource)},
1372          bootEnable{std::move(bootEnable)}](const boost::system::error_code ec,
1373                                             const std::variant<bool>& oneTime) {
1374             if (ec)
1375             {
1376                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1377                 messages::internalError(aResp->res);
1378                 return;
1379             }
1380 
1381             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1382 
1383             if (!oneTimePtr)
1384             {
1385                 messages::internalError(aResp->res);
1386                 return;
1387             }
1388 
1389             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1390 
1391             setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable);
1392         },
1393         "xyz.openbmc_project.Settings",
1394         "/xyz/openbmc_project/control/host0/boot/one_time",
1395         "org.freedesktop.DBus.Properties", "Get",
1396         "xyz.openbmc_project.Object.Enable", "Enabled");
1397 }
1398 
1399 /**
1400  * @brief Sets AssetTag
1401  *
1402  * @param[in] aResp   Shared pointer for generating response message.
1403  * @param[in] assetTag  "AssetTag" from request.
1404  *
1405  * @return None.
1406  */
1407 inline void setAssetTag(const std::shared_ptr<AsyncResp>& aResp,
1408                         const std::string& assetTag)
1409 {
1410     crow::connections::systemBus->async_method_call(
1411         [aResp, assetTag](
1412             const boost::system::error_code ec,
1413             const std::vector<std::pair<
1414                 std::string,
1415                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1416                 subtree) {
1417             if (ec)
1418             {
1419                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1420                 messages::internalError(aResp->res);
1421                 return;
1422             }
1423             if (subtree.size() == 0)
1424             {
1425                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1426                 messages::internalError(aResp->res);
1427                 return;
1428             }
1429             // Assume only 1 system D-Bus object
1430             // Throw an error if there is more than 1
1431             if (subtree.size() > 1)
1432             {
1433                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1434                 messages::internalError(aResp->res);
1435                 return;
1436             }
1437             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1438             {
1439                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1440                 messages::internalError(aResp->res);
1441                 return;
1442             }
1443 
1444             const std::string& path = subtree[0].first;
1445             const std::string& service = subtree[0].second.begin()->first;
1446 
1447             if (service.empty())
1448             {
1449                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1450                 messages::internalError(aResp->res);
1451                 return;
1452             }
1453 
1454             crow::connections::systemBus->async_method_call(
1455                 [aResp](const boost::system::error_code ec2) {
1456                     if (ec2)
1457                     {
1458                         BMCWEB_LOG_DEBUG
1459                             << "D-Bus response error on AssetTag Set " << ec2;
1460                         messages::internalError(aResp->res);
1461                         return;
1462                     }
1463                 },
1464                 service, path, "org.freedesktop.DBus.Properties", "Set",
1465                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1466                 std::variant<std::string>(assetTag));
1467         },
1468         "xyz.openbmc_project.ObjectMapper",
1469         "/xyz/openbmc_project/object_mapper",
1470         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1471         "/xyz/openbmc_project/inventory", int32_t(0),
1472         std::array<const char*, 1>{
1473             "xyz.openbmc_project.Inventory.Item.System"});
1474 }
1475 
1476 /**
1477  * @brief Sets automaticRetry (Auto Reboot)
1478  *
1479  * @param[in] aResp   Shared pointer for generating response message.
1480  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1481  *
1482  * @return None.
1483  */
1484 inline void setAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp,
1485                               const std::string& automaticRetryConfig)
1486 {
1487     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1488 
1489     // OpenBMC only supports "Disabled" and "RetryAttempts".
1490     bool autoRebootEnabled;
1491 
1492     if (automaticRetryConfig == "Disabled")
1493     {
1494         autoRebootEnabled = false;
1495     }
1496     else if (automaticRetryConfig == "RetryAttempts")
1497     {
1498         autoRebootEnabled = true;
1499     }
1500     else
1501     {
1502         BMCWEB_LOG_DEBUG << "Invalid property value for "
1503                             "AutomaticRetryConfig: "
1504                          << automaticRetryConfig;
1505         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1506                                          "AutomaticRetryConfig");
1507         return;
1508     }
1509 
1510     crow::connections::systemBus->async_method_call(
1511         [aResp](const boost::system::error_code ec) {
1512             if (ec)
1513             {
1514                 messages::internalError(aResp->res);
1515                 return;
1516             }
1517         },
1518         "xyz.openbmc_project.Settings",
1519         "/xyz/openbmc_project/control/host0/auto_reboot",
1520         "org.freedesktop.DBus.Properties", "Set",
1521         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1522         std::variant<bool>(autoRebootEnabled));
1523 }
1524 
1525 /**
1526  * @brief Sets power restore policy properties.
1527  *
1528  * @param[in] aResp   Shared pointer for generating response message.
1529  * @param[in] policy  power restore policy properties from request.
1530  *
1531  * @return None.
1532  */
1533 inline void setPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp,
1534                                   std::optional<std::string> policy)
1535 {
1536     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1537 
1538     const boost::container::flat_map<std::string, std::string> policyMaps = {
1539         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1540                      "AlwaysOn"},
1541         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1542                       "AlwaysOff"},
1543         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1544                       "LastState"}};
1545 
1546     std::string powerRestorPolicy;
1547 
1548     auto policyMapsIt = policyMaps.find(*policy);
1549     if (policyMapsIt == policyMaps.end())
1550     {
1551         messages::internalError(aResp->res);
1552         return;
1553     }
1554 
1555     powerRestorPolicy = policyMapsIt->second;
1556 
1557     crow::connections::systemBus->async_method_call(
1558         [aResp](const boost::system::error_code ec) {
1559             if (ec)
1560             {
1561                 messages::internalError(aResp->res);
1562                 return;
1563             }
1564         },
1565         "xyz.openbmc_project.Settings",
1566         "/xyz/openbmc_project/control/host0/power_restore_policy",
1567         "org.freedesktop.DBus.Properties", "Set",
1568         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1569         std::variant<std::string>(powerRestorPolicy));
1570 }
1571 
1572 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1573 /**
1574  * @brief Retrieves provisioning status
1575  *
1576  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1577  *
1578  * @return None.
1579  */
1580 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1581 {
1582     BMCWEB_LOG_DEBUG << "Get OEM information.";
1583     crow::connections::systemBus->async_method_call(
1584         [aResp](const boost::system::error_code ec,
1585                 const std::vector<std::pair<std::string, VariantType>>&
1586                     propertiesList) {
1587             nlohmann::json& oemPFR =
1588                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1589             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1590                 "#OemComputerSystem.OpenBmc";
1591             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1592 
1593             if (ec)
1594             {
1595                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1596                 // not an error, don't have to have the interface
1597                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1598                 return;
1599             }
1600 
1601             const bool* provState = nullptr;
1602             const bool* lockState = nullptr;
1603             for (const std::pair<std::string, VariantType>& property :
1604                  propertiesList)
1605             {
1606                 if (property.first == "UfmProvisioned")
1607                 {
1608                     provState = std::get_if<bool>(&property.second);
1609                 }
1610                 else if (property.first == "UfmLocked")
1611                 {
1612                     lockState = std::get_if<bool>(&property.second);
1613                 }
1614             }
1615 
1616             if ((provState == nullptr) || (lockState == nullptr))
1617             {
1618                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1619                 messages::internalError(aResp->res);
1620                 return;
1621             }
1622 
1623             if (*provState == true)
1624             {
1625                 if (*lockState == true)
1626                 {
1627                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1628                 }
1629                 else
1630                 {
1631                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1632                 }
1633             }
1634             else
1635             {
1636                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1637             }
1638         },
1639         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1640         "org.freedesktop.DBus.Properties", "GetAll",
1641         "xyz.openbmc_project.PFR.Attributes");
1642 }
1643 #endif
1644 
1645 /**
1646  * @brief Translates watchdog timeout action DBUS property value to redfish.
1647  *
1648  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1649  *
1650  * @return Returns as a string, the timeout action in Redfish terms. If
1651  * translation cannot be done, returns an empty string.
1652  */
1653 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
1654 {
1655     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1656     {
1657         return "None";
1658     }
1659     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1660     {
1661         return "ResetSystem";
1662     }
1663     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1664     {
1665         return "PowerDown";
1666     }
1667     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1668     {
1669         return "PowerCycle";
1670     }
1671 
1672     return "";
1673 }
1674 
1675 /**
1676  *@brief Translates timeout action from Redfish to DBUS property value.
1677  *
1678  *@param[in] rfAction The timeout action in Redfish.
1679  *
1680  *@return Returns as a string, the time_out action as expected by DBUS.
1681  *If translation cannot be done, returns an empty string.
1682  */
1683 
1684 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
1685 {
1686     if (rfAction == "None")
1687     {
1688         return "xyz.openbmc_project.State.Watchdog.Action.None";
1689     }
1690     if (rfAction == "PowerCycle")
1691     {
1692         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1693     }
1694     if (rfAction == "PowerDown")
1695     {
1696         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1697     }
1698     if (rfAction == "ResetSystem")
1699     {
1700         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1701     }
1702 
1703     return "";
1704 }
1705 
1706 /**
1707  * @brief Retrieves host watchdog timer properties over DBUS
1708  *
1709  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1710  *
1711  * @return None.
1712  */
1713 inline void getHostWatchdogTimer(const std::shared_ptr<AsyncResp>& aResp)
1714 {
1715     BMCWEB_LOG_DEBUG << "Get host watchodg";
1716     crow::connections::systemBus->async_method_call(
1717         [aResp](const boost::system::error_code ec,
1718                 PropertiesType& properties) {
1719             if (ec)
1720             {
1721                 // watchdog service is stopped
1722                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1723                 return;
1724             }
1725 
1726             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1727 
1728             nlohmann::json& hostWatchdogTimer =
1729                 aResp->res.jsonValue["HostWatchdogTimer"];
1730 
1731             // watchdog service is running/enabled
1732             hostWatchdogTimer["Status"]["State"] = "Enabled";
1733 
1734             for (const auto& property : properties)
1735             {
1736                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1737                 if (property.first == "Enabled")
1738                 {
1739                     const bool* state = std::get_if<bool>(&property.second);
1740 
1741                     if (!state)
1742                     {
1743                         messages::internalError(aResp->res);
1744                         continue;
1745                     }
1746 
1747                     hostWatchdogTimer["FunctionEnabled"] = *state;
1748                 }
1749                 else if (property.first == "ExpireAction")
1750                 {
1751                     const std::string* s =
1752                         std::get_if<std::string>(&property.second);
1753                     if (!s)
1754                     {
1755                         messages::internalError(aResp->res);
1756                         continue;
1757                     }
1758 
1759                     std::string action = dbusToRfWatchdogAction(*s);
1760                     if (action.empty())
1761                     {
1762                         messages::internalError(aResp->res);
1763                         continue;
1764                     }
1765                     hostWatchdogTimer["TimeoutAction"] = action;
1766                 }
1767             }
1768         },
1769         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1770         "org.freedesktop.DBus.Properties", "GetAll",
1771         "xyz.openbmc_project.State.Watchdog");
1772 }
1773 
1774 /**
1775  * @brief Sets Host WatchDog Timer properties.
1776  *
1777  * @param[in] aResp      Shared pointer for generating response message.
1778  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1779  *                       RF request.
1780  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1781  *
1782  * @return None.
1783  */
1784 inline void setWDTProperties(const std::shared_ptr<AsyncResp>& aResp,
1785                              const std::optional<bool> wdtEnable,
1786                              const std::optional<std::string>& wdtTimeOutAction)
1787 {
1788     BMCWEB_LOG_DEBUG << "Set host watchdog";
1789 
1790     if (wdtTimeOutAction)
1791     {
1792         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1793         // check if TimeOut Action is Valid
1794         if (wdtTimeOutActStr.empty())
1795         {
1796             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1797                              << *wdtTimeOutAction;
1798             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1799                                              "TimeoutAction");
1800             return;
1801         }
1802 
1803         crow::connections::systemBus->async_method_call(
1804             [aResp](const boost::system::error_code ec) {
1805                 if (ec)
1806                 {
1807                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1808                     messages::internalError(aResp->res);
1809                     return;
1810                 }
1811             },
1812             "xyz.openbmc_project.Watchdog",
1813             "/xyz/openbmc_project/watchdog/host0",
1814             "org.freedesktop.DBus.Properties", "Set",
1815             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1816             std::variant<std::string>(wdtTimeOutActStr));
1817     }
1818 
1819     if (wdtEnable)
1820     {
1821         crow::connections::systemBus->async_method_call(
1822             [aResp](const boost::system::error_code ec) {
1823                 if (ec)
1824                 {
1825                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1826                     messages::internalError(aResp->res);
1827                     return;
1828                 }
1829             },
1830             "xyz.openbmc_project.Watchdog",
1831             "/xyz/openbmc_project/watchdog/host0",
1832             "org.freedesktop.DBus.Properties", "Set",
1833             "xyz.openbmc_project.State.Watchdog", "Enabled",
1834             std::variant<bool>(*wdtEnable));
1835     }
1836 }
1837 
1838 /**
1839  * SystemsCollection derived class for delivering ComputerSystems Collection
1840  * Schema
1841  */
1842 class SystemsCollection : public Node
1843 {
1844   public:
1845     SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/")
1846     {
1847         entityPrivileges = {
1848             {boost::beast::http::verb::get, {{"Login"}}},
1849             {boost::beast::http::verb::head, {{"Login"}}},
1850             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1851             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1852             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1853             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1854     }
1855 
1856   private:
1857     void doGet(crow::Response& res, const crow::Request&,
1858                const std::vector<std::string>&) override
1859     {
1860         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1861         res.jsonValue["@odata.type"] =
1862             "#ComputerSystemCollection.ComputerSystemCollection";
1863         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1864         res.jsonValue["Name"] = "Computer System Collection";
1865 
1866         crow::connections::systemBus->async_method_call(
1867             [asyncResp](const boost::system::error_code ec,
1868                         const std::variant<std::string>& /*hostName*/) {
1869                 nlohmann::json& ifaceArray =
1870                     asyncResp->res.jsonValue["Members"];
1871                 ifaceArray = nlohmann::json::array();
1872                 auto& count = asyncResp->res.jsonValue["Members@odata.count"];
1873                 ifaceArray.push_back(
1874                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1875                 count = ifaceArray.size();
1876                 if (!ec)
1877                 {
1878                     BMCWEB_LOG_DEBUG << "Hypervisor is available";
1879                     ifaceArray.push_back(
1880                         {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1881                     count = ifaceArray.size();
1882                     return;
1883                 }
1884             },
1885             "xyz.openbmc_project.Settings",
1886             "/xyz/openbmc_project/network/hypervisor",
1887             "org.freedesktop.DBus.Properties", "Get",
1888             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1889     }
1890 };
1891 
1892 /**
1893  * SystemActionsReset class supports handle POST method for Reset action.
1894  * The class retrieves and sends data directly to D-Bus.
1895  */
1896 class SystemActionsReset : public Node
1897 {
1898   public:
1899     SystemActionsReset(App& app) :
1900         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1901     {
1902         entityPrivileges = {
1903             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1904     }
1905 
1906   private:
1907     /**
1908      * Function handles POST method request.
1909      * Analyzes POST body message before sends Reset request data to D-Bus.
1910      */
1911     void doPost(crow::Response& res, const crow::Request& req,
1912                 const std::vector<std::string>&) override
1913     {
1914         auto asyncResp = std::make_shared<AsyncResp>(res);
1915 
1916         std::string resetType;
1917         if (!json_util::readJson(req, res, "ResetType", resetType))
1918         {
1919             return;
1920         }
1921 
1922         // Get the command and host vs. chassis
1923         std::string command;
1924         bool hostCommand;
1925         if ((resetType == "On") || (resetType == "ForceOn"))
1926         {
1927             command = "xyz.openbmc_project.State.Host.Transition.On";
1928             hostCommand = true;
1929         }
1930         else if (resetType == "ForceOff")
1931         {
1932             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1933             hostCommand = false;
1934         }
1935         else if (resetType == "ForceRestart")
1936         {
1937             command =
1938                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1939             hostCommand = true;
1940         }
1941         else if (resetType == "GracefulShutdown")
1942         {
1943             command = "xyz.openbmc_project.State.Host.Transition.Off";
1944             hostCommand = true;
1945         }
1946         else if (resetType == "GracefulRestart")
1947         {
1948             command =
1949                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1950             hostCommand = true;
1951         }
1952         else if (resetType == "PowerCycle")
1953         {
1954             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1955             hostCommand = true;
1956         }
1957         else if (resetType == "Nmi")
1958         {
1959             doNMI(asyncResp);
1960             return;
1961         }
1962         else
1963         {
1964             messages::actionParameterUnknown(res, "Reset", resetType);
1965             return;
1966         }
1967 
1968         if (hostCommand)
1969         {
1970             crow::connections::systemBus->async_method_call(
1971                 [asyncResp, resetType](const boost::system::error_code ec) {
1972                     if (ec)
1973                     {
1974                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1975                         if (ec.value() == boost::asio::error::invalid_argument)
1976                         {
1977                             messages::actionParameterNotSupported(
1978                                 asyncResp->res, resetType, "Reset");
1979                         }
1980                         else
1981                         {
1982                             messages::internalError(asyncResp->res);
1983                         }
1984                         return;
1985                     }
1986                     messages::success(asyncResp->res);
1987                 },
1988                 "xyz.openbmc_project.State.Host",
1989                 "/xyz/openbmc_project/state/host0",
1990                 "org.freedesktop.DBus.Properties", "Set",
1991                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1992                 std::variant<std::string>{command});
1993         }
1994         else
1995         {
1996             crow::connections::systemBus->async_method_call(
1997                 [asyncResp, resetType](const boost::system::error_code ec) {
1998                     if (ec)
1999                     {
2000                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2001                         if (ec.value() == boost::asio::error::invalid_argument)
2002                         {
2003                             messages::actionParameterNotSupported(
2004                                 asyncResp->res, resetType, "Reset");
2005                         }
2006                         else
2007                         {
2008                             messages::internalError(asyncResp->res);
2009                         }
2010                         return;
2011                     }
2012                     messages::success(asyncResp->res);
2013                 },
2014                 "xyz.openbmc_project.State.Chassis",
2015                 "/xyz/openbmc_project/state/chassis0",
2016                 "org.freedesktop.DBus.Properties", "Set",
2017                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2018                 std::variant<std::string>{command});
2019         }
2020     }
2021     /**
2022      * Function transceives data with dbus directly.
2023      */
2024     void doNMI(const std::shared_ptr<AsyncResp>& asyncResp)
2025     {
2026         constexpr char const* serviceName =
2027             "xyz.openbmc_project.Control.Host.NMI";
2028         constexpr char const* objectPath =
2029             "/xyz/openbmc_project/control/host0/nmi";
2030         constexpr char const* interfaceName =
2031             "xyz.openbmc_project.Control.Host.NMI";
2032         constexpr char const* method = "NMI";
2033 
2034         crow::connections::systemBus->async_method_call(
2035             [asyncResp](const boost::system::error_code ec) {
2036                 if (ec)
2037                 {
2038                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2039                     messages::internalError(asyncResp->res);
2040                     return;
2041                 }
2042                 messages::success(asyncResp->res);
2043             },
2044             serviceName, objectPath, interfaceName, method);
2045     }
2046 };
2047 
2048 /**
2049  * Systems derived class for delivering Computer Systems Schema.
2050  */
2051 class Systems : public Node
2052 {
2053   public:
2054     /*
2055      * Default Constructor
2056      */
2057     Systems(App& app) : Node(app, "/redfish/v1/Systems/system/")
2058     {
2059         entityPrivileges = {
2060             {boost::beast::http::verb::get, {{"Login"}}},
2061             {boost::beast::http::verb::head, {{"Login"}}},
2062             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2063             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2064             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2065             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2066     }
2067 
2068   private:
2069     /**
2070      * Functions triggers appropriate requests on DBus
2071      */
2072     void doGet(crow::Response& res, const crow::Request&,
2073                const std::vector<std::string>&) override
2074     {
2075         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_13_0.ComputerSystem";
2076         res.jsonValue["Name"] = "system";
2077         res.jsonValue["Id"] = "system";
2078         res.jsonValue["SystemType"] = "Physical";
2079         res.jsonValue["Description"] = "Computer System";
2080         res.jsonValue["ProcessorSummary"]["Count"] = 0;
2081         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
2082         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
2083         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
2084         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2085 
2086         res.jsonValue["Processors"] = {
2087             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2088         res.jsonValue["Memory"] = {
2089             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2090         res.jsonValue["Storage"] = {
2091             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2092 
2093         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2094             {"target",
2095              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2096             {"@Redfish.ActionInfo",
2097              "/redfish/v1/Systems/system/ResetActionInfo"}};
2098 
2099         res.jsonValue["LogServices"] = {
2100             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2101 
2102         res.jsonValue["Bios"] = {
2103             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2104 
2105         res.jsonValue["Links"]["ManagedBy"] = {
2106             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2107 
2108         res.jsonValue["Status"] = {
2109             {"Health", "OK"},
2110             {"State", "Enabled"},
2111         };
2112         auto asyncResp = std::make_shared<AsyncResp>(res);
2113 
2114         constexpr const std::array<const char*, 4> inventoryForSystems = {
2115             "xyz.openbmc_project.Inventory.Item.Dimm",
2116             "xyz.openbmc_project.Inventory.Item.Cpu",
2117             "xyz.openbmc_project.Inventory.Item.Drive",
2118             "xyz.openbmc_project.Inventory.Item.StorageController"};
2119 
2120         auto health = std::make_shared<HealthPopulate>(asyncResp);
2121         crow::connections::systemBus->async_method_call(
2122             [health](const boost::system::error_code ec,
2123                      std::vector<std::string>& resp) {
2124                 if (ec)
2125                 {
2126                     // no inventory
2127                     return;
2128                 }
2129 
2130                 health->inventory = std::move(resp);
2131             },
2132             "xyz.openbmc_project.ObjectMapper",
2133             "/xyz/openbmc_project/object_mapper",
2134             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2135             int32_t(0), inventoryForSystems);
2136 
2137         health->populate();
2138 
2139         getMainChassisId(asyncResp, [](const std::string& chassisId,
2140                                        const std::shared_ptr<AsyncResp>& aRsp) {
2141             aRsp->res.jsonValue["Links"]["Chassis"] = {
2142                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2143         });
2144 
2145         getLocationIndicatorActive(asyncResp);
2146         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2147         getIndicatorLedState(asyncResp);
2148         getComputerSystem(asyncResp, health);
2149         getHostState(asyncResp);
2150         getBootProperties(asyncResp);
2151         getBootProgress(asyncResp);
2152         getPCIeDeviceList(asyncResp, "PCIeDevices");
2153         getHostWatchdogTimer(asyncResp);
2154         getPowerRestorePolicy(asyncResp);
2155         getAutomaticRetry(asyncResp);
2156         getLastResetTime(asyncResp);
2157 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2158         getProvisioningStatus(asyncResp);
2159 #endif
2160     }
2161 
2162     void doPatch(crow::Response& res, const crow::Request& req,
2163                  const std::vector<std::string>&) override
2164     {
2165         std::optional<bool> locationIndicatorActive;
2166         std::optional<std::string> indicatorLed;
2167         std::optional<nlohmann::json> bootProps;
2168         std::optional<nlohmann::json> wdtTimerProps;
2169         std::optional<std::string> assetTag;
2170         std::optional<std::string> powerRestorePolicy;
2171         auto asyncResp = std::make_shared<AsyncResp>(res);
2172 
2173         if (!json_util::readJson(
2174                 req, res, "IndicatorLED", indicatorLed,
2175                 "LocationIndicatorActive", locationIndicatorActive, "Boot",
2176                 bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy",
2177                 powerRestorePolicy, "AssetTag", assetTag))
2178         {
2179             return;
2180         }
2181 
2182         res.result(boost::beast::http::status::no_content);
2183 
2184         if (assetTag)
2185         {
2186             setAssetTag(asyncResp, *assetTag);
2187         }
2188 
2189         if (wdtTimerProps)
2190         {
2191             std::optional<bool> wdtEnable;
2192             std::optional<std::string> wdtTimeOutAction;
2193 
2194             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2195                                      "FunctionEnabled", wdtEnable,
2196                                      "TimeoutAction", wdtTimeOutAction))
2197             {
2198                 return;
2199             }
2200             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2201         }
2202 
2203         if (bootProps)
2204         {
2205             std::optional<std::string> bootSource;
2206             std::optional<std::string> bootEnable;
2207             std::optional<std::string> automaticRetryConfig;
2208 
2209             if (!json_util::readJson(
2210                     *bootProps, asyncResp->res, "BootSourceOverrideTarget",
2211                     bootSource, "BootSourceOverrideEnabled", bootEnable,
2212                     "AutomaticRetryConfig", automaticRetryConfig))
2213             {
2214                 return;
2215             }
2216             if (bootSource || bootEnable)
2217             {
2218                 setBootSourceProperties(asyncResp, std::move(bootSource),
2219                                         std::move(bootEnable));
2220             }
2221             if (automaticRetryConfig)
2222             {
2223                 setAutomaticRetry(asyncResp, *automaticRetryConfig);
2224             }
2225         }
2226 
2227         if (locationIndicatorActive)
2228         {
2229             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
2230         }
2231 
2232         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2233         if (indicatorLed)
2234         {
2235             setIndicatorLedState(asyncResp, *indicatorLed);
2236             res.addHeader(boost::beast::http::field::warning,
2237                           "299 - \"IndicatorLED is deprecated. Use "
2238                           "LocationIndicatorActive instead.\"");
2239         }
2240 
2241         if (powerRestorePolicy)
2242         {
2243             setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy));
2244         }
2245     }
2246 };
2247 
2248 /**
2249  * SystemResetActionInfo derived class for delivering Computer Systems
2250  * ResetType AllowableValues using ResetInfo schema.
2251  */
2252 class SystemResetActionInfo : public Node
2253 {
2254   public:
2255     /*
2256      * Default Constructor
2257      */
2258     SystemResetActionInfo(App& app) :
2259         Node(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2260     {
2261         entityPrivileges = {
2262             {boost::beast::http::verb::get, {{"Login"}}},
2263             {boost::beast::http::verb::head, {{"Login"}}},
2264             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2265             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2266             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2267             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2268     }
2269 
2270   private:
2271     /**
2272      * Functions triggers appropriate requests on DBus
2273      */
2274     void doGet(crow::Response& res, const crow::Request&,
2275                const std::vector<std::string>&) override
2276     {
2277         res.jsonValue = {
2278             {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2279             {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2280             {"Name", "Reset Action Info"},
2281             {"Id", "ResetActionInfo"},
2282             {"Parameters",
2283              {{{"Name", "ResetType"},
2284                {"Required", true},
2285                {"DataType", "String"},
2286                {"AllowableValues",
2287                 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
2288                  "GracefulShutdown", "PowerCycle", "Nmi"}}}}}};
2289         res.end();
2290     }
2291 };
2292 } // namespace redfish
2293