xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision d8ef9915)
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 if (*s == "xyz.openbmc_project.State.Host.HostState."
652                                "TransitioningToRunning")
653                 {
654                     aResp->res.jsonValue["PowerState"] = "PoweringOn";
655                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
656                 }
657                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
658                                "TransitioningToOff")
659                 {
660                     aResp->res.jsonValue["PowerState"] = "PoweringOff";
661                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
662                 }
663                 else
664                 {
665                     aResp->res.jsonValue["PowerState"] = "Off";
666                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
667                 }
668             }
669         },
670         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
671         "org.freedesktop.DBus.Properties", "Get",
672         "xyz.openbmc_project.State.Host", "CurrentHostState");
673 }
674 
675 /**
676  * @brief Translates boot source DBUS property value to redfish.
677  *
678  * @param[in] dbusSource    The boot source in DBUS speak.
679  *
680  * @return Returns as a string, the boot source in Redfish terms. If translation
681  * cannot be done, returns an empty string.
682  */
683 inline std::string dbusToRfBootSource(const std::string& dbusSource)
684 {
685     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
686     {
687         return "None";
688     }
689     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
690     {
691         return "Hdd";
692     }
693     if (dbusSource ==
694         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
695     {
696         return "Cd";
697     }
698     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
699     {
700         return "Pxe";
701     }
702     if (dbusSource ==
703         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
704     {
705         return "Usb";
706     }
707     return "";
708 }
709 
710 /**
711  * @brief Translates boot mode DBUS property value to redfish.
712  *
713  * @param[in] dbusMode    The boot mode in DBUS speak.
714  *
715  * @return Returns as a string, the boot mode in Redfish terms. If translation
716  * cannot be done, returns an empty string.
717  */
718 inline std::string dbusToRfBootMode(const std::string& dbusMode)
719 {
720     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
721     {
722         return "None";
723     }
724     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
725     {
726         return "Diags";
727     }
728     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
729     {
730         return "BiosSetup";
731     }
732     return "";
733 }
734 
735 /**
736  * @brief Translates boot source from Redfish to the DBus boot paths.
737  *
738  * @param[in] rfSource    The boot source in Redfish.
739  * @param[out] bootSource The DBus source
740  * @param[out] bootMode   the DBus boot mode
741  *
742  * @return Integer error code.
743  */
744 inline int assignBootParameters(const std::shared_ptr<AsyncResp>& aResp,
745                                 const std::string& rfSource,
746                                 std::string& bootSource, std::string& bootMode)
747 {
748     // The caller has initialized the bootSource and bootMode to:
749     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
750     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
751     // Only modify the bootSource/bootMode variable needed to achieve the
752     // desired boot action.
753 
754     if (rfSource == "None")
755     {
756         return 0;
757     }
758     if (rfSource == "Pxe")
759     {
760         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
761     }
762     else if (rfSource == "Hdd")
763     {
764         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
765     }
766     else if (rfSource == "Diags")
767     {
768         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
769     }
770     else if (rfSource == "Cd")
771     {
772         bootSource =
773             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
774     }
775     else if (rfSource == "BiosSetup")
776     {
777         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
778     }
779     else if (rfSource == "Usb")
780     {
781         bootSource =
782             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
783     }
784     else
785     {
786         BMCWEB_LOG_DEBUG << "Invalid property value for "
787                             "BootSourceOverrideTarget: "
788                          << bootSource;
789         messages::propertyValueNotInList(aResp->res, rfSource,
790                                          "BootSourceTargetOverride");
791         return -1;
792     }
793     return 0;
794 }
795 /**
796  * @brief Retrieves boot progress of the system
797  *
798  * @param[in] aResp  Shared pointer for generating response message.
799  *
800  * @return None.
801  */
802 inline void getBootProgress(const std::shared_ptr<AsyncResp>& aResp)
803 {
804     crow::connections::systemBus->async_method_call(
805         [aResp](const boost::system::error_code ec,
806                 const std::variant<std::string>& bootProgress) {
807             if (ec)
808             {
809                 // BootProgress is an optional object so just do nothing if
810                 // not found
811                 return;
812             }
813 
814             const std::string* bootProgressStr =
815                 std::get_if<std::string>(&bootProgress);
816 
817             if (!bootProgressStr)
818             {
819                 // Interface implemented but property not found, return error
820                 // for that
821                 messages::internalError(aResp->res);
822                 return;
823             }
824 
825             BMCWEB_LOG_DEBUG << "Boot Progress: " << *bootProgressStr;
826 
827             // Now convert the D-Bus BootProgress to the appropriate Redfish
828             // enum
829             std::string rfBpLastState = "None";
830             if (*bootProgressStr == "xyz.openbmc_project.State.Boot.Progress."
831                                     "ProgressStages.Unspecified")
832             {
833                 rfBpLastState = "None";
834             }
835             else if (*bootProgressStr ==
836                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
837                      "PrimaryProcInit")
838             {
839                 rfBpLastState = "PrimaryProcessorInitializationStarted";
840             }
841             else if (*bootProgressStr ==
842                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
843                      "BusInit")
844             {
845                 rfBpLastState = "BusInitializationStarted";
846             }
847             else if (*bootProgressStr ==
848                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
849                      "MemoryInit")
850             {
851                 rfBpLastState = "MemoryInitializationStarted";
852             }
853             else if (*bootProgressStr ==
854                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
855                      "SecondaryProcInit")
856             {
857                 rfBpLastState = "SecondaryProcessorInitializationStarted";
858             }
859             else if (*bootProgressStr ==
860                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
861                      "PCIInit")
862             {
863                 rfBpLastState = "PCIResourceConfigStarted";
864             }
865             else if (*bootProgressStr ==
866                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
867                      "SystemInitComplete")
868             {
869                 rfBpLastState = "SystemHardwareInitializationComplete";
870             }
871             else if (*bootProgressStr ==
872                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
873                      "OSStart")
874             {
875                 rfBpLastState = "OSBootStarted";
876             }
877             else if (*bootProgressStr ==
878                      "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
879                      "OSRunning")
880             {
881                 rfBpLastState = "OSRunning";
882             }
883             else
884             {
885                 BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
886                                  << *bootProgressStr;
887                 // Just return the default
888             }
889 
890             aResp->res.jsonValue["BootProgress"]["LastState"] = rfBpLastState;
891         },
892         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
893         "org.freedesktop.DBus.Properties", "Get",
894         "xyz.openbmc_project.State.Boot.Progress", "BootProgress");
895 }
896 
897 /**
898  * @brief Retrieves boot mode over DBUS and fills out the response
899  *
900  * @param[in] aResp         Shared pointer for generating response message.
901  * @param[in] bootDbusObj   The dbus object to query for boot properties.
902  *
903  * @return None.
904  */
905 inline void getBootMode(const std::shared_ptr<AsyncResp>& aResp,
906                         const std::string& bootDbusObj)
907 {
908     crow::connections::systemBus->async_method_call(
909         [aResp](const boost::system::error_code ec,
910                 const std::variant<std::string>& bootMode) {
911             if (ec)
912             {
913                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
914                 messages::internalError(aResp->res);
915                 return;
916             }
917 
918             const std::string* bootModeStr =
919                 std::get_if<std::string>(&bootMode);
920 
921             if (!bootModeStr)
922             {
923                 messages::internalError(aResp->res);
924                 return;
925             }
926 
927             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
928 
929             // TODO (Santosh): Do we need to support override mode?
930             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
931             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
932                                          "AllowableValues"] = {
933                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
934 
935             if (*bootModeStr !=
936                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
937             {
938                 auto rfMode = dbusToRfBootMode(*bootModeStr);
939                 if (!rfMode.empty())
940                 {
941                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
942                         rfMode;
943                 }
944             }
945 
946             // If the BootSourceOverrideTarget is still "None" at the end,
947             // reset the BootSourceOverrideEnabled to indicate that
948             // overrides are disabled
949             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
950                 "None")
951             {
952                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
953                     "Disabled";
954             }
955         },
956         "xyz.openbmc_project.Settings", bootDbusObj,
957         "org.freedesktop.DBus.Properties", "Get",
958         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
959 }
960 
961 /**
962  * @brief Retrieves boot source over DBUS
963  *
964  * @param[in] aResp         Shared pointer for generating response message.
965  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
966  *
967  * @return None.
968  */
969 inline void getBootSource(const std::shared_ptr<AsyncResp>& aResp,
970                           bool oneTimeEnabled)
971 {
972     std::string bootDbusObj =
973         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
974                        : "/xyz/openbmc_project/control/host0/boot";
975 
976     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
977     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
978         (oneTimeEnabled) ? "Once" : "Continuous";
979 
980     crow::connections::systemBus->async_method_call(
981         [aResp, bootDbusObj](const boost::system::error_code ec,
982                              const std::variant<std::string>& bootSource) {
983             if (ec)
984             {
985                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
986                 messages::internalError(aResp->res);
987                 return;
988             }
989 
990             const std::string* bootSourceStr =
991                 std::get_if<std::string>(&bootSource);
992 
993             if (!bootSourceStr)
994             {
995                 messages::internalError(aResp->res);
996                 return;
997             }
998             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
999 
1000             auto rfSource = dbusToRfBootSource(*bootSourceStr);
1001             if (!rfSource.empty())
1002             {
1003                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1004                     rfSource;
1005             }
1006         },
1007         "xyz.openbmc_project.Settings", bootDbusObj,
1008         "org.freedesktop.DBus.Properties", "Get",
1009         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
1010     getBootMode(aResp, bootDbusObj);
1011 }
1012 
1013 /**
1014  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1015  * get boot source and boot mode.
1016  *
1017  * @param[in] aResp     Shared pointer for generating response message.
1018  *
1019  * @return None.
1020  */
1021 inline void getBootProperties(const std::shared_ptr<AsyncResp>& aResp)
1022 {
1023     BMCWEB_LOG_DEBUG << "Get boot information.";
1024 
1025     crow::connections::systemBus->async_method_call(
1026         [aResp](const boost::system::error_code ec,
1027                 const std::variant<bool>& oneTime) {
1028             if (ec)
1029             {
1030                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1031                 // not an error, don't have to have the interface
1032                 return;
1033             }
1034 
1035             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1036 
1037             if (!oneTimePtr)
1038             {
1039                 messages::internalError(aResp->res);
1040                 return;
1041             }
1042             getBootSource(aResp, *oneTimePtr);
1043         },
1044         "xyz.openbmc_project.Settings",
1045         "/xyz/openbmc_project/control/host0/boot/one_time",
1046         "org.freedesktop.DBus.Properties", "Get",
1047         "xyz.openbmc_project.Object.Enable", "Enabled");
1048 }
1049 
1050 /**
1051  * @brief Retrieves the Last Reset Time
1052  *
1053  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1054  * and power off. Even though this is the "system" Redfish object look at the
1055  * chassis D-Bus interface for the LastStateChangeTime since this has the
1056  * last power operation time.
1057  *
1058  * @param[in] aResp     Shared pointer for generating response message.
1059  *
1060  * @return None.
1061  */
1062 inline void getLastResetTime(const std::shared_ptr<AsyncResp>& aResp)
1063 {
1064     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1065 
1066     crow::connections::systemBus->async_method_call(
1067         [aResp](const boost::system::error_code ec,
1068                 std::variant<uint64_t>& lastResetTime) {
1069             if (ec)
1070             {
1071                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1072                 return;
1073             }
1074 
1075             const uint64_t* lastResetTimePtr =
1076                 std::get_if<uint64_t>(&lastResetTime);
1077 
1078             if (!lastResetTimePtr)
1079             {
1080                 messages::internalError(aResp->res);
1081                 return;
1082             }
1083             // LastStateChangeTime is epoch time, in milliseconds
1084             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1085             time_t lastResetTimeStamp =
1086                 static_cast<time_t>(*lastResetTimePtr / 1000);
1087 
1088             // Convert to ISO 8601 standard
1089             aResp->res.jsonValue["LastResetTime"] =
1090                 crow::utility::getDateTime(lastResetTimeStamp);
1091         },
1092         "xyz.openbmc_project.State.Chassis",
1093         "/xyz/openbmc_project/state/chassis0",
1094         "org.freedesktop.DBus.Properties", "Get",
1095         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime");
1096 }
1097 
1098 /**
1099  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1100  *
1101  * @param[in] aResp     Shared pointer for generating response message.
1102  *
1103  * @return None.
1104  */
1105 inline void getAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp)
1106 {
1107     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1108 
1109     crow::connections::systemBus->async_method_call(
1110         [aResp](const boost::system::error_code ec,
1111                 std::variant<bool>& autoRebootEnabled) {
1112             if (ec)
1113             {
1114                 BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1115                 return;
1116             }
1117 
1118             const bool* autoRebootEnabledPtr =
1119                 std::get_if<bool>(&autoRebootEnabled);
1120 
1121             if (!autoRebootEnabledPtr)
1122             {
1123                 messages::internalError(aResp->res);
1124                 return;
1125             }
1126 
1127             BMCWEB_LOG_DEBUG << "Auto Reboot: " << *autoRebootEnabledPtr;
1128             if (*autoRebootEnabledPtr == true)
1129             {
1130                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1131                     "RetryAttempts";
1132                 // If AutomaticRetry (AutoReboot) is enabled see how many
1133                 // attempts are left
1134                 crow::connections::systemBus->async_method_call(
1135                     [aResp](const boost::system::error_code ec2,
1136                             std::variant<uint32_t>& autoRebootAttemptsLeft) {
1137                         if (ec2)
1138                         {
1139                             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2;
1140                             return;
1141                         }
1142 
1143                         const uint32_t* autoRebootAttemptsLeftPtr =
1144                             std::get_if<uint32_t>(&autoRebootAttemptsLeft);
1145 
1146                         if (!autoRebootAttemptsLeftPtr)
1147                         {
1148                             messages::internalError(aResp->res);
1149                             return;
1150                         }
1151 
1152                         BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: "
1153                                          << *autoRebootAttemptsLeftPtr;
1154 
1155                         aResp->res
1156                             .jsonValue["Boot"]
1157                                       ["RemainingAutomaticRetryAttempts"] =
1158                             *autoRebootAttemptsLeftPtr;
1159                     },
1160                     "xyz.openbmc_project.State.Host",
1161                     "/xyz/openbmc_project/state/host0",
1162                     "org.freedesktop.DBus.Properties", "Get",
1163                     "xyz.openbmc_project.Control.Boot.RebootAttempts",
1164                     "AttemptsLeft");
1165             }
1166             else
1167             {
1168                 aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1169                     "Disabled";
1170             }
1171 
1172             // Not on D-Bus. Hardcoded here:
1173             // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71
1174             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3;
1175 
1176             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1177             // and RetryAttempts. OpenBMC only supports Disabled and
1178             // RetryAttempts.
1179             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig@Redfish."
1180                                          "AllowableValues"] = {"Disabled",
1181                                                                "RetryAttempts"};
1182         },
1183         "xyz.openbmc_project.Settings",
1184         "/xyz/openbmc_project/control/host0/auto_reboot",
1185         "org.freedesktop.DBus.Properties", "Get",
1186         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot");
1187 }
1188 
1189 /**
1190  * @brief Retrieves power restore policy over DBUS.
1191  *
1192  * @param[in] aResp     Shared pointer for generating response message.
1193  *
1194  * @return None.
1195  */
1196 inline void getPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp)
1197 {
1198     BMCWEB_LOG_DEBUG << "Get power restore policy";
1199 
1200     crow::connections::systemBus->async_method_call(
1201         [aResp](const boost::system::error_code ec,
1202                 std::variant<std::string>& policy) {
1203             if (ec)
1204             {
1205                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1206                 return;
1207             }
1208 
1209             const boost::container::flat_map<std::string, std::string>
1210                 policyMaps = {
1211                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1212                      "AlwaysOn",
1213                      "AlwaysOn"},
1214                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1215                      "AlwaysOff",
1216                      "AlwaysOff"},
1217                     {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1218                      "Restore",
1219                      "LastState"}};
1220 
1221             const std::string* policyPtr = std::get_if<std::string>(&policy);
1222 
1223             if (!policyPtr)
1224             {
1225                 messages::internalError(aResp->res);
1226                 return;
1227             }
1228 
1229             auto policyMapsIt = policyMaps.find(*policyPtr);
1230             if (policyMapsIt == policyMaps.end())
1231             {
1232                 messages::internalError(aResp->res);
1233                 return;
1234             }
1235 
1236             aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1237         },
1238         "xyz.openbmc_project.Settings",
1239         "/xyz/openbmc_project/control/host0/power_restore_policy",
1240         "org.freedesktop.DBus.Properties", "Get",
1241         "xyz.openbmc_project.Control.Power.RestorePolicy",
1242         "PowerRestorePolicy");
1243 }
1244 
1245 /**
1246  * @brief Sets boot properties into DBUS object(s).
1247  *
1248  * @param[in] aResp           Shared pointer for generating response message.
1249  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
1250  * @param[in] bootSource      The boot source to set.
1251  * @param[in] bootEnable      The source override "enable" to set.
1252  *
1253  * @return Integer error code.
1254  */
1255 inline void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
1256                                 bool oneTimeEnabled,
1257                                 const std::optional<std::string>& bootSource,
1258                                 const std::optional<std::string>& bootEnable)
1259 {
1260     std::string bootSourceStr =
1261         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
1262     std::string bootModeStr =
1263         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
1264     bool oneTimeSetting = oneTimeEnabled;
1265     bool useBootSource = true;
1266 
1267     // Validate incoming parameters
1268     if (bootEnable)
1269     {
1270         if (*bootEnable == "Once")
1271         {
1272             oneTimeSetting = true;
1273         }
1274         else if (*bootEnable == "Continuous")
1275         {
1276             oneTimeSetting = false;
1277         }
1278         else if (*bootEnable == "Disabled")
1279         {
1280             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
1281             oneTimeSetting = false;
1282             useBootSource = false;
1283         }
1284         else
1285         {
1286             BMCWEB_LOG_DEBUG << "Unsupported value for "
1287                                 "BootSourceOverrideEnabled: "
1288                              << *bootEnable;
1289             messages::propertyValueNotInList(aResp->res, *bootEnable,
1290                                              "BootSourceOverrideEnabled");
1291             return;
1292         }
1293     }
1294 
1295     if (bootSource && useBootSource)
1296     {
1297         // Source target specified
1298         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1299         // Figure out which DBUS interface and property to use
1300         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
1301                                  bootModeStr))
1302         {
1303             BMCWEB_LOG_DEBUG
1304                 << "Invalid property value for BootSourceOverrideTarget: "
1305                 << *bootSource;
1306             messages::propertyValueNotInList(aResp->res, *bootSource,
1307                                              "BootSourceTargetOverride");
1308             return;
1309         }
1310     }
1311 
1312     // Act on validated parameters
1313     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1314     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1315     const char* bootObj =
1316         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
1317                        : "/xyz/openbmc_project/control/host0/boot";
1318 
1319     crow::connections::systemBus->async_method_call(
1320         [aResp](const boost::system::error_code ec) {
1321             if (ec)
1322             {
1323                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1324                 messages::internalError(aResp->res);
1325                 return;
1326             }
1327             BMCWEB_LOG_DEBUG << "Boot source update done.";
1328         },
1329         "xyz.openbmc_project.Settings", bootObj,
1330         "org.freedesktop.DBus.Properties", "Set",
1331         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1332         std::variant<std::string>(bootSourceStr));
1333 
1334     crow::connections::systemBus->async_method_call(
1335         [aResp](const boost::system::error_code ec) {
1336             if (ec)
1337             {
1338                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1339                 messages::internalError(aResp->res);
1340                 return;
1341             }
1342             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1343         },
1344         "xyz.openbmc_project.Settings", bootObj,
1345         "org.freedesktop.DBus.Properties", "Set",
1346         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1347         std::variant<std::string>(bootModeStr));
1348 
1349     crow::connections::systemBus->async_method_call(
1350         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1351             if (ec)
1352             {
1353                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1354                 messages::internalError(aResp->res);
1355                 return;
1356             }
1357             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1358         },
1359         "xyz.openbmc_project.Settings",
1360         "/xyz/openbmc_project/control/host0/boot/one_time",
1361         "org.freedesktop.DBus.Properties", "Set",
1362         "xyz.openbmc_project.Object.Enable", "Enabled",
1363         std::variant<bool>(oneTimeSetting));
1364 }
1365 
1366 /**
1367  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1368  * set boot source/boot mode properties.
1369  *
1370  * @param[in] aResp      Shared pointer for generating response message.
1371  * @param[in] bootSource The boot source from incoming RF request.
1372  * @param[in] bootEnable The boot override enable from incoming RF request.
1373  *
1374  * @return Integer error code.
1375  */
1376 inline void setBootSourceProperties(const std::shared_ptr<AsyncResp>& aResp,
1377                                     std::optional<std::string> bootSource,
1378                                     std::optional<std::string> bootEnable)
1379 {
1380     BMCWEB_LOG_DEBUG << "Set boot information.";
1381 
1382     crow::connections::systemBus->async_method_call(
1383         [aResp, bootSource{std::move(bootSource)},
1384          bootEnable{std::move(bootEnable)}](const boost::system::error_code ec,
1385                                             const std::variant<bool>& oneTime) {
1386             if (ec)
1387             {
1388                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1389                 messages::internalError(aResp->res);
1390                 return;
1391             }
1392 
1393             const bool* oneTimePtr = std::get_if<bool>(&oneTime);
1394 
1395             if (!oneTimePtr)
1396             {
1397                 messages::internalError(aResp->res);
1398                 return;
1399             }
1400 
1401             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1402 
1403             setBootModeOrSource(aResp, *oneTimePtr, bootSource, bootEnable);
1404         },
1405         "xyz.openbmc_project.Settings",
1406         "/xyz/openbmc_project/control/host0/boot/one_time",
1407         "org.freedesktop.DBus.Properties", "Get",
1408         "xyz.openbmc_project.Object.Enable", "Enabled");
1409 }
1410 
1411 /**
1412  * @brief Sets AssetTag
1413  *
1414  * @param[in] aResp   Shared pointer for generating response message.
1415  * @param[in] assetTag  "AssetTag" from request.
1416  *
1417  * @return None.
1418  */
1419 inline void setAssetTag(const std::shared_ptr<AsyncResp>& aResp,
1420                         const std::string& assetTag)
1421 {
1422     crow::connections::systemBus->async_method_call(
1423         [aResp, assetTag](
1424             const boost::system::error_code ec,
1425             const std::vector<std::pair<
1426                 std::string,
1427                 std::vector<std::pair<std::string, std::vector<std::string>>>>>&
1428                 subtree) {
1429             if (ec)
1430             {
1431                 BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1432                 messages::internalError(aResp->res);
1433                 return;
1434             }
1435             if (subtree.size() == 0)
1436             {
1437                 BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1438                 messages::internalError(aResp->res);
1439                 return;
1440             }
1441             // Assume only 1 system D-Bus object
1442             // Throw an error if there is more than 1
1443             if (subtree.size() > 1)
1444             {
1445                 BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1446                 messages::internalError(aResp->res);
1447                 return;
1448             }
1449             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1450             {
1451                 BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1452                 messages::internalError(aResp->res);
1453                 return;
1454             }
1455 
1456             const std::string& path = subtree[0].first;
1457             const std::string& service = subtree[0].second.begin()->first;
1458 
1459             if (service.empty())
1460             {
1461                 BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1462                 messages::internalError(aResp->res);
1463                 return;
1464             }
1465 
1466             crow::connections::systemBus->async_method_call(
1467                 [aResp](const boost::system::error_code ec2) {
1468                     if (ec2)
1469                     {
1470                         BMCWEB_LOG_DEBUG
1471                             << "D-Bus response error on AssetTag Set " << ec2;
1472                         messages::internalError(aResp->res);
1473                         return;
1474                     }
1475                 },
1476                 service, path, "org.freedesktop.DBus.Properties", "Set",
1477                 "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1478                 std::variant<std::string>(assetTag));
1479         },
1480         "xyz.openbmc_project.ObjectMapper",
1481         "/xyz/openbmc_project/object_mapper",
1482         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
1483         "/xyz/openbmc_project/inventory", int32_t(0),
1484         std::array<const char*, 1>{
1485             "xyz.openbmc_project.Inventory.Item.System"});
1486 }
1487 
1488 /**
1489  * @brief Sets automaticRetry (Auto Reboot)
1490  *
1491  * @param[in] aResp   Shared pointer for generating response message.
1492  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1493  *
1494  * @return None.
1495  */
1496 inline void setAutomaticRetry(const std::shared_ptr<AsyncResp>& aResp,
1497                               const std::string& automaticRetryConfig)
1498 {
1499     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1500 
1501     // OpenBMC only supports "Disabled" and "RetryAttempts".
1502     bool autoRebootEnabled;
1503 
1504     if (automaticRetryConfig == "Disabled")
1505     {
1506         autoRebootEnabled = false;
1507     }
1508     else if (automaticRetryConfig == "RetryAttempts")
1509     {
1510         autoRebootEnabled = true;
1511     }
1512     else
1513     {
1514         BMCWEB_LOG_DEBUG << "Invalid property value for "
1515                             "AutomaticRetryConfig: "
1516                          << automaticRetryConfig;
1517         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1518                                          "AutomaticRetryConfig");
1519         return;
1520     }
1521 
1522     crow::connections::systemBus->async_method_call(
1523         [aResp](const boost::system::error_code ec) {
1524             if (ec)
1525             {
1526                 messages::internalError(aResp->res);
1527                 return;
1528             }
1529         },
1530         "xyz.openbmc_project.Settings",
1531         "/xyz/openbmc_project/control/host0/auto_reboot",
1532         "org.freedesktop.DBus.Properties", "Set",
1533         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1534         std::variant<bool>(autoRebootEnabled));
1535 }
1536 
1537 /**
1538  * @brief Sets power restore policy properties.
1539  *
1540  * @param[in] aResp   Shared pointer for generating response message.
1541  * @param[in] policy  power restore policy properties from request.
1542  *
1543  * @return None.
1544  */
1545 inline void setPowerRestorePolicy(const std::shared_ptr<AsyncResp>& aResp,
1546                                   std::optional<std::string> policy)
1547 {
1548     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1549 
1550     const boost::container::flat_map<std::string, std::string> policyMaps = {
1551         {"AlwaysOn", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1552                      "AlwaysOn"},
1553         {"AlwaysOff", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1554                       "AlwaysOff"},
1555         {"LastState", "xyz.openbmc_project.Control.Power.RestorePolicy.Policy."
1556                       "Restore"}};
1557 
1558     std::string powerRestorPolicy;
1559 
1560     auto policyMapsIt = policyMaps.find(*policy);
1561     if (policyMapsIt == policyMaps.end())
1562     {
1563         messages::internalError(aResp->res);
1564         return;
1565     }
1566 
1567     powerRestorPolicy = policyMapsIt->second;
1568 
1569     crow::connections::systemBus->async_method_call(
1570         [aResp](const boost::system::error_code ec) {
1571             if (ec)
1572             {
1573                 messages::internalError(aResp->res);
1574                 return;
1575             }
1576         },
1577         "xyz.openbmc_project.Settings",
1578         "/xyz/openbmc_project/control/host0/power_restore_policy",
1579         "org.freedesktop.DBus.Properties", "Set",
1580         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1581         std::variant<std::string>(powerRestorPolicy));
1582 }
1583 
1584 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1585 /**
1586  * @brief Retrieves provisioning status
1587  *
1588  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1589  *
1590  * @return None.
1591  */
1592 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1593 {
1594     BMCWEB_LOG_DEBUG << "Get OEM information.";
1595     crow::connections::systemBus->async_method_call(
1596         [aResp](const boost::system::error_code ec,
1597                 const std::vector<std::pair<std::string, VariantType>>&
1598                     propertiesList) {
1599             nlohmann::json& oemPFR =
1600                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1601             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1602                 "#OemComputerSystem.OpenBmc";
1603             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1604 
1605             if (ec)
1606             {
1607                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1608                 // not an error, don't have to have the interface
1609                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1610                 return;
1611             }
1612 
1613             const bool* provState = nullptr;
1614             const bool* lockState = nullptr;
1615             for (const std::pair<std::string, VariantType>& property :
1616                  propertiesList)
1617             {
1618                 if (property.first == "UfmProvisioned")
1619                 {
1620                     provState = std::get_if<bool>(&property.second);
1621                 }
1622                 else if (property.first == "UfmLocked")
1623                 {
1624                     lockState = std::get_if<bool>(&property.second);
1625                 }
1626             }
1627 
1628             if ((provState == nullptr) || (lockState == nullptr))
1629             {
1630                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1631                 messages::internalError(aResp->res);
1632                 return;
1633             }
1634 
1635             if (*provState == true)
1636             {
1637                 if (*lockState == true)
1638                 {
1639                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1640                 }
1641                 else
1642                 {
1643                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1644                 }
1645             }
1646             else
1647             {
1648                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1649             }
1650         },
1651         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1652         "org.freedesktop.DBus.Properties", "GetAll",
1653         "xyz.openbmc_project.PFR.Attributes");
1654 }
1655 #endif
1656 
1657 /**
1658  * @brief Translates watchdog timeout action DBUS property value to redfish.
1659  *
1660  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1661  *
1662  * @return Returns as a string, the timeout action in Redfish terms. If
1663  * translation cannot be done, returns an empty string.
1664  */
1665 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
1666 {
1667     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1668     {
1669         return "None";
1670     }
1671     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1672     {
1673         return "ResetSystem";
1674     }
1675     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1676     {
1677         return "PowerDown";
1678     }
1679     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1680     {
1681         return "PowerCycle";
1682     }
1683 
1684     return "";
1685 }
1686 
1687 /**
1688  *@brief Translates timeout action from Redfish to DBUS property value.
1689  *
1690  *@param[in] rfAction The timeout action in Redfish.
1691  *
1692  *@return Returns as a string, the time_out action as expected by DBUS.
1693  *If translation cannot be done, returns an empty string.
1694  */
1695 
1696 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
1697 {
1698     if (rfAction == "None")
1699     {
1700         return "xyz.openbmc_project.State.Watchdog.Action.None";
1701     }
1702     if (rfAction == "PowerCycle")
1703     {
1704         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1705     }
1706     if (rfAction == "PowerDown")
1707     {
1708         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1709     }
1710     if (rfAction == "ResetSystem")
1711     {
1712         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1713     }
1714 
1715     return "";
1716 }
1717 
1718 /**
1719  * @brief Retrieves host watchdog timer properties over DBUS
1720  *
1721  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1722  *
1723  * @return None.
1724  */
1725 inline void getHostWatchdogTimer(const std::shared_ptr<AsyncResp>& aResp)
1726 {
1727     BMCWEB_LOG_DEBUG << "Get host watchodg";
1728     crow::connections::systemBus->async_method_call(
1729         [aResp](const boost::system::error_code ec,
1730                 PropertiesType& properties) {
1731             if (ec)
1732             {
1733                 // watchdog service is stopped
1734                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1735                 return;
1736             }
1737 
1738             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1739 
1740             nlohmann::json& hostWatchdogTimer =
1741                 aResp->res.jsonValue["HostWatchdogTimer"];
1742 
1743             // watchdog service is running/enabled
1744             hostWatchdogTimer["Status"]["State"] = "Enabled";
1745 
1746             for (const auto& property : properties)
1747             {
1748                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1749                 if (property.first == "Enabled")
1750                 {
1751                     const bool* state = std::get_if<bool>(&property.second);
1752 
1753                     if (!state)
1754                     {
1755                         messages::internalError(aResp->res);
1756                         continue;
1757                     }
1758 
1759                     hostWatchdogTimer["FunctionEnabled"] = *state;
1760                 }
1761                 else if (property.first == "ExpireAction")
1762                 {
1763                     const std::string* s =
1764                         std::get_if<std::string>(&property.second);
1765                     if (!s)
1766                     {
1767                         messages::internalError(aResp->res);
1768                         continue;
1769                     }
1770 
1771                     std::string action = dbusToRfWatchdogAction(*s);
1772                     if (action.empty())
1773                     {
1774                         messages::internalError(aResp->res);
1775                         continue;
1776                     }
1777                     hostWatchdogTimer["TimeoutAction"] = action;
1778                 }
1779             }
1780         },
1781         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1782         "org.freedesktop.DBus.Properties", "GetAll",
1783         "xyz.openbmc_project.State.Watchdog");
1784 }
1785 
1786 /**
1787  * @brief Sets Host WatchDog Timer properties.
1788  *
1789  * @param[in] aResp      Shared pointer for generating response message.
1790  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1791  *                       RF request.
1792  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1793  *
1794  * @return None.
1795  */
1796 inline void setWDTProperties(const std::shared_ptr<AsyncResp>& aResp,
1797                              const std::optional<bool> wdtEnable,
1798                              const std::optional<std::string>& wdtTimeOutAction)
1799 {
1800     BMCWEB_LOG_DEBUG << "Set host watchdog";
1801 
1802     if (wdtTimeOutAction)
1803     {
1804         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1805         // check if TimeOut Action is Valid
1806         if (wdtTimeOutActStr.empty())
1807         {
1808             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1809                              << *wdtTimeOutAction;
1810             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1811                                              "TimeoutAction");
1812             return;
1813         }
1814 
1815         crow::connections::systemBus->async_method_call(
1816             [aResp](const boost::system::error_code ec) {
1817                 if (ec)
1818                 {
1819                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1820                     messages::internalError(aResp->res);
1821                     return;
1822                 }
1823             },
1824             "xyz.openbmc_project.Watchdog",
1825             "/xyz/openbmc_project/watchdog/host0",
1826             "org.freedesktop.DBus.Properties", "Set",
1827             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1828             std::variant<std::string>(wdtTimeOutActStr));
1829     }
1830 
1831     if (wdtEnable)
1832     {
1833         crow::connections::systemBus->async_method_call(
1834             [aResp](const boost::system::error_code ec) {
1835                 if (ec)
1836                 {
1837                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1838                     messages::internalError(aResp->res);
1839                     return;
1840                 }
1841             },
1842             "xyz.openbmc_project.Watchdog",
1843             "/xyz/openbmc_project/watchdog/host0",
1844             "org.freedesktop.DBus.Properties", "Set",
1845             "xyz.openbmc_project.State.Watchdog", "Enabled",
1846             std::variant<bool>(*wdtEnable));
1847     }
1848 }
1849 
1850 /**
1851  * SystemsCollection derived class for delivering ComputerSystems Collection
1852  * Schema
1853  */
1854 class SystemsCollection : public Node
1855 {
1856   public:
1857     SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/")
1858     {
1859         entityPrivileges = {
1860             {boost::beast::http::verb::get, {{"Login"}}},
1861             {boost::beast::http::verb::head, {{"Login"}}},
1862             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1863             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1864             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1865             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1866     }
1867 
1868   private:
1869     void doGet(crow::Response& res, const crow::Request&,
1870                const std::vector<std::string>&) override
1871     {
1872         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1873         res.jsonValue["@odata.type"] =
1874             "#ComputerSystemCollection.ComputerSystemCollection";
1875         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1876         res.jsonValue["Name"] = "Computer System Collection";
1877 
1878         crow::connections::systemBus->async_method_call(
1879             [asyncResp](const boost::system::error_code ec,
1880                         const std::variant<std::string>& /*hostName*/) {
1881                 nlohmann::json& ifaceArray =
1882                     asyncResp->res.jsonValue["Members"];
1883                 ifaceArray = nlohmann::json::array();
1884                 auto& count = asyncResp->res.jsonValue["Members@odata.count"];
1885                 ifaceArray.push_back(
1886                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1887                 count = ifaceArray.size();
1888                 if (!ec)
1889                 {
1890                     BMCWEB_LOG_DEBUG << "Hypervisor is available";
1891                     ifaceArray.push_back(
1892                         {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1893                     count = ifaceArray.size();
1894                     return;
1895                 }
1896             },
1897             "xyz.openbmc_project.Settings",
1898             "/xyz/openbmc_project/network/hypervisor",
1899             "org.freedesktop.DBus.Properties", "Get",
1900             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1901     }
1902 };
1903 
1904 /**
1905  * SystemActionsReset class supports handle POST method for Reset action.
1906  * The class retrieves and sends data directly to D-Bus.
1907  */
1908 class SystemActionsReset : public Node
1909 {
1910   public:
1911     SystemActionsReset(App& app) :
1912         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1913     {
1914         entityPrivileges = {
1915             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1916     }
1917 
1918   private:
1919     /**
1920      * Function handles POST method request.
1921      * Analyzes POST body message before sends Reset request data to D-Bus.
1922      */
1923     void doPost(crow::Response& res, const crow::Request& req,
1924                 const std::vector<std::string>&) override
1925     {
1926         auto asyncResp = std::make_shared<AsyncResp>(res);
1927 
1928         std::string resetType;
1929         if (!json_util::readJson(req, res, "ResetType", resetType))
1930         {
1931             return;
1932         }
1933 
1934         // Get the command and host vs. chassis
1935         std::string command;
1936         bool hostCommand;
1937         if ((resetType == "On") || (resetType == "ForceOn"))
1938         {
1939             command = "xyz.openbmc_project.State.Host.Transition.On";
1940             hostCommand = true;
1941         }
1942         else if (resetType == "ForceOff")
1943         {
1944             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1945             hostCommand = false;
1946         }
1947         else if (resetType == "ForceRestart")
1948         {
1949             command =
1950                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1951             hostCommand = true;
1952         }
1953         else if (resetType == "GracefulShutdown")
1954         {
1955             command = "xyz.openbmc_project.State.Host.Transition.Off";
1956             hostCommand = true;
1957         }
1958         else if (resetType == "GracefulRestart")
1959         {
1960             command =
1961                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1962             hostCommand = true;
1963         }
1964         else if (resetType == "PowerCycle")
1965         {
1966             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1967             hostCommand = true;
1968         }
1969         else if (resetType == "Nmi")
1970         {
1971             doNMI(asyncResp);
1972             return;
1973         }
1974         else
1975         {
1976             messages::actionParameterUnknown(res, "Reset", resetType);
1977             return;
1978         }
1979 
1980         if (hostCommand)
1981         {
1982             crow::connections::systemBus->async_method_call(
1983                 [asyncResp, resetType](const boost::system::error_code ec) {
1984                     if (ec)
1985                     {
1986                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1987                         if (ec.value() == boost::asio::error::invalid_argument)
1988                         {
1989                             messages::actionParameterNotSupported(
1990                                 asyncResp->res, resetType, "Reset");
1991                         }
1992                         else
1993                         {
1994                             messages::internalError(asyncResp->res);
1995                         }
1996                         return;
1997                     }
1998                     messages::success(asyncResp->res);
1999                 },
2000                 "xyz.openbmc_project.State.Host",
2001                 "/xyz/openbmc_project/state/host0",
2002                 "org.freedesktop.DBus.Properties", "Set",
2003                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2004                 std::variant<std::string>{command});
2005         }
2006         else
2007         {
2008             crow::connections::systemBus->async_method_call(
2009                 [asyncResp, resetType](const boost::system::error_code ec) {
2010                     if (ec)
2011                     {
2012                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2013                         if (ec.value() == boost::asio::error::invalid_argument)
2014                         {
2015                             messages::actionParameterNotSupported(
2016                                 asyncResp->res, resetType, "Reset");
2017                         }
2018                         else
2019                         {
2020                             messages::internalError(asyncResp->res);
2021                         }
2022                         return;
2023                     }
2024                     messages::success(asyncResp->res);
2025                 },
2026                 "xyz.openbmc_project.State.Chassis",
2027                 "/xyz/openbmc_project/state/chassis0",
2028                 "org.freedesktop.DBus.Properties", "Set",
2029                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2030                 std::variant<std::string>{command});
2031         }
2032     }
2033     /**
2034      * Function transceives data with dbus directly.
2035      */
2036     void doNMI(const std::shared_ptr<AsyncResp>& asyncResp)
2037     {
2038         constexpr char const* serviceName =
2039             "xyz.openbmc_project.Control.Host.NMI";
2040         constexpr char const* objectPath =
2041             "/xyz/openbmc_project/control/host0/nmi";
2042         constexpr char const* interfaceName =
2043             "xyz.openbmc_project.Control.Host.NMI";
2044         constexpr char const* method = "NMI";
2045 
2046         crow::connections::systemBus->async_method_call(
2047             [asyncResp](const boost::system::error_code ec) {
2048                 if (ec)
2049                 {
2050                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2051                     messages::internalError(asyncResp->res);
2052                     return;
2053                 }
2054                 messages::success(asyncResp->res);
2055             },
2056             serviceName, objectPath, interfaceName, method);
2057     }
2058 };
2059 
2060 /**
2061  * Systems derived class for delivering Computer Systems Schema.
2062  */
2063 class Systems : public Node
2064 {
2065   public:
2066     /*
2067      * Default Constructor
2068      */
2069     Systems(App& app) : Node(app, "/redfish/v1/Systems/system/")
2070     {
2071         entityPrivileges = {
2072             {boost::beast::http::verb::get, {{"Login"}}},
2073             {boost::beast::http::verb::head, {{"Login"}}},
2074             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2075             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2076             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2077             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2078     }
2079 
2080   private:
2081     /**
2082      * Functions triggers appropriate requests on DBus
2083      */
2084     void doGet(crow::Response& res, const crow::Request&,
2085                const std::vector<std::string>&) override
2086     {
2087         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_13_0.ComputerSystem";
2088         res.jsonValue["Name"] = "system";
2089         res.jsonValue["Id"] = "system";
2090         res.jsonValue["SystemType"] = "Physical";
2091         res.jsonValue["Description"] = "Computer System";
2092         res.jsonValue["ProcessorSummary"]["Count"] = 0;
2093         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
2094         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
2095         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
2096         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2097 
2098         res.jsonValue["Processors"] = {
2099             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2100         res.jsonValue["Memory"] = {
2101             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2102         res.jsonValue["Storage"] = {
2103             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2104 
2105         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2106             {"target",
2107              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2108             {"@Redfish.ActionInfo",
2109              "/redfish/v1/Systems/system/ResetActionInfo"}};
2110 
2111         res.jsonValue["LogServices"] = {
2112             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2113 
2114         res.jsonValue["Bios"] = {
2115             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2116 
2117         res.jsonValue["Links"]["ManagedBy"] = {
2118             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2119 
2120         res.jsonValue["Status"] = {
2121             {"Health", "OK"},
2122             {"State", "Enabled"},
2123         };
2124         auto asyncResp = std::make_shared<AsyncResp>(res);
2125 
2126         constexpr const std::array<const char*, 4> inventoryForSystems = {
2127             "xyz.openbmc_project.Inventory.Item.Dimm",
2128             "xyz.openbmc_project.Inventory.Item.Cpu",
2129             "xyz.openbmc_project.Inventory.Item.Drive",
2130             "xyz.openbmc_project.Inventory.Item.StorageController"};
2131 
2132         auto health = std::make_shared<HealthPopulate>(asyncResp);
2133         crow::connections::systemBus->async_method_call(
2134             [health](const boost::system::error_code ec,
2135                      std::vector<std::string>& resp) {
2136                 if (ec)
2137                 {
2138                     // no inventory
2139                     return;
2140                 }
2141 
2142                 health->inventory = std::move(resp);
2143             },
2144             "xyz.openbmc_project.ObjectMapper",
2145             "/xyz/openbmc_project/object_mapper",
2146             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2147             int32_t(0), inventoryForSystems);
2148 
2149         health->populate();
2150 
2151         getMainChassisId(asyncResp, [](const std::string& chassisId,
2152                                        const std::shared_ptr<AsyncResp>& aRsp) {
2153             aRsp->res.jsonValue["Links"]["Chassis"] = {
2154                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2155         });
2156 
2157         getLocationIndicatorActive(asyncResp);
2158         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2159         getIndicatorLedState(asyncResp);
2160         getComputerSystem(asyncResp, health);
2161         getHostState(asyncResp);
2162         getBootProperties(asyncResp);
2163         getBootProgress(asyncResp);
2164         getPCIeDeviceList(asyncResp, "PCIeDevices");
2165         getHostWatchdogTimer(asyncResp);
2166         getPowerRestorePolicy(asyncResp);
2167         getAutomaticRetry(asyncResp);
2168         getLastResetTime(asyncResp);
2169 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2170         getProvisioningStatus(asyncResp);
2171 #endif
2172     }
2173 
2174     void doPatch(crow::Response& res, const crow::Request& req,
2175                  const std::vector<std::string>&) override
2176     {
2177         std::optional<bool> locationIndicatorActive;
2178         std::optional<std::string> indicatorLed;
2179         std::optional<nlohmann::json> bootProps;
2180         std::optional<nlohmann::json> wdtTimerProps;
2181         std::optional<std::string> assetTag;
2182         std::optional<std::string> powerRestorePolicy;
2183         auto asyncResp = std::make_shared<AsyncResp>(res);
2184 
2185         if (!json_util::readJson(
2186                 req, res, "IndicatorLED", indicatorLed,
2187                 "LocationIndicatorActive", locationIndicatorActive, "Boot",
2188                 bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy",
2189                 powerRestorePolicy, "AssetTag", assetTag))
2190         {
2191             return;
2192         }
2193 
2194         res.result(boost::beast::http::status::no_content);
2195 
2196         if (assetTag)
2197         {
2198             setAssetTag(asyncResp, *assetTag);
2199         }
2200 
2201         if (wdtTimerProps)
2202         {
2203             std::optional<bool> wdtEnable;
2204             std::optional<std::string> wdtTimeOutAction;
2205 
2206             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2207                                      "FunctionEnabled", wdtEnable,
2208                                      "TimeoutAction", wdtTimeOutAction))
2209             {
2210                 return;
2211             }
2212             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2213         }
2214 
2215         if (bootProps)
2216         {
2217             std::optional<std::string> bootSource;
2218             std::optional<std::string> bootEnable;
2219             std::optional<std::string> automaticRetryConfig;
2220 
2221             if (!json_util::readJson(
2222                     *bootProps, asyncResp->res, "BootSourceOverrideTarget",
2223                     bootSource, "BootSourceOverrideEnabled", bootEnable,
2224                     "AutomaticRetryConfig", automaticRetryConfig))
2225             {
2226                 return;
2227             }
2228             if (bootSource || bootEnable)
2229             {
2230                 setBootSourceProperties(asyncResp, std::move(bootSource),
2231                                         std::move(bootEnable));
2232             }
2233             if (automaticRetryConfig)
2234             {
2235                 setAutomaticRetry(asyncResp, *automaticRetryConfig);
2236             }
2237         }
2238 
2239         if (locationIndicatorActive)
2240         {
2241             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
2242         }
2243 
2244         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2245         if (indicatorLed)
2246         {
2247             setIndicatorLedState(asyncResp, *indicatorLed);
2248             res.addHeader(boost::beast::http::field::warning,
2249                           "299 - \"IndicatorLED is deprecated. Use "
2250                           "LocationIndicatorActive instead.\"");
2251         }
2252 
2253         if (powerRestorePolicy)
2254         {
2255             setPowerRestorePolicy(asyncResp, std::move(*powerRestorePolicy));
2256         }
2257     }
2258 };
2259 
2260 /**
2261  * SystemResetActionInfo derived class for delivering Computer Systems
2262  * ResetType AllowableValues using ResetInfo schema.
2263  */
2264 class SystemResetActionInfo : public Node
2265 {
2266   public:
2267     /*
2268      * Default Constructor
2269      */
2270     SystemResetActionInfo(App& app) :
2271         Node(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2272     {
2273         entityPrivileges = {
2274             {boost::beast::http::verb::get, {{"Login"}}},
2275             {boost::beast::http::verb::head, {{"Login"}}},
2276             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2277             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2278             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2279             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2280     }
2281 
2282   private:
2283     /**
2284      * Functions triggers appropriate requests on DBus
2285      */
2286     void doGet(crow::Response& res, const crow::Request&,
2287                const std::vector<std::string>&) override
2288     {
2289         res.jsonValue = {
2290             {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2291             {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2292             {"Name", "Reset Action Info"},
2293             {"Id", "ResetActionInfo"},
2294             {"Parameters",
2295              {{{"Name", "ResetType"},
2296                {"Required", true},
2297                {"DataType", "String"},
2298                {"AllowableValues",
2299                 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
2300                  "GracefulShutdown", "PowerCycle", "Nmi"}}}}}};
2301         res.end();
2302     }
2303 };
2304 } // namespace redfish
2305