xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 462023addac00b521fc2e59ae53080046438ddfa)
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 #include <variant>
28 
29 namespace redfish
30 {
31 
32 /**
33  * @brief Updates the Functional State of DIMMs
34  *
35  * @param[in] aResp Shared pointer for completing asynchronous calls
36  * @param[in] dimmState Dimm's Functional state, true/false
37  *
38  * @return None.
39  */
40 void updateDimmProperties(std::shared_ptr<AsyncResp> aResp,
41                           const std::variant<bool> &dimmState)
42 {
43     const bool *isDimmFunctional = std::get_if<bool>(&dimmState);
44     if (isDimmFunctional == nullptr)
45     {
46         messages::internalError(aResp->res);
47         return;
48     }
49     BMCWEB_LOG_DEBUG << "Dimm Functional: " << *isDimmFunctional;
50 
51     // Set it as Enabled if atleast one DIMM is functional
52     // Update STATE only if previous State was DISABLED and current Dimm is
53     // ENABLED.
54     nlohmann::json &prevMemSummary =
55         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
56     if (prevMemSummary == "Disabled")
57     {
58         if (*isDimmFunctional == true)
59         {
60             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
61                 "Enabled";
62         }
63     }
64 }
65 
66 /*
67  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
68  *
69  * @param[in] aResp Shared pointer for completing asynchronous calls
70  * @param[in] cpuPresenceState CPU present or not
71  *
72  * @return None.
73  */
74 void modifyCpuPresenceState(std::shared_ptr<AsyncResp> aResp,
75                             const std::variant<bool> &cpuPresenceState)
76 {
77     const bool *isCpuPresent = std::get_if<bool>(&cpuPresenceState);
78 
79     if (isCpuPresent == nullptr)
80     {
81         messages::internalError(aResp->res);
82         return;
83     }
84     BMCWEB_LOG_DEBUG << "Cpu Present: " << *isCpuPresent;
85 
86     if (*isCpuPresent == true)
87     {
88         nlohmann::json &procCount =
89             aResp->res.jsonValue["ProcessorSummary"]["Count"];
90         auto procCountPtr =
91             procCount.get_ptr<nlohmann::json::number_integer_t *>();
92         if (procCountPtr != nullptr)
93         {
94             // shouldn't be possible to be nullptr
95             *procCountPtr += 1;
96         }
97     }
98 }
99 
100 /*
101  * @brief Update "ProcessorSummary" "Status" "State" based on
102  *        CPU Functional State
103  *
104  * @param[in] aResp Shared pointer for completing asynchronous calls
105  * @param[in] cpuFunctionalState is CPU functional true/false
106  *
107  * @return None.
108  */
109 void modifyCpuFunctionalState(std::shared_ptr<AsyncResp> aResp,
110                               const std::variant<bool> &cpuFunctionalState)
111 {
112     const bool *isCpuFunctional = std::get_if<bool>(&cpuFunctionalState);
113 
114     if (isCpuFunctional == nullptr)
115     {
116         messages::internalError(aResp->res);
117         return;
118     }
119     BMCWEB_LOG_DEBUG << "Cpu Functional: " << *isCpuFunctional;
120 
121     nlohmann::json &prevProcState =
122         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
123 
124     // Set it as Enabled if atleast one CPU is functional
125     // Update STATE only if previous State was Non_Functional and current CPU is
126     // Functional.
127     if (prevProcState == "Disabled")
128     {
129         if (*isCpuFunctional == true)
130         {
131             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
132                 "Enabled";
133         }
134     }
135 }
136 
137 /*
138  * @brief Retrieves computer system properties over dbus
139  *
140  * @param[in] aResp Shared pointer for completing asynchronous calls
141  * @param[in] name  Computer system name from request
142  *
143  * @return None.
144  */
145 void getComputerSystem(std::shared_ptr<AsyncResp> aResp,
146                        std::shared_ptr<HealthPopulate> systemHealth)
147 {
148     BMCWEB_LOG_DEBUG << "Get available system components.";
149 
150     crow::connections::systemBus->async_method_call(
151         [aResp, systemHealth](
152             const boost::system::error_code ec,
153             const std::vector<std::pair<
154                 std::string,
155                 std::vector<std::pair<std::string, std::vector<std::string>>>>>
156                 &subtree) {
157             if (ec)
158             {
159                 BMCWEB_LOG_DEBUG << "DBUS response error";
160                 messages::internalError(aResp->res);
161                 return;
162             }
163             // Iterate over all retrieved ObjectPaths.
164             for (const std::pair<std::string,
165                                  std::vector<std::pair<
166                                      std::string, std::vector<std::string>>>>
167                      &object : subtree)
168             {
169                 const std::string &path = object.first;
170                 BMCWEB_LOG_DEBUG << "Got path: " << path;
171                 const std::vector<
172                     std::pair<std::string, std::vector<std::string>>>
173                     &connectionNames = object.second;
174                 if (connectionNames.size() < 1)
175                 {
176                     continue;
177                 }
178 
179                 auto memoryHealth = std::make_shared<HealthPopulate>(
180                     aResp, aResp->res.jsonValue["MemorySummary"]["Status"]);
181 
182                 auto cpuHealth = std::make_shared<HealthPopulate>(
183                     aResp, aResp->res.jsonValue["ProcessorSummary"]["Status"]);
184 
185                 systemHealth->children.emplace_back(memoryHealth);
186                 systemHealth->children.emplace_back(cpuHealth);
187 
188                 // This is not system, so check if it's cpu, dimm, UUID or
189                 // BiosVer
190                 for (const auto &connection : connectionNames)
191                 {
192                     for (const auto &interfaceName : connection.second)
193                     {
194                         if (interfaceName ==
195                             "xyz.openbmc_project.Inventory.Item.Dimm")
196                         {
197                             BMCWEB_LOG_DEBUG
198                                 << "Found Dimm, now get its properties.";
199 
200                             crow::connections::systemBus->async_method_call(
201                                 [aResp, service{connection.first},
202                                  path(std::move(path))](
203                                     const boost::system::error_code ec,
204                                     const std::vector<
205                                         std::pair<std::string, VariantType>>
206                                         &properties) {
207                                     if (ec)
208                                     {
209                                         BMCWEB_LOG_ERROR
210                                             << "DBUS response error " << ec;
211                                         messages::internalError(aResp->res);
212                                         return;
213                                     }
214                                     BMCWEB_LOG_DEBUG << "Got "
215                                                      << properties.size()
216                                                      << " Dimm properties.";
217 
218                                     if (properties.size() > 0)
219                                     {
220                                         for (const std::pair<std::string,
221                                                              VariantType>
222                                                  &property : properties)
223                                         {
224                                             if (property.first !=
225                                                 "MemorySizeInKB")
226                                             {
227                                                 continue;
228                                             }
229                                             const uint32_t *value =
230                                                 sdbusplus::message::variant_ns::
231                                                     get_if<uint32_t>(
232                                                         &property.second);
233                                             if (value == nullptr)
234                                             {
235                                                 BMCWEB_LOG_DEBUG
236                                                     << "Find incorrect type of "
237                                                        "MemorySize";
238                                                 continue;
239                                             }
240                                             nlohmann::json &totalMemory =
241                                                 aResp->res
242                                                     .jsonValue["MemorySummar"
243                                                                "y"]
244                                                               ["TotalSystemMe"
245                                                                "moryGiB"];
246                                             uint64_t *preValue =
247                                                 totalMemory
248                                                     .get_ptr<uint64_t *>();
249                                             if (preValue == nullptr)
250                                             {
251                                                 continue;
252                                             }
253                                             aResp->res
254                                                 .jsonValue["MemorySummary"]
255                                                           ["TotalSystemMemoryGi"
256                                                            "B"] =
257                                                 *value / (1024 * 1024) +
258                                                 *preValue;
259                                             aResp->res
260                                                 .jsonValue["MemorySummary"]
261                                                           ["Status"]["State"] =
262                                                 "Enabled";
263                                         }
264                                     }
265                                     else
266                                     {
267                                         auto getDimmProperties =
268                                             [aResp](
269                                                 const boost::system::error_code
270                                                     ec,
271                                                 const std::variant<bool>
272                                                     &dimmState) {
273                                                 if (ec)
274                                                 {
275                                                     BMCWEB_LOG_ERROR
276                                                         << "DBUS response "
277                                                            "error "
278                                                         << ec;
279                                                     return;
280                                                 }
281                                                 updateDimmProperties(aResp,
282                                                                      dimmState);
283                                             };
284                                         crow::connections::systemBus
285                                             ->async_method_call(
286                                                 std::move(getDimmProperties),
287                                                 service, path,
288                                                 "org.freedesktop.DBus."
289                                                 "Properties",
290                                                 "Get",
291                                                 "xyz.openbmc_project.State."
292                                                 "Decorator.OperationalStatus",
293                                                 "Functional");
294                                     }
295                                 },
296                                 connection.first, path,
297                                 "org.freedesktop.DBus.Properties", "GetAll",
298                                 "xyz.openbmc_project.Inventory.Item.Dimm");
299 
300                             memoryHealth->inventory.emplace_back(path);
301                         }
302                         else if (interfaceName ==
303                                  "xyz.openbmc_project.Inventory.Item.Cpu")
304                         {
305                             BMCWEB_LOG_DEBUG
306                                 << "Found Cpu, now get its properties.";
307 
308                             crow::connections::systemBus->async_method_call(
309                                 [aResp, service{connection.first},
310                                  path(std::move(path))](
311                                     const boost::system::error_code ec,
312                                     const std::vector<
313                                         std::pair<std::string, VariantType>>
314                                         &properties) {
315                                     if (ec)
316                                     {
317                                         BMCWEB_LOG_ERROR
318                                             << "DBUS response error " << ec;
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                                         for (const auto &property : properties)
329                                         {
330                                             if (property.first ==
331                                                 "ProcessorFamily")
332                                             {
333                                                 const std::string *value =
334                                                     sdbusplus::message::
335                                                         variant_ns::get_if<
336                                                             std::string>(
337                                                             &property.second);
338                                                 if (value != nullptr)
339                                                 {
340                                                     nlohmann::json
341                                                         &procSummary =
342                                                             aResp->res.jsonValue
343                                                                 ["ProcessorSumm"
344                                                                  "ary"];
345                                                     nlohmann::json &procCount =
346                                                         procSummary["Count"];
347 
348                                                     auto procCountPtr =
349                                                         procCount.get_ptr<
350                                                             nlohmann::json::
351                                                                 number_integer_t
352                                                                     *>();
353                                                     if (procCountPtr != nullptr)
354                                                     {
355                                                         // shouldn't be possible
356                                                         // to be nullptr
357                                                         *procCountPtr += 1;
358                                                     }
359                                                     procSummary["Status"]
360                                                                ["State"] =
361                                                                    "Enabled";
362                                                     procSummary["Model"] =
363                                                         *value;
364                                                 }
365                                             }
366                                         }
367                                     }
368                                     else
369                                     {
370                                         auto getCpuPresenceState =
371                                             [aResp](
372                                                 const boost::system::error_code
373                                                     ec,
374                                                 const std::variant<bool>
375                                                     &cpuPresenceCheck) {
376                                                 if (ec)
377                                                 {
378                                                     BMCWEB_LOG_ERROR
379                                                         << "DBUS response "
380                                                            "error "
381                                                         << ec;
382                                                     return;
383                                                 }
384                                                 modifyCpuPresenceState(
385                                                     aResp, cpuPresenceCheck);
386                                             };
387 
388                                         auto getCpuFunctionalState =
389                                             [aResp](
390                                                 const boost::system::error_code
391                                                     ec,
392                                                 const std::variant<bool>
393                                                     &cpuFunctionalCheck) {
394                                                 if (ec)
395                                                 {
396                                                     BMCWEB_LOG_ERROR
397                                                         << "DBUS response "
398                                                            "error "
399                                                         << ec;
400                                                     return;
401                                                 }
402                                                 modifyCpuFunctionalState(
403                                                     aResp, cpuFunctionalCheck);
404                                             };
405                                         // Get the Presence of CPU
406                                         crow::connections::systemBus
407                                             ->async_method_call(
408                                                 std::move(getCpuPresenceState),
409                                                 service, path,
410                                                 "org.freedesktop.DBus."
411                                                 "Properties",
412                                                 "Get",
413                                                 "xyz.openbmc_project.Inventory."
414                                                 "Item",
415                                                 "Present");
416 
417                                         // Get the Functional State
418                                         crow::connections::systemBus
419                                             ->async_method_call(
420                                                 std::move(
421                                                     getCpuFunctionalState),
422                                                 service, path,
423                                                 "org.freedesktop.DBus."
424                                                 "Properties",
425                                                 "Get",
426                                                 "xyz.openbmc_project.State."
427                                                 "Decorator."
428                                                 "OperationalStatus",
429                                                 "Functional");
430 
431                                         // Get the MODEL from
432                                         // xyz.openbmc_project.Inventory.Decorator.Asset
433                                         // support it later as Model  is Empty
434                                         // currently.
435                                     }
436                                 },
437                                 connection.first, path,
438                                 "org.freedesktop.DBus.Properties", "GetAll",
439                                 "xyz.openbmc_project.Inventory.Item.Cpu");
440 
441                             cpuHealth->inventory.emplace_back(path);
442                         }
443                         else if (interfaceName ==
444                                  "xyz.openbmc_project.Common.UUID")
445                         {
446                             BMCWEB_LOG_DEBUG
447                                 << "Found UUID, now get its properties.";
448                             crow::connections::systemBus->async_method_call(
449                                 [aResp](const boost::system::error_code ec,
450                                         const std::vector<
451                                             std::pair<std::string, VariantType>>
452                                             &properties) {
453                                     if (ec)
454                                     {
455                                         BMCWEB_LOG_DEBUG
456                                             << "DBUS response error " << ec;
457                                         messages::internalError(aResp->res);
458                                         return;
459                                     }
460                                     BMCWEB_LOG_DEBUG << "Got "
461                                                      << properties.size()
462                                                      << " UUID properties.";
463                                     for (const std::pair<std::string,
464                                                          VariantType>
465                                              &property : properties)
466                                     {
467                                         if (property.first == "UUID")
468                                         {
469                                             const std::string *value =
470                                                 sdbusplus::message::variant_ns::
471                                                     get_if<std::string>(
472                                                         &property.second);
473 
474                                             if (value != nullptr)
475                                             {
476                                                 std::string valueStr = *value;
477                                                 if (valueStr.size() == 32)
478                                                 {
479                                                     valueStr.insert(8, 1, '-');
480                                                     valueStr.insert(13, 1, '-');
481                                                     valueStr.insert(18, 1, '-');
482                                                     valueStr.insert(23, 1, '-');
483                                                 }
484                                                 BMCWEB_LOG_DEBUG << "UUID = "
485                                                                  << valueStr;
486                                                 aResp->res.jsonValue["UUID"] =
487                                                     valueStr;
488                                             }
489                                         }
490                                     }
491                                 },
492                                 connection.first, path,
493                                 "org.freedesktop.DBus.Properties", "GetAll",
494                                 "xyz.openbmc_project.Common.UUID");
495                         }
496                         else if (interfaceName ==
497                                  "xyz.openbmc_project.Inventory.Item.System")
498                         {
499                             crow::connections::systemBus->async_method_call(
500                                 [aResp](const boost::system::error_code ec,
501                                         const std::vector<
502                                             std::pair<std::string, VariantType>>
503                                             &propertiesList) {
504                                     if (ec)
505                                     {
506                                         // doesn't have to include this
507                                         // interface
508                                         return;
509                                     }
510                                     BMCWEB_LOG_DEBUG
511                                         << "Got " << propertiesList.size()
512                                         << " properties for system";
513                                     for (const std::pair<std::string,
514                                                          VariantType>
515                                              &property : propertiesList)
516                                     {
517                                         const std::string &propertyName =
518                                             property.first;
519                                         if ((propertyName == "PartNumber") ||
520                                             (propertyName == "SerialNumber") ||
521                                             (propertyName == "Manufacturer") ||
522                                             (propertyName == "Model"))
523                                         {
524                                             const std::string *value =
525                                                 std::get_if<std::string>(
526                                                     &property.second);
527                                             if (value != nullptr)
528                                             {
529                                                 aResp->res
530                                                     .jsonValue[propertyName] =
531                                                     *value;
532                                             }
533                                         }
534                                     }
535 
536                                     // Grab the bios version
537                                     fw_util::getActiveFwVersion(
538                                         aResp, fw_util::biosPurpose,
539                                         "BiosVersion");
540                                 },
541                                 connection.first, path,
542                                 "org.freedesktop.DBus.Properties", "GetAll",
543                                 "xyz.openbmc_project.Inventory.Decorator."
544                                 "Asset");
545 
546                             crow::connections::systemBus->async_method_call(
547                                 [aResp](
548                                     const boost::system::error_code ec,
549                                     const std::variant<std::string> &property) {
550                                     if (ec)
551                                     {
552                                         // doesn't have to include this
553                                         // interface
554                                         return;
555                                     }
556 
557                                     const std::string *value =
558                                         std::get_if<std::string>(&property);
559                                     if (value != nullptr)
560                                     {
561                                         aResp->res.jsonValue["AssetTag"] =
562                                             *value;
563                                     }
564                                 },
565                                 connection.first, path,
566                                 "org.freedesktop.DBus.Properties", "Get",
567                                 "xyz.openbmc_project.Inventory.Decorator."
568                                 "AssetTag",
569                                 "AssetTag");
570                         }
571                     }
572                 }
573             }
574         },
575         "xyz.openbmc_project.ObjectMapper",
576         "/xyz/openbmc_project/object_mapper",
577         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
578         "/xyz/openbmc_project/inventory", int32_t(0),
579         std::array<const char *, 5>{
580             "xyz.openbmc_project.Inventory.Decorator.Asset",
581             "xyz.openbmc_project.Inventory.Item.Cpu",
582             "xyz.openbmc_project.Inventory.Item.Dimm",
583             "xyz.openbmc_project.Inventory.Item.System",
584             "xyz.openbmc_project.Common.UUID",
585         });
586 }
587 
588 /**
589  * @brief Retrieves host state properties over dbus
590  *
591  * @param[in] aResp     Shared pointer for completing asynchronous calls.
592  *
593  * @return None.
594  */
595 void getHostState(std::shared_ptr<AsyncResp> aResp)
596 {
597     BMCWEB_LOG_DEBUG << "Get host information.";
598     crow::connections::systemBus->async_method_call(
599         [aResp](const boost::system::error_code ec,
600                 const std::variant<std::string> &hostState) {
601             if (ec)
602             {
603                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
604                 messages::internalError(aResp->res);
605                 return;
606             }
607 
608             const std::string *s = std::get_if<std::string>(&hostState);
609             BMCWEB_LOG_DEBUG << "Host state: " << *s;
610             if (s != nullptr)
611             {
612                 // Verify Host State
613                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
614                 {
615                     aResp->res.jsonValue["PowerState"] = "On";
616                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
617                 }
618                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
619                                "DiagnosticMode")
620                 {
621                     aResp->res.jsonValue["PowerState"] = "On";
622                     aResp->res.jsonValue["Status"]["State"] = "InTest";
623                 }
624                 else
625                 {
626                     aResp->res.jsonValue["PowerState"] = "Off";
627                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
628                 }
629             }
630         },
631         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
632         "org.freedesktop.DBus.Properties", "Get",
633         "xyz.openbmc_project.State.Host", "CurrentHostState");
634 }
635 
636 /**
637  * @brief Traslates boot source DBUS property value to redfish.
638  *
639  * @param[in] dbusSource    The boot source in DBUS speak.
640  *
641  * @return Returns as a string, the boot source in Redfish terms. If translation
642  * cannot be done, returns an empty string.
643  */
644 static std::string dbusToRfBootSource(const std::string &dbusSource)
645 {
646     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
647     {
648         return "None";
649     }
650     else if (dbusSource ==
651              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
652     {
653         return "Hdd";
654     }
655     else if (dbusSource ==
656              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
657     {
658         return "Cd";
659     }
660     else if (dbusSource ==
661              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
662     {
663         return "Pxe";
664     }
665     else if (dbusSource ==
666              "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
667     {
668         return "Usb";
669     }
670     else
671     {
672         return "";
673     }
674 }
675 
676 /**
677  * @brief Traslates boot mode DBUS property value to redfish.
678  *
679  * @param[in] dbusMode    The boot mode in DBUS speak.
680  *
681  * @return Returns as a string, the boot mode in Redfish terms. If translation
682  * cannot be done, returns an empty string.
683  */
684 static std::string dbusToRfBootMode(const std::string &dbusMode)
685 {
686     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
687     {
688         return "None";
689     }
690     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
691     {
692         return "Diags";
693     }
694     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
695     {
696         return "BiosSetup";
697     }
698     else
699     {
700         return "";
701     }
702 }
703 
704 /**
705  * @brief Traslates boot source from Redfish to the DBus boot paths.
706  *
707  * @param[in] rfSource    The boot source in Redfish.
708  * @param[out] bootSource The DBus source
709  * @param[out] bootMode   the DBus boot mode
710  *
711  * @return Integer error code.
712  */
713 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
714                                 const std::string &rfSource,
715                                 std::string &bootSource, std::string &bootMode)
716 {
717     // The caller has initialized the bootSource and bootMode to:
718     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
719     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
720     // Only modify the bootSource/bootMode variable needed to achieve the
721     // desired boot action.
722 
723     if (rfSource == "None")
724     {
725         return 0;
726     }
727     else if (rfSource == "Pxe")
728     {
729         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
730     }
731     else if (rfSource == "Hdd")
732     {
733         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
734     }
735     else if (rfSource == "Diags")
736     {
737         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
738     }
739     else if (rfSource == "Cd")
740     {
741         bootSource =
742             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
743     }
744     else if (rfSource == "BiosSetup")
745     {
746         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
747     }
748     else if (rfSource == "Usb")
749     {
750         bootSource =
751             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
752     }
753     else
754     {
755         BMCWEB_LOG_DEBUG << "Invalid property value for "
756                             "BootSourceOverrideTarget: "
757                          << bootSource;
758         messages::propertyValueNotInList(aResp->res, rfSource,
759                                          "BootSourceTargetOverride");
760         return -1;
761     }
762     return 0;
763 }
764 
765 /**
766  * @brief Retrieves boot mode over DBUS and fills out the response
767  *
768  * @param[in] aResp         Shared pointer for generating response message.
769  * @param[in] bootDbusObj   The dbus object to query for boot properties.
770  *
771  * @return None.
772  */
773 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
774                         std::string bootDbusObj)
775 {
776     crow::connections::systemBus->async_method_call(
777         [aResp](const boost::system::error_code ec,
778                 const std::variant<std::string> &bootMode) {
779             if (ec)
780             {
781                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
782                 messages::internalError(aResp->res);
783                 return;
784             }
785 
786             const std::string *bootModeStr =
787                 std::get_if<std::string>(&bootMode);
788 
789             if (!bootModeStr)
790             {
791                 messages::internalError(aResp->res);
792                 return;
793             }
794 
795             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
796 
797             // TODO (Santosh): Do we need to support override mode?
798             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
799             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
800                                          "AllowableValues"] = {
801                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
802 
803             if (*bootModeStr !=
804                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
805             {
806                 auto rfMode = dbusToRfBootMode(*bootModeStr);
807                 if (!rfMode.empty())
808                 {
809                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
810                         rfMode;
811                 }
812             }
813 
814             // If the BootSourceOverrideTarget is still "None" at the end,
815             // reset the BootSourceOverrideEnabled to indicate that
816             // overrides are disabled
817             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
818                 "None")
819             {
820                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
821                     "Disabled";
822             }
823         },
824         "xyz.openbmc_project.Settings", bootDbusObj,
825         "org.freedesktop.DBus.Properties", "Get",
826         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
827 }
828 
829 /**
830  * @brief Retrieves boot source over DBUS
831  *
832  * @param[in] aResp         Shared pointer for generating response message.
833  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
834  *
835  * @return None.
836  */
837 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
838 {
839     std::string bootDbusObj =
840         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
841                        : "/xyz/openbmc_project/control/host0/boot";
842 
843     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
844     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
845         (oneTimeEnabled) ? "Once" : "Continuous";
846 
847     crow::connections::systemBus->async_method_call(
848         [aResp, bootDbusObj](const boost::system::error_code ec,
849                              const std::variant<std::string> &bootSource) {
850             if (ec)
851             {
852                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
853                 messages::internalError(aResp->res);
854                 return;
855             }
856 
857             const std::string *bootSourceStr =
858                 std::get_if<std::string>(&bootSource);
859 
860             if (!bootSourceStr)
861             {
862                 messages::internalError(aResp->res);
863                 return;
864             }
865             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
866 
867             auto rfSource = dbusToRfBootSource(*bootSourceStr);
868             if (!rfSource.empty())
869             {
870                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
871                     rfSource;
872             }
873         },
874         "xyz.openbmc_project.Settings", bootDbusObj,
875         "org.freedesktop.DBus.Properties", "Get",
876         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
877     getBootMode(std::move(aResp), std::move(bootDbusObj));
878 }
879 
880 /**
881  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
882  * get boot source and boot mode.
883  *
884  * @param[in] aResp     Shared pointer for generating response message.
885  *
886  * @return None.
887  */
888 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
889 {
890     BMCWEB_LOG_DEBUG << "Get boot information.";
891 
892     crow::connections::systemBus->async_method_call(
893         [aResp](const boost::system::error_code ec,
894                 const sdbusplus::message::variant<bool> &oneTime) {
895             if (ec)
896             {
897                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
898                 // not an error, don't have to have the interface
899                 return;
900             }
901 
902             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
903 
904             if (!oneTimePtr)
905             {
906                 messages::internalError(aResp->res);
907                 return;
908             }
909             getBootSource(aResp, *oneTimePtr);
910         },
911         "xyz.openbmc_project.Settings",
912         "/xyz/openbmc_project/control/host0/boot/one_time",
913         "org.freedesktop.DBus.Properties", "Get",
914         "xyz.openbmc_project.Object.Enable", "Enabled");
915 }
916 
917 /**
918  * @brief Sets boot properties into DBUS object(s).
919  *
920  * @param[in] aResp           Shared pointer for generating response message.
921  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
922  * @param[in] bootSource      The boot source to set.
923  * @param[in] bootEnable      The source override "enable" to set.
924  *
925  * @return Integer error code.
926  */
927 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
928                                 bool oneTimeEnabled,
929                                 std::optional<std::string> bootSource,
930                                 std::optional<std::string> bootEnable)
931 {
932     std::string bootSourceStr =
933         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
934     std::string bootModeStr =
935         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
936     bool oneTimeSetting = oneTimeEnabled;
937     bool useBootSource = true;
938 
939     // Validate incoming parameters
940     if (bootEnable)
941     {
942         if (*bootEnable == "Once")
943         {
944             oneTimeSetting = true;
945         }
946         else if (*bootEnable == "Continuous")
947         {
948             oneTimeSetting = false;
949         }
950         else if (*bootEnable == "Disabled")
951         {
952             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
953             oneTimeSetting = false;
954             useBootSource = false;
955         }
956         else
957         {
958             BMCWEB_LOG_DEBUG << "Unsupported value for "
959                                 "BootSourceOverrideEnabled: "
960                              << *bootEnable;
961             messages::propertyValueNotInList(aResp->res, *bootEnable,
962                                              "BootSourceOverrideEnabled");
963             return;
964         }
965     }
966 
967     if (bootSource && useBootSource)
968     {
969         // Source target specified
970         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
971         // Figure out which DBUS interface and property to use
972         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
973                                  bootModeStr))
974         {
975             BMCWEB_LOG_DEBUG
976                 << "Invalid property value for BootSourceOverrideTarget: "
977                 << *bootSource;
978             messages::propertyValueNotInList(aResp->res, *bootSource,
979                                              "BootSourceTargetOverride");
980             return;
981         }
982     }
983 
984     // Act on validated parameters
985     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
986     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
987     const char *bootObj =
988         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
989                        : "/xyz/openbmc_project/control/host0/boot";
990 
991     crow::connections::systemBus->async_method_call(
992         [aResp](const boost::system::error_code ec) {
993             if (ec)
994             {
995                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
996                 messages::internalError(aResp->res);
997                 return;
998             }
999             BMCWEB_LOG_DEBUG << "Boot source update done.";
1000         },
1001         "xyz.openbmc_project.Settings", bootObj,
1002         "org.freedesktop.DBus.Properties", "Set",
1003         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1004         std::variant<std::string>(bootSourceStr));
1005 
1006     crow::connections::systemBus->async_method_call(
1007         [aResp](const boost::system::error_code ec) {
1008             if (ec)
1009             {
1010                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1011                 messages::internalError(aResp->res);
1012                 return;
1013             }
1014             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1015         },
1016         "xyz.openbmc_project.Settings", bootObj,
1017         "org.freedesktop.DBus.Properties", "Set",
1018         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1019         std::variant<std::string>(bootModeStr));
1020 
1021     crow::connections::systemBus->async_method_call(
1022         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1023             if (ec)
1024             {
1025                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1026                 messages::internalError(aResp->res);
1027                 return;
1028             }
1029             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1030         },
1031         "xyz.openbmc_project.Settings",
1032         "/xyz/openbmc_project/control/host0/boot/one_time",
1033         "org.freedesktop.DBus.Properties", "Set",
1034         "xyz.openbmc_project.Object.Enable", "Enabled",
1035         std::variant<bool>(oneTimeSetting));
1036 }
1037 
1038 /**
1039  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1040  * set boot source/boot mode properties.
1041  *
1042  * @param[in] aResp      Shared pointer for generating response message.
1043  * @param[in] bootSource The boot source from incoming RF request.
1044  * @param[in] bootEnable The boot override enable from incoming RF request.
1045  *
1046  * @return Integer error code.
1047  */
1048 static void setBootProperties(std::shared_ptr<AsyncResp> aResp,
1049                               std::optional<std::string> bootSource,
1050                               std::optional<std::string> bootEnable)
1051 {
1052     BMCWEB_LOG_DEBUG << "Set boot information.";
1053 
1054     crow::connections::systemBus->async_method_call(
1055         [aResp, bootSource{std::move(bootSource)},
1056          bootEnable{std::move(bootEnable)}](
1057             const boost::system::error_code ec,
1058             const sdbusplus::message::variant<bool> &oneTime) {
1059             if (ec)
1060             {
1061                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1062                 messages::internalError(aResp->res);
1063                 return;
1064             }
1065 
1066             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1067 
1068             if (!oneTimePtr)
1069             {
1070                 messages::internalError(aResp->res);
1071                 return;
1072             }
1073 
1074             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1075 
1076             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1077                                 std::move(bootEnable));
1078         },
1079         "xyz.openbmc_project.Settings",
1080         "/xyz/openbmc_project/control/host0/boot/one_time",
1081         "org.freedesktop.DBus.Properties", "Get",
1082         "xyz.openbmc_project.Object.Enable", "Enabled");
1083 }
1084 
1085 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1086 /**
1087  * @brief Retrieves provisioning status
1088  *
1089  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1090  *
1091  * @return None.
1092  */
1093 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1094 {
1095     BMCWEB_LOG_DEBUG << "Get OEM information.";
1096     crow::connections::systemBus->async_method_call(
1097         [aResp](const boost::system::error_code ec,
1098                 const std::vector<std::pair<std::string, VariantType>>
1099                     &propertiesList) {
1100             if (ec)
1101             {
1102                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1103                 messages::internalError(aResp->res);
1104                 return;
1105             }
1106 
1107             const bool *provState = nullptr;
1108             const bool *lockState = nullptr;
1109             for (const std::pair<std::string, VariantType> &property :
1110                  propertiesList)
1111             {
1112                 if (property.first == "UfmProvisioned")
1113                 {
1114                     provState = std::get_if<bool>(&property.second);
1115                 }
1116                 else if (property.first == "UfmLocked")
1117                 {
1118                     lockState = std::get_if<bool>(&property.second);
1119                 }
1120             }
1121 
1122             if ((provState == nullptr) || (lockState == nullptr))
1123             {
1124                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1125                 messages::internalError(aResp->res);
1126                 return;
1127             }
1128 
1129             nlohmann::json &oemPFR =
1130                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1131             if (*provState == true)
1132             {
1133                 if (*lockState == true)
1134                 {
1135                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1136                 }
1137                 else
1138                 {
1139                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1140                 }
1141             }
1142             else
1143             {
1144                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1145             }
1146         },
1147         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1148         "org.freedesktop.DBus.Properties", "GetAll",
1149         "xyz.openbmc_project.PFR.Attributes");
1150 }
1151 #endif
1152 
1153 /**
1154  * @brief Translates watchdog timeout action DBUS property value to redfish.
1155  *
1156  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1157  *
1158  * @return Returns as a string, the timeout action in Redfish terms. If
1159  * translation cannot be done, returns an empty string.
1160  */
1161 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1162 {
1163     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1164     {
1165         return "None";
1166     }
1167     else if (dbusAction ==
1168              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1169     {
1170         return "ResetSystem";
1171     }
1172     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1173     {
1174         return "PowerDown";
1175     }
1176     else if (dbusAction ==
1177              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1178     {
1179         return "PowerCycle";
1180     }
1181 
1182     return "";
1183 }
1184 
1185 /**
1186  *@brief Translates timeout action from Redfish to DBUS property value.
1187  *
1188  *@param[in] rfAction The timeout action in Redfish.
1189  *
1190  *@return Returns as a string, the time_out action as expected by DBUS.
1191  *If translation cannot be done, returns an empty string.
1192  */
1193 
1194 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction)
1195 {
1196     if (rfAction == "None")
1197     {
1198         return "xyz.openbmc_project.State.Watchdog.Action.None";
1199     }
1200     else if (rfAction == "PowerCycle")
1201     {
1202         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1203     }
1204     else if (rfAction == "PowerDown")
1205     {
1206         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1207     }
1208     else if (rfAction == "ResetSystem")
1209     {
1210         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1211     }
1212 
1213     return "";
1214 }
1215 
1216 /**
1217  * @brief Retrieves host watchdog timer properties over DBUS
1218  *
1219  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1220  *
1221  * @return None.
1222  */
1223 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1224 {
1225     BMCWEB_LOG_DEBUG << "Get host watchodg";
1226     crow::connections::systemBus->async_method_call(
1227         [aResp](const boost::system::error_code ec,
1228                 PropertiesType &properties) {
1229             if (ec)
1230             {
1231                 // watchdog service is stopped
1232                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1233                 return;
1234             }
1235 
1236             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1237 
1238             nlohmann::json &hostWatchdogTimer =
1239                 aResp->res.jsonValue["HostWatchdogTimer"];
1240 
1241             // watchdog service is running/enabled
1242             hostWatchdogTimer["Status"]["State"] = "Enabled";
1243 
1244             for (const auto &property : properties)
1245             {
1246                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1247                 if (property.first == "Enabled")
1248                 {
1249                     const bool *state = std::get_if<bool>(&property.second);
1250 
1251                     if (!state)
1252                     {
1253                         messages::internalError(aResp->res);
1254                         continue;
1255                     }
1256 
1257                     hostWatchdogTimer["FunctionEnabled"] = *state;
1258                 }
1259                 else if (property.first == "ExpireAction")
1260                 {
1261                     const std::string *s =
1262                         std::get_if<std::string>(&property.second);
1263                     if (!s)
1264                     {
1265                         messages::internalError(aResp->res);
1266                         continue;
1267                     }
1268 
1269                     std::string action = dbusToRfWatchdogAction(*s);
1270                     if (action.empty())
1271                     {
1272                         messages::internalError(aResp->res);
1273                         continue;
1274                     }
1275                     hostWatchdogTimer["TimeoutAction"] = action;
1276                 }
1277             }
1278         },
1279         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1280         "org.freedesktop.DBus.Properties", "GetAll",
1281         "xyz.openbmc_project.State.Watchdog");
1282 }
1283 
1284 /**
1285  * @brief Sets Host WatchDog Timer properties.
1286  *
1287  * @param[in] aResp      Shared pointer for generating response message.
1288  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1289  *                       RF request.
1290  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1291  *
1292  * @return None.
1293  */
1294 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1295                              const std::optional<bool> wdtEnable,
1296                              const std::optional<std::string> &wdtTimeOutAction)
1297 {
1298     BMCWEB_LOG_DEBUG << "Set host watchdog";
1299 
1300     if (wdtTimeOutAction)
1301     {
1302         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1303         // check if TimeOut Action is Valid
1304         if (wdtTimeOutActStr.empty())
1305         {
1306             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1307                              << *wdtTimeOutAction;
1308             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1309                                              "TimeoutAction");
1310             return;
1311         }
1312 
1313         crow::connections::systemBus->async_method_call(
1314             [aResp](const boost::system::error_code ec) {
1315                 if (ec)
1316                 {
1317                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1318                     messages::internalError(aResp->res);
1319                     return;
1320                 }
1321             },
1322             "xyz.openbmc_project.Watchdog",
1323             "/xyz/openbmc_project/watchdog/host0",
1324             "org.freedesktop.DBus.Properties", "Set",
1325             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1326             std::variant<std::string>(wdtTimeOutActStr));
1327     }
1328 
1329     if (wdtEnable)
1330     {
1331         crow::connections::systemBus->async_method_call(
1332             [aResp](const boost::system::error_code ec) {
1333                 if (ec)
1334                 {
1335                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1336                     messages::internalError(aResp->res);
1337                     return;
1338                 }
1339             },
1340             "xyz.openbmc_project.Watchdog",
1341             "/xyz/openbmc_project/watchdog/host0",
1342             "org.freedesktop.DBus.Properties", "Set",
1343             "xyz.openbmc_project.State.Watchdog", "Enabled",
1344             std::variant<bool>(*wdtEnable));
1345     }
1346 }
1347 
1348 /**
1349  * SystemsCollection derived class for delivering ComputerSystems Collection
1350  * Schema
1351  */
1352 class SystemsCollection : public Node
1353 {
1354   public:
1355     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1356     {
1357         entityPrivileges = {
1358             {boost::beast::http::verb::get, {{"Login"}}},
1359             {boost::beast::http::verb::head, {{"Login"}}},
1360             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1361             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1362             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1363             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1364     }
1365 
1366   private:
1367     void doGet(crow::Response &res, const crow::Request &req,
1368                const std::vector<std::string> &params) override
1369     {
1370         std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
1371         res.jsonValue["@odata.type"] =
1372             "#ComputerSystemCollection.ComputerSystemCollection";
1373         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1374         res.jsonValue["Name"] = "Computer System Collection";
1375 
1376         crow::connections::systemBus->async_method_call(
1377             [asyncResp](const boost::system::error_code ec,
1378                         const std::variant<std::string> &hostName) {
1379                 nlohmann::json &iface_array =
1380                     asyncResp->res.jsonValue["Members"];
1381                 iface_array = nlohmann::json::array();
1382                 auto &count = asyncResp->res.jsonValue["Members@odata.count"];
1383                 count = 0;
1384                 if (ec)
1385                 {
1386                     iface_array.push_back(
1387                         {{"@odata.id", "/redfish/v1/Systems/system"}});
1388                     count = iface_array.size();
1389                     return;
1390                 }
1391                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
1392                 iface_array.push_back(
1393                     {{"@odata.id", "/redfish/v1/Systems/system"}});
1394                 iface_array.push_back(
1395                     {{"@odata.id", "/redfish/v1/Systems/hypervisor"}});
1396                 count = iface_array.size();
1397             },
1398             "xyz.openbmc_project.Settings", "/xyz/openbmc_project/network/vmi",
1399             "org.freedesktop.DBus.Properties", "Get",
1400             "xyz.openbmc_project.Network.SystemConfiguration", "HostName");
1401     }
1402 };
1403 
1404 /**
1405  * SystemActionsReset class supports handle POST method for Reset action.
1406  * The class retrieves and sends data directly to D-Bus.
1407  */
1408 class SystemActionsReset : public Node
1409 {
1410   public:
1411     SystemActionsReset(CrowApp &app) :
1412         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1413     {
1414         entityPrivileges = {
1415             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1416     }
1417 
1418   private:
1419     /**
1420      * Function handles POST method request.
1421      * Analyzes POST body message before sends Reset request data to D-Bus.
1422      */
1423     void doPost(crow::Response &res, const crow::Request &req,
1424                 const std::vector<std::string> &params) override
1425     {
1426         auto asyncResp = std::make_shared<AsyncResp>(res);
1427 
1428         std::string resetType;
1429         if (!json_util::readJson(req, res, "ResetType", resetType))
1430         {
1431             return;
1432         }
1433 
1434         // Get the command and host vs. chassis
1435         std::string command;
1436         bool hostCommand;
1437         if (resetType == "On")
1438         {
1439             command = "xyz.openbmc_project.State.Host.Transition.On";
1440             hostCommand = true;
1441         }
1442         else if (resetType == "ForceOff")
1443         {
1444             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1445             hostCommand = false;
1446         }
1447         else if (resetType == "ForceOn")
1448         {
1449             command = "xyz.openbmc_project.State.Host.Transition.On";
1450             hostCommand = true;
1451         }
1452         else if (resetType == "ForceRestart")
1453         {
1454             command =
1455                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1456             hostCommand = true;
1457         }
1458         else if (resetType == "GracefulShutdown")
1459         {
1460             command = "xyz.openbmc_project.State.Host.Transition.Off";
1461             hostCommand = true;
1462         }
1463         else if (resetType == "GracefulRestart")
1464         {
1465             command =
1466                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1467             hostCommand = true;
1468         }
1469         else if (resetType == "PowerCycle")
1470         {
1471             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1472             hostCommand = true;
1473         }
1474         else if (resetType == "Nmi")
1475         {
1476             doNMI(asyncResp);
1477             return;
1478         }
1479         else
1480         {
1481             messages::actionParameterUnknown(res, "Reset", resetType);
1482             return;
1483         }
1484 
1485         if (hostCommand)
1486         {
1487             crow::connections::systemBus->async_method_call(
1488                 [asyncResp, resetType](const boost::system::error_code ec) {
1489                     if (ec)
1490                     {
1491                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1492                         if (ec.value() == boost::asio::error::invalid_argument)
1493                         {
1494                             messages::actionParameterNotSupported(
1495                                 asyncResp->res, resetType, "Reset");
1496                         }
1497                         else
1498                         {
1499                             messages::internalError(asyncResp->res);
1500                         }
1501                         return;
1502                     }
1503                     messages::success(asyncResp->res);
1504                 },
1505                 "xyz.openbmc_project.State.Host",
1506                 "/xyz/openbmc_project/state/host0",
1507                 "org.freedesktop.DBus.Properties", "Set",
1508                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1509                 std::variant<std::string>{command});
1510         }
1511         else
1512         {
1513             crow::connections::systemBus->async_method_call(
1514                 [asyncResp, resetType](const boost::system::error_code ec) {
1515                     if (ec)
1516                     {
1517                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1518                         if (ec.value() == boost::asio::error::invalid_argument)
1519                         {
1520                             messages::actionParameterNotSupported(
1521                                 asyncResp->res, resetType, "Reset");
1522                         }
1523                         else
1524                         {
1525                             messages::internalError(asyncResp->res);
1526                         }
1527                         return;
1528                     }
1529                     messages::success(asyncResp->res);
1530                 },
1531                 "xyz.openbmc_project.State.Chassis",
1532                 "/xyz/openbmc_project/state/chassis0",
1533                 "org.freedesktop.DBus.Properties", "Set",
1534                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1535                 std::variant<std::string>{command});
1536         }
1537     }
1538     /**
1539      * Function transceives data with dbus directly.
1540      */
1541     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1542     {
1543         constexpr char const *serviceName =
1544             "xyz.openbmc_project.Control.Host.NMI";
1545         constexpr char const *objectPath =
1546             "/xyz/openbmc_project/control/host0/nmi";
1547         constexpr char const *interfaceName =
1548             "xyz.openbmc_project.Control.Host.NMI";
1549         constexpr char const *method = "NMI";
1550 
1551         crow::connections::systemBus->async_method_call(
1552             [asyncResp](const boost::system::error_code ec) {
1553                 if (ec)
1554                 {
1555                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1556                     messages::internalError(asyncResp->res);
1557                     return;
1558                 }
1559                 messages::success(asyncResp->res);
1560             },
1561             serviceName, objectPath, interfaceName, method);
1562     }
1563 };
1564 
1565 /**
1566  * Systems derived class for delivering Computer Systems Schema.
1567  */
1568 class Systems : public Node
1569 {
1570   public:
1571     /*
1572      * Default Constructor
1573      */
1574     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1575     {
1576         entityPrivileges = {
1577             {boost::beast::http::verb::get, {{"Login"}}},
1578             {boost::beast::http::verb::head, {{"Login"}}},
1579             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1580             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1581             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1582             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1583     }
1584 
1585   private:
1586     /**
1587      * Functions triggers appropriate requests on DBus
1588      */
1589     void doGet(crow::Response &res, const crow::Request &req,
1590                const std::vector<std::string> &params) override
1591     {
1592         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1593         res.jsonValue["Name"] = "system";
1594         res.jsonValue["Id"] = "system";
1595         res.jsonValue["SystemType"] = "Physical";
1596         res.jsonValue["Description"] = "Computer System";
1597         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1598         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1599         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
1600         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1601         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1602 
1603         res.jsonValue["Processors"] = {
1604             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1605         res.jsonValue["Memory"] = {
1606             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1607         res.jsonValue["Storage"] = {
1608             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1609 
1610         // TODO Need to support ForceRestart.
1611         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1612             {"target",
1613              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1614             {"ResetType@Redfish.AllowableValues",
1615              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1616               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1617 
1618         res.jsonValue["LogServices"] = {
1619             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1620 
1621         res.jsonValue["Bios"] = {
1622             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
1623 
1624         res.jsonValue["Links"]["ManagedBy"] = {
1625             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1626 
1627         res.jsonValue["Status"] = {
1628             {"Health", "OK"},
1629             {"State", "Enabled"},
1630         };
1631         auto asyncResp = std::make_shared<AsyncResp>(res);
1632 
1633         constexpr const std::array<const char *, 4> inventoryForSystems = {
1634             "xyz.openbmc_project.Inventory.Item.Dimm",
1635             "xyz.openbmc_project.Inventory.Item.Cpu",
1636             "xyz.openbmc_project.Inventory.Item.Drive",
1637             "xyz.openbmc_project.Inventory.Item.StorageController"};
1638 
1639         auto health = std::make_shared<HealthPopulate>(asyncResp);
1640         crow::connections::systemBus->async_method_call(
1641             [health](const boost::system::error_code ec,
1642                      std::vector<std::string> &resp) {
1643                 if (ec)
1644                 {
1645                     // no inventory
1646                     return;
1647                 }
1648 
1649                 health->inventory = std::move(resp);
1650             },
1651             "xyz.openbmc_project.ObjectMapper",
1652             "/xyz/openbmc_project/object_mapper",
1653             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1654             int32_t(0), inventoryForSystems);
1655 
1656         health->populate();
1657 
1658         getMainChassisId(asyncResp, [](const std::string &chassisId,
1659                                        std::shared_ptr<AsyncResp> aRsp) {
1660             aRsp->res.jsonValue["Links"]["Chassis"] = {
1661                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1662         });
1663 
1664         getIndicatorLedState(asyncResp);
1665         getComputerSystem(asyncResp, health);
1666         getHostState(asyncResp);
1667         getBootProperties(asyncResp);
1668         getPCIeDeviceList(asyncResp, "PCIeDevices");
1669         getHostWatchdogTimer(asyncResp);
1670 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1671         getProvisioningStatus(asyncResp);
1672 #endif
1673     }
1674 
1675     void doPatch(crow::Response &res, const crow::Request &req,
1676                  const std::vector<std::string> &params) override
1677     {
1678         std::optional<std::string> indicatorLed;
1679         std::optional<nlohmann::json> bootProps;
1680         std::optional<nlohmann::json> wdtTimerProps;
1681         auto asyncResp = std::make_shared<AsyncResp>(res);
1682 
1683         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1684                                  bootProps, "WatchdogTimer", wdtTimerProps))
1685         {
1686             return;
1687         }
1688 
1689         res.result(boost::beast::http::status::no_content);
1690 
1691         if (wdtTimerProps)
1692         {
1693             std::optional<bool> wdtEnable;
1694             std::optional<std::string> wdtTimeOutAction;
1695 
1696             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1697                                      "FunctionEnabled", wdtEnable,
1698                                      "TimeoutAction", wdtTimeOutAction))
1699             {
1700                 return;
1701             }
1702             setWDTProperties(asyncResp, std::move(wdtEnable),
1703                              std::move(wdtTimeOutAction));
1704         }
1705 
1706         if (bootProps)
1707         {
1708             std::optional<std::string> bootSource;
1709             std::optional<std::string> bootEnable;
1710 
1711             if (!json_util::readJson(*bootProps, asyncResp->res,
1712                                      "BootSourceOverrideTarget", bootSource,
1713                                      "BootSourceOverrideEnabled", bootEnable))
1714             {
1715                 return;
1716             }
1717             setBootProperties(asyncResp, std::move(bootSource),
1718                               std::move(bootEnable));
1719         }
1720 
1721         if (indicatorLed)
1722         {
1723             setIndicatorLedState(asyncResp, std::move(*indicatorLed));
1724         }
1725     }
1726 };
1727 } // namespace redfish
1728