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