xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 4e69c9040b996b48b6e361ac8caed47e91b71a83)
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                                   const 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::propertyValueNotInList(aResp->res, policy,
1564                                          "PowerRestorePolicy");
1565         return;
1566     }
1567 
1568     powerRestorPolicy = policyMapsIt->second;
1569 
1570     crow::connections::systemBus->async_method_call(
1571         [aResp](const boost::system::error_code ec) {
1572             if (ec)
1573             {
1574                 messages::internalError(aResp->res);
1575                 return;
1576             }
1577         },
1578         "xyz.openbmc_project.Settings",
1579         "/xyz/openbmc_project/control/host0/power_restore_policy",
1580         "org.freedesktop.DBus.Properties", "Set",
1581         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1582         std::variant<std::string>(powerRestorPolicy));
1583 }
1584 
1585 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1586 /**
1587  * @brief Retrieves provisioning status
1588  *
1589  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1590  *
1591  * @return None.
1592  */
1593 inline void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1594 {
1595     BMCWEB_LOG_DEBUG << "Get OEM information.";
1596     crow::connections::systemBus->async_method_call(
1597         [aResp](const boost::system::error_code ec,
1598                 const std::vector<std::pair<std::string, VariantType>>&
1599                     propertiesList) {
1600             nlohmann::json& oemPFR =
1601                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1602             aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1603                 "#OemComputerSystem.OpenBmc";
1604             oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1605 
1606             if (ec)
1607             {
1608                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1609                 // not an error, don't have to have the interface
1610                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1611                 return;
1612             }
1613 
1614             const bool* provState = nullptr;
1615             const bool* lockState = nullptr;
1616             for (const std::pair<std::string, VariantType>& property :
1617                  propertiesList)
1618             {
1619                 if (property.first == "UfmProvisioned")
1620                 {
1621                     provState = std::get_if<bool>(&property.second);
1622                 }
1623                 else if (property.first == "UfmLocked")
1624                 {
1625                     lockState = std::get_if<bool>(&property.second);
1626                 }
1627             }
1628 
1629             if ((provState == nullptr) || (lockState == nullptr))
1630             {
1631                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1632                 messages::internalError(aResp->res);
1633                 return;
1634             }
1635 
1636             if (*provState == true)
1637             {
1638                 if (*lockState == true)
1639                 {
1640                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1641                 }
1642                 else
1643                 {
1644                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1645                 }
1646             }
1647             else
1648             {
1649                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1650             }
1651         },
1652         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1653         "org.freedesktop.DBus.Properties", "GetAll",
1654         "xyz.openbmc_project.PFR.Attributes");
1655 }
1656 #endif
1657 
1658 /**
1659  * @brief Translates watchdog timeout action DBUS property value to redfish.
1660  *
1661  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1662  *
1663  * @return Returns as a string, the timeout action in Redfish terms. If
1664  * translation cannot be done, returns an empty string.
1665  */
1666 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
1667 {
1668     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1669     {
1670         return "None";
1671     }
1672     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1673     {
1674         return "ResetSystem";
1675     }
1676     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1677     {
1678         return "PowerDown";
1679     }
1680     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1681     {
1682         return "PowerCycle";
1683     }
1684 
1685     return "";
1686 }
1687 
1688 /**
1689  *@brief Translates timeout action from Redfish to DBUS property value.
1690  *
1691  *@param[in] rfAction The timeout action in Redfish.
1692  *
1693  *@return Returns as a string, the time_out action as expected by DBUS.
1694  *If translation cannot be done, returns an empty string.
1695  */
1696 
1697 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
1698 {
1699     if (rfAction == "None")
1700     {
1701         return "xyz.openbmc_project.State.Watchdog.Action.None";
1702     }
1703     if (rfAction == "PowerCycle")
1704     {
1705         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1706     }
1707     if (rfAction == "PowerDown")
1708     {
1709         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1710     }
1711     if (rfAction == "ResetSystem")
1712     {
1713         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1714     }
1715 
1716     return "";
1717 }
1718 
1719 /**
1720  * @brief Retrieves host watchdog timer properties over DBUS
1721  *
1722  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1723  *
1724  * @return None.
1725  */
1726 inline void getHostWatchdogTimer(const std::shared_ptr<AsyncResp>& aResp)
1727 {
1728     BMCWEB_LOG_DEBUG << "Get host watchodg";
1729     crow::connections::systemBus->async_method_call(
1730         [aResp](const boost::system::error_code ec,
1731                 PropertiesType& properties) {
1732             if (ec)
1733             {
1734                 // watchdog service is stopped
1735                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1736                 return;
1737             }
1738 
1739             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1740 
1741             nlohmann::json& hostWatchdogTimer =
1742                 aResp->res.jsonValue["HostWatchdogTimer"];
1743 
1744             // watchdog service is running/enabled
1745             hostWatchdogTimer["Status"]["State"] = "Enabled";
1746 
1747             for (const auto& property : properties)
1748             {
1749                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1750                 if (property.first == "Enabled")
1751                 {
1752                     const bool* state = std::get_if<bool>(&property.second);
1753 
1754                     if (!state)
1755                     {
1756                         messages::internalError(aResp->res);
1757                         continue;
1758                     }
1759 
1760                     hostWatchdogTimer["FunctionEnabled"] = *state;
1761                 }
1762                 else if (property.first == "ExpireAction")
1763                 {
1764                     const std::string* s =
1765                         std::get_if<std::string>(&property.second);
1766                     if (!s)
1767                     {
1768                         messages::internalError(aResp->res);
1769                         continue;
1770                     }
1771 
1772                     std::string action = dbusToRfWatchdogAction(*s);
1773                     if (action.empty())
1774                     {
1775                         messages::internalError(aResp->res);
1776                         continue;
1777                     }
1778                     hostWatchdogTimer["TimeoutAction"] = action;
1779                 }
1780             }
1781         },
1782         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1783         "org.freedesktop.DBus.Properties", "GetAll",
1784         "xyz.openbmc_project.State.Watchdog");
1785 }
1786 
1787 /**
1788  * @brief Sets Host WatchDog Timer properties.
1789  *
1790  * @param[in] aResp      Shared pointer for generating response message.
1791  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1792  *                       RF request.
1793  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1794  *
1795  * @return None.
1796  */
1797 inline void setWDTProperties(const std::shared_ptr<AsyncResp>& aResp,
1798                              const std::optional<bool> wdtEnable,
1799                              const std::optional<std::string>& wdtTimeOutAction)
1800 {
1801     BMCWEB_LOG_DEBUG << "Set host watchdog";
1802 
1803     if (wdtTimeOutAction)
1804     {
1805         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1806         // check if TimeOut Action is Valid
1807         if (wdtTimeOutActStr.empty())
1808         {
1809             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1810                              << *wdtTimeOutAction;
1811             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1812                                              "TimeoutAction");
1813             return;
1814         }
1815 
1816         crow::connections::systemBus->async_method_call(
1817             [aResp](const boost::system::error_code ec) {
1818                 if (ec)
1819                 {
1820                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1821                     messages::internalError(aResp->res);
1822                     return;
1823                 }
1824             },
1825             "xyz.openbmc_project.Watchdog",
1826             "/xyz/openbmc_project/watchdog/host0",
1827             "org.freedesktop.DBus.Properties", "Set",
1828             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1829             std::variant<std::string>(wdtTimeOutActStr));
1830     }
1831 
1832     if (wdtEnable)
1833     {
1834         crow::connections::systemBus->async_method_call(
1835             [aResp](const boost::system::error_code ec) {
1836                 if (ec)
1837                 {
1838                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1839                     messages::internalError(aResp->res);
1840                     return;
1841                 }
1842             },
1843             "xyz.openbmc_project.Watchdog",
1844             "/xyz/openbmc_project/watchdog/host0",
1845             "org.freedesktop.DBus.Properties", "Set",
1846             "xyz.openbmc_project.State.Watchdog", "Enabled",
1847             std::variant<bool>(*wdtEnable));
1848     }
1849 }
1850 
1851 /**
1852  * SystemsCollection derived class for delivering ComputerSystems Collection
1853  * Schema
1854  */
1855 class SystemsCollection : public Node
1856 {
1857   public:
1858     SystemsCollection(App& app) : Node(app, "/redfish/v1/Systems/")
1859     {
1860         entityPrivileges = {
1861             {boost::beast::http::verb::get, {{"Login"}}},
1862             {boost::beast::http::verb::head, {{"Login"}}},
1863             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1864             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1865             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1866             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1867     }
1868 
1869   private:
1870     void doGet(crow::Response& res, const crow::Request&,
1871                const std::vector<std::string>&) override
1872     {
1873         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1874         res.jsonValue["@odata.type"] =
1875             "#ComputerSystemCollection.ComputerSystemCollection";
1876         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1877         res.jsonValue["Name"] = "Computer System Collection";
1878 
1879         crow::connections::systemBus->async_method_call(
1880             [asyncResp](const boost::system::error_code ec,
1881                         const std::variant<std::string>& /*hostName*/) {
1882                 nlohmann::json& ifaceArray =
1883                     asyncResp->res.jsonValue["Members"];
1884                 ifaceArray = nlohmann::json::array();
1885                 auto& count = asyncResp->res.jsonValue["Members@odata.count"];
1886                 ifaceArray.push_back(
1887                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1888                 count = ifaceArray.size();
1889                 if (!ec)
1890                 {
1891                     BMCWEB_LOG_DEBUG << "Hypervisor is available";
1892                     ifaceArray.push_back(
1893                         {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1894                     count = ifaceArray.size();
1895                     return;
1896                 }
1897             },
1898             "xyz.openbmc_project.Settings",
1899             "/xyz/openbmc_project/network/hypervisor",
1900             "org.freedesktop.DBus.Properties", "Get",
1901             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1902     }
1903 };
1904 
1905 /**
1906  * SystemActionsReset class supports handle POST method for Reset action.
1907  * The class retrieves and sends data directly to D-Bus.
1908  */
1909 class SystemActionsReset : public Node
1910 {
1911   public:
1912     SystemActionsReset(App& app) :
1913         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1914     {
1915         entityPrivileges = {
1916             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1917     }
1918 
1919   private:
1920     /**
1921      * Function handles POST method request.
1922      * Analyzes POST body message before sends Reset request data to D-Bus.
1923      */
1924     void doPost(crow::Response& res, const crow::Request& req,
1925                 const std::vector<std::string>&) override
1926     {
1927         auto asyncResp = std::make_shared<AsyncResp>(res);
1928 
1929         std::string resetType;
1930         if (!json_util::readJson(req, res, "ResetType", resetType))
1931         {
1932             return;
1933         }
1934 
1935         // Get the command and host vs. chassis
1936         std::string command;
1937         bool hostCommand;
1938         if ((resetType == "On") || (resetType == "ForceOn"))
1939         {
1940             command = "xyz.openbmc_project.State.Host.Transition.On";
1941             hostCommand = true;
1942         }
1943         else if (resetType == "ForceOff")
1944         {
1945             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1946             hostCommand = false;
1947         }
1948         else if (resetType == "ForceRestart")
1949         {
1950             command =
1951                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1952             hostCommand = true;
1953         }
1954         else if (resetType == "GracefulShutdown")
1955         {
1956             command = "xyz.openbmc_project.State.Host.Transition.Off";
1957             hostCommand = true;
1958         }
1959         else if (resetType == "GracefulRestart")
1960         {
1961             command =
1962                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1963             hostCommand = true;
1964         }
1965         else if (resetType == "PowerCycle")
1966         {
1967             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1968             hostCommand = true;
1969         }
1970         else if (resetType == "Nmi")
1971         {
1972             doNMI(asyncResp);
1973             return;
1974         }
1975         else
1976         {
1977             messages::actionParameterUnknown(res, "Reset", resetType);
1978             return;
1979         }
1980 
1981         if (hostCommand)
1982         {
1983             crow::connections::systemBus->async_method_call(
1984                 [asyncResp, resetType](const boost::system::error_code ec) {
1985                     if (ec)
1986                     {
1987                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1988                         if (ec.value() == boost::asio::error::invalid_argument)
1989                         {
1990                             messages::actionParameterNotSupported(
1991                                 asyncResp->res, resetType, "Reset");
1992                         }
1993                         else
1994                         {
1995                             messages::internalError(asyncResp->res);
1996                         }
1997                         return;
1998                     }
1999                     messages::success(asyncResp->res);
2000                 },
2001                 "xyz.openbmc_project.State.Host",
2002                 "/xyz/openbmc_project/state/host0",
2003                 "org.freedesktop.DBus.Properties", "Set",
2004                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2005                 std::variant<std::string>{command});
2006         }
2007         else
2008         {
2009             crow::connections::systemBus->async_method_call(
2010                 [asyncResp, resetType](const boost::system::error_code ec) {
2011                     if (ec)
2012                     {
2013                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2014                         if (ec.value() == boost::asio::error::invalid_argument)
2015                         {
2016                             messages::actionParameterNotSupported(
2017                                 asyncResp->res, resetType, "Reset");
2018                         }
2019                         else
2020                         {
2021                             messages::internalError(asyncResp->res);
2022                         }
2023                         return;
2024                     }
2025                     messages::success(asyncResp->res);
2026                 },
2027                 "xyz.openbmc_project.State.Chassis",
2028                 "/xyz/openbmc_project/state/chassis0",
2029                 "org.freedesktop.DBus.Properties", "Set",
2030                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2031                 std::variant<std::string>{command});
2032         }
2033     }
2034     /**
2035      * Function transceives data with dbus directly.
2036      */
2037     void doNMI(const std::shared_ptr<AsyncResp>& asyncResp)
2038     {
2039         constexpr char const* serviceName =
2040             "xyz.openbmc_project.Control.Host.NMI";
2041         constexpr char const* objectPath =
2042             "/xyz/openbmc_project/control/host0/nmi";
2043         constexpr char const* interfaceName =
2044             "xyz.openbmc_project.Control.Host.NMI";
2045         constexpr char const* method = "NMI";
2046 
2047         crow::connections::systemBus->async_method_call(
2048             [asyncResp](const boost::system::error_code ec) {
2049                 if (ec)
2050                 {
2051                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2052                     messages::internalError(asyncResp->res);
2053                     return;
2054                 }
2055                 messages::success(asyncResp->res);
2056             },
2057             serviceName, objectPath, interfaceName, method);
2058     }
2059 };
2060 
2061 /**
2062  * Systems derived class for delivering Computer Systems Schema.
2063  */
2064 class Systems : public Node
2065 {
2066   public:
2067     /*
2068      * Default Constructor
2069      */
2070     Systems(App& app) : Node(app, "/redfish/v1/Systems/system/")
2071     {
2072         entityPrivileges = {
2073             {boost::beast::http::verb::get, {{"Login"}}},
2074             {boost::beast::http::verb::head, {{"Login"}}},
2075             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2076             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2077             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2078             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2079     }
2080 
2081   private:
2082     /**
2083      * Functions triggers appropriate requests on DBus
2084      */
2085     void doGet(crow::Response& res, const crow::Request&,
2086                const std::vector<std::string>&) override
2087     {
2088         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_13_0.ComputerSystem";
2089         res.jsonValue["Name"] = "system";
2090         res.jsonValue["Id"] = "system";
2091         res.jsonValue["SystemType"] = "Physical";
2092         res.jsonValue["Description"] = "Computer System";
2093         res.jsonValue["ProcessorSummary"]["Count"] = 0;
2094         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
2095         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
2096         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
2097         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
2098 
2099         res.jsonValue["Processors"] = {
2100             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2101         res.jsonValue["Memory"] = {
2102             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2103         res.jsonValue["Storage"] = {
2104             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2105 
2106         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2107             {"target",
2108              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2109             {"@Redfish.ActionInfo",
2110              "/redfish/v1/Systems/system/ResetActionInfo"}};
2111 
2112         res.jsonValue["LogServices"] = {
2113             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2114 
2115         res.jsonValue["Bios"] = {
2116             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2117 
2118         res.jsonValue["Links"]["ManagedBy"] = {
2119             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2120 
2121         res.jsonValue["Status"] = {
2122             {"Health", "OK"},
2123             {"State", "Enabled"},
2124         };
2125         auto asyncResp = std::make_shared<AsyncResp>(res);
2126 
2127         constexpr const std::array<const char*, 4> inventoryForSystems = {
2128             "xyz.openbmc_project.Inventory.Item.Dimm",
2129             "xyz.openbmc_project.Inventory.Item.Cpu",
2130             "xyz.openbmc_project.Inventory.Item.Drive",
2131             "xyz.openbmc_project.Inventory.Item.StorageController"};
2132 
2133         auto health = std::make_shared<HealthPopulate>(asyncResp);
2134         crow::connections::systemBus->async_method_call(
2135             [health](const boost::system::error_code ec,
2136                      std::vector<std::string>& resp) {
2137                 if (ec)
2138                 {
2139                     // no inventory
2140                     return;
2141                 }
2142 
2143                 health->inventory = std::move(resp);
2144             },
2145             "xyz.openbmc_project.ObjectMapper",
2146             "/xyz/openbmc_project/object_mapper",
2147             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2148             int32_t(0), inventoryForSystems);
2149 
2150         health->populate();
2151 
2152         getMainChassisId(asyncResp, [](const std::string& chassisId,
2153                                        const std::shared_ptr<AsyncResp>& aRsp) {
2154             aRsp->res.jsonValue["Links"]["Chassis"] = {
2155                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2156         });
2157 
2158         getLocationIndicatorActive(asyncResp);
2159         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2160         getIndicatorLedState(asyncResp);
2161         getComputerSystem(asyncResp, health);
2162         getHostState(asyncResp);
2163         getBootProperties(asyncResp);
2164         getBootProgress(asyncResp);
2165         getPCIeDeviceList(asyncResp, "PCIeDevices");
2166         getHostWatchdogTimer(asyncResp);
2167         getPowerRestorePolicy(asyncResp);
2168         getAutomaticRetry(asyncResp);
2169         getLastResetTime(asyncResp);
2170 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2171         getProvisioningStatus(asyncResp);
2172 #endif
2173     }
2174 
2175     void doPatch(crow::Response& res, const crow::Request& req,
2176                  const std::vector<std::string>&) override
2177     {
2178         std::optional<bool> locationIndicatorActive;
2179         std::optional<std::string> indicatorLed;
2180         std::optional<nlohmann::json> bootProps;
2181         std::optional<nlohmann::json> wdtTimerProps;
2182         std::optional<std::string> assetTag;
2183         std::optional<std::string> powerRestorePolicy;
2184         auto asyncResp = std::make_shared<AsyncResp>(res);
2185 
2186         if (!json_util::readJson(
2187                 req, res, "IndicatorLED", indicatorLed,
2188                 "LocationIndicatorActive", locationIndicatorActive, "Boot",
2189                 bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy",
2190                 powerRestorePolicy, "AssetTag", assetTag))
2191         {
2192             return;
2193         }
2194 
2195         res.result(boost::beast::http::status::no_content);
2196 
2197         if (assetTag)
2198         {
2199             setAssetTag(asyncResp, *assetTag);
2200         }
2201 
2202         if (wdtTimerProps)
2203         {
2204             std::optional<bool> wdtEnable;
2205             std::optional<std::string> wdtTimeOutAction;
2206 
2207             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2208                                      "FunctionEnabled", wdtEnable,
2209                                      "TimeoutAction", wdtTimeOutAction))
2210             {
2211                 return;
2212             }
2213             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2214         }
2215 
2216         if (bootProps)
2217         {
2218             std::optional<std::string> bootSource;
2219             std::optional<std::string> bootEnable;
2220             std::optional<std::string> automaticRetryConfig;
2221 
2222             if (!json_util::readJson(
2223                     *bootProps, asyncResp->res, "BootSourceOverrideTarget",
2224                     bootSource, "BootSourceOverrideEnabled", bootEnable,
2225                     "AutomaticRetryConfig", automaticRetryConfig))
2226             {
2227                 return;
2228             }
2229             if (bootSource || bootEnable)
2230             {
2231                 setBootSourceProperties(asyncResp, std::move(bootSource),
2232                                         std::move(bootEnable));
2233             }
2234             if (automaticRetryConfig)
2235             {
2236                 setAutomaticRetry(asyncResp, *automaticRetryConfig);
2237             }
2238         }
2239 
2240         if (locationIndicatorActive)
2241         {
2242             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
2243         }
2244 
2245         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2246         if (indicatorLed)
2247         {
2248             setIndicatorLedState(asyncResp, *indicatorLed);
2249             res.addHeader(boost::beast::http::field::warning,
2250                           "299 - \"IndicatorLED is deprecated. Use "
2251                           "LocationIndicatorActive instead.\"");
2252         }
2253 
2254         if (powerRestorePolicy)
2255         {
2256             setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
2257         }
2258     }
2259 };
2260 
2261 /**
2262  * SystemResetActionInfo derived class for delivering Computer Systems
2263  * ResetType AllowableValues using ResetInfo schema.
2264  */
2265 class SystemResetActionInfo : public Node
2266 {
2267   public:
2268     /*
2269      * Default Constructor
2270      */
2271     SystemResetActionInfo(App& app) :
2272         Node(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2273     {
2274         entityPrivileges = {
2275             {boost::beast::http::verb::get, {{"Login"}}},
2276             {boost::beast::http::verb::head, {{"Login"}}},
2277             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
2278             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
2279             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
2280             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
2281     }
2282 
2283   private:
2284     /**
2285      * Functions triggers appropriate requests on DBus
2286      */
2287     void doGet(crow::Response& res, const crow::Request&,
2288                const std::vector<std::string>&) override
2289     {
2290         res.jsonValue = {
2291             {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2292             {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2293             {"Name", "Reset Action Info"},
2294             {"Id", "ResetActionInfo"},
2295             {"Parameters",
2296              {{{"Name", "ResetType"},
2297                {"Required", true},
2298                {"DataType", "String"},
2299                {"AllowableValues",
2300                 {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
2301                  "GracefulShutdown", "PowerCycle", "Nmi"}}}}}};
2302         res.end();
2303     }
2304 };
2305 } // namespace redfish
2306