xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision f20ee1487881342bba27fc14f66668c7519889c3)
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                                     aResp->res.jsonValue["Name"] = "system";
536                                     aResp->res.jsonValue["Id"] =
537                                         aResp->res.jsonValue["SerialNumber"];
538                                     // Grab the bios version
539                                     fw_util::getActiveFwVersion(
540                                         aResp, fw_util::biosPurpose,
541                                         "BiosVersion");
542                                 },
543                                 connection.first, path,
544                                 "org.freedesktop.DBus.Properties", "GetAll",
545                                 "xyz.openbmc_project.Inventory.Decorator."
546                                 "Asset");
547 
548                             crow::connections::systemBus->async_method_call(
549                                 [aResp](
550                                     const boost::system::error_code ec,
551                                     const std::variant<std::string> &property) {
552                                     if (ec)
553                                     {
554                                         // doesn't have to include this
555                                         // interface
556                                         return;
557                                     }
558 
559                                     const std::string *value =
560                                         std::get_if<std::string>(&property);
561                                     if (value != nullptr)
562                                     {
563                                         aResp->res.jsonValue["AssetTag"] =
564                                             *value;
565                                     }
566                                 },
567                                 connection.first, path,
568                                 "org.freedesktop.DBus.Properties", "Get",
569                                 "xyz.openbmc_project.Inventory.Decorator."
570                                 "AssetTag",
571                                 "AssetTag");
572                         }
573                     }
574                 }
575             }
576         },
577         "xyz.openbmc_project.ObjectMapper",
578         "/xyz/openbmc_project/object_mapper",
579         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
580         "/xyz/openbmc_project/inventory", int32_t(0),
581         std::array<const char *, 5>{
582             "xyz.openbmc_project.Inventory.Decorator.Asset",
583             "xyz.openbmc_project.Inventory.Item.Cpu",
584             "xyz.openbmc_project.Inventory.Item.Dimm",
585             "xyz.openbmc_project.Inventory.Item.System",
586             "xyz.openbmc_project.Common.UUID",
587         });
588 }
589 
590 /**
591  * @brief Retrieves host state properties over dbus
592  *
593  * @param[in] aResp     Shared pointer for completing asynchronous calls.
594  *
595  * @return None.
596  */
597 void getHostState(std::shared_ptr<AsyncResp> aResp)
598 {
599     BMCWEB_LOG_DEBUG << "Get host information.";
600     crow::connections::systemBus->async_method_call(
601         [aResp](const boost::system::error_code ec,
602                 const std::variant<std::string> &hostState) {
603             if (ec)
604             {
605                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
606                 messages::internalError(aResp->res);
607                 return;
608             }
609 
610             const std::string *s = std::get_if<std::string>(&hostState);
611             BMCWEB_LOG_DEBUG << "Host state: " << *s;
612             if (s != nullptr)
613             {
614                 // Verify Host State
615                 if (*s == "xyz.openbmc_project.State.Host.HostState.Running")
616                 {
617                     aResp->res.jsonValue["PowerState"] = "On";
618                     aResp->res.jsonValue["Status"]["State"] = "Enabled";
619                 }
620                 else if (*s == "xyz.openbmc_project.State.Host.HostState."
621                                "DiagnosticMode")
622                 {
623                     aResp->res.jsonValue["PowerState"] = "On";
624                     aResp->res.jsonValue["Status"]["State"] = "InTest";
625                 }
626                 else
627                 {
628                     aResp->res.jsonValue["PowerState"] = "Off";
629                     aResp->res.jsonValue["Status"]["State"] = "Disabled";
630                 }
631             }
632         },
633         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
634         "org.freedesktop.DBus.Properties", "Get",
635         "xyz.openbmc_project.State.Host", "CurrentHostState");
636 }
637 
638 /**
639  * @brief Traslates boot source DBUS property value to redfish.
640  *
641  * @param[in] dbusSource    The boot source in DBUS speak.
642  *
643  * @return Returns as a string, the boot source in Redfish terms. If translation
644  * cannot be done, returns an empty string.
645  */
646 static std::string dbusToRfBootSource(const std::string &dbusSource)
647 {
648     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
649     {
650         return "None";
651     }
652     else if (dbusSource ==
653              "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
654     {
655         return "Hdd";
656     }
657     else if (dbusSource ==
658              "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
659     {
660         return "Cd";
661     }
662     else if (dbusSource ==
663              "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
664     {
665         return "Pxe";
666     }
667     else if (dbusSource ==
668              "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
669     {
670         return "Usb";
671     }
672     else
673     {
674         return "";
675     }
676 }
677 
678 /**
679  * @brief Traslates boot mode DBUS property value to redfish.
680  *
681  * @param[in] dbusMode    The boot mode in DBUS speak.
682  *
683  * @return Returns as a string, the boot mode in Redfish terms. If translation
684  * cannot be done, returns an empty string.
685  */
686 static std::string dbusToRfBootMode(const std::string &dbusMode)
687 {
688     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
689     {
690         return "None";
691     }
692     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
693     {
694         return "Diags";
695     }
696     else if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
697     {
698         return "BiosSetup";
699     }
700     else
701     {
702         return "";
703     }
704 }
705 
706 /**
707  * @brief Traslates boot source from Redfish to the DBus boot paths.
708  *
709  * @param[in] rfSource    The boot source in Redfish.
710  * @param[out] bootSource The DBus source
711  * @param[out] bootMode   the DBus boot mode
712  *
713  * @return Integer error code.
714  */
715 static int assignBootParameters(std::shared_ptr<AsyncResp> aResp,
716                                 const std::string &rfSource,
717                                 std::string &bootSource, std::string &bootMode)
718 {
719     // The caller has initialized the bootSource and bootMode to:
720     // bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
721     // bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
722     // Only modify the bootSource/bootMode variable needed to achieve the
723     // desired boot action.
724 
725     if (rfSource == "None")
726     {
727         return 0;
728     }
729     else if (rfSource == "Pxe")
730     {
731         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
732     }
733     else if (rfSource == "Hdd")
734     {
735         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
736     }
737     else if (rfSource == "Diags")
738     {
739         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
740     }
741     else if (rfSource == "Cd")
742     {
743         bootSource =
744             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
745     }
746     else if (rfSource == "BiosSetup")
747     {
748         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
749     }
750     else if (rfSource == "Usb")
751     {
752         bootSource =
753             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
754     }
755     else
756     {
757         BMCWEB_LOG_DEBUG << "Invalid property value for "
758                             "BootSourceOverrideTarget: "
759                          << bootSource;
760         messages::propertyValueNotInList(aResp->res, rfSource,
761                                          "BootSourceTargetOverride");
762         return -1;
763     }
764     return 0;
765 }
766 
767 /**
768  * @brief Retrieves boot mode over DBUS and fills out the response
769  *
770  * @param[in] aResp         Shared pointer for generating response message.
771  * @param[in] bootDbusObj   The dbus object to query for boot properties.
772  *
773  * @return None.
774  */
775 static void getBootMode(std::shared_ptr<AsyncResp> aResp,
776                         std::string bootDbusObj)
777 {
778     crow::connections::systemBus->async_method_call(
779         [aResp](const boost::system::error_code ec,
780                 const std::variant<std::string> &bootMode) {
781             if (ec)
782             {
783                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
784                 messages::internalError(aResp->res);
785                 return;
786             }
787 
788             const std::string *bootModeStr =
789                 std::get_if<std::string>(&bootMode);
790 
791             if (!bootModeStr)
792             {
793                 messages::internalError(aResp->res);
794                 return;
795             }
796 
797             BMCWEB_LOG_DEBUG << "Boot mode: " << *bootModeStr;
798 
799             // TODO (Santosh): Do we need to support override mode?
800             aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = "Legacy";
801             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget@Redfish."
802                                          "AllowableValues"] = {
803                 "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
804 
805             if (*bootModeStr !=
806                 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
807             {
808                 auto rfMode = dbusToRfBootMode(*bootModeStr);
809                 if (!rfMode.empty())
810                 {
811                     aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
812                         rfMode;
813                 }
814             }
815 
816             // If the BootSourceOverrideTarget is still "None" at the end,
817             // reset the BootSourceOverrideEnabled to indicate that
818             // overrides are disabled
819             if (aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] ==
820                 "None")
821             {
822                 aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
823                     "Disabled";
824             }
825         },
826         "xyz.openbmc_project.Settings", bootDbusObj,
827         "org.freedesktop.DBus.Properties", "Get",
828         "xyz.openbmc_project.Control.Boot.Mode", "BootMode");
829 }
830 
831 /**
832  * @brief Retrieves boot source over DBUS
833  *
834  * @param[in] aResp         Shared pointer for generating response message.
835  * @param[in] oneTimeEnable Boolean to indicate boot properties are one-time.
836  *
837  * @return None.
838  */
839 static void getBootSource(std::shared_ptr<AsyncResp> aResp, bool oneTimeEnabled)
840 {
841     std::string bootDbusObj =
842         oneTimeEnabled ? "/xyz/openbmc_project/control/host0/boot/one_time"
843                        : "/xyz/openbmc_project/control/host0/boot";
844 
845     BMCWEB_LOG_DEBUG << "Is one time: " << oneTimeEnabled;
846     aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
847         (oneTimeEnabled) ? "Once" : "Continuous";
848 
849     crow::connections::systemBus->async_method_call(
850         [aResp, bootDbusObj](const boost::system::error_code ec,
851                              const std::variant<std::string> &bootSource) {
852             if (ec)
853             {
854                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
855                 messages::internalError(aResp->res);
856                 return;
857             }
858 
859             const std::string *bootSourceStr =
860                 std::get_if<std::string>(&bootSource);
861 
862             if (!bootSourceStr)
863             {
864                 messages::internalError(aResp->res);
865                 return;
866             }
867             BMCWEB_LOG_DEBUG << "Boot source: " << *bootSourceStr;
868 
869             auto rfSource = dbusToRfBootSource(*bootSourceStr);
870             if (!rfSource.empty())
871             {
872                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
873                     rfSource;
874             }
875         },
876         "xyz.openbmc_project.Settings", bootDbusObj,
877         "org.freedesktop.DBus.Properties", "Get",
878         "xyz.openbmc_project.Control.Boot.Source", "BootSource");
879     getBootMode(std::move(aResp), std::move(bootDbusObj));
880 }
881 
882 /**
883  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
884  * get boot source and boot mode.
885  *
886  * @param[in] aResp     Shared pointer for generating response message.
887  *
888  * @return None.
889  */
890 static void getBootProperties(std::shared_ptr<AsyncResp> aResp)
891 {
892     BMCWEB_LOG_DEBUG << "Get boot information.";
893 
894     crow::connections::systemBus->async_method_call(
895         [aResp](const boost::system::error_code ec,
896                 const sdbusplus::message::variant<bool> &oneTime) {
897             if (ec)
898             {
899                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
900                 // not an error, don't have to have the interface
901                 return;
902             }
903 
904             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
905 
906             if (!oneTimePtr)
907             {
908                 messages::internalError(aResp->res);
909                 return;
910             }
911             getBootSource(aResp, *oneTimePtr);
912         },
913         "xyz.openbmc_project.Settings",
914         "/xyz/openbmc_project/control/host0/boot/one_time",
915         "org.freedesktop.DBus.Properties", "Get",
916         "xyz.openbmc_project.Object.Enable", "Enabled");
917 }
918 
919 /**
920  * @brief Sets boot properties into DBUS object(s).
921  *
922  * @param[in] aResp           Shared pointer for generating response message.
923  * @param[in] oneTimeEnabled  Is "one-time" setting already enabled.
924  * @param[in] bootSource      The boot source to set.
925  * @param[in] bootEnable      The source override "enable" to set.
926  *
927  * @return Integer error code.
928  */
929 static void setBootModeOrSource(std::shared_ptr<AsyncResp> aResp,
930                                 bool oneTimeEnabled,
931                                 std::optional<std::string> bootSource,
932                                 std::optional<std::string> bootEnable)
933 {
934     std::string bootSourceStr =
935         "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
936     std::string bootModeStr =
937         "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
938     bool oneTimeSetting = oneTimeEnabled;
939     bool useBootSource = true;
940 
941     // Validate incoming parameters
942     if (bootEnable)
943     {
944         if (*bootEnable == "Once")
945         {
946             oneTimeSetting = true;
947         }
948         else if (*bootEnable == "Continuous")
949         {
950             oneTimeSetting = false;
951         }
952         else if (*bootEnable == "Disabled")
953         {
954             BMCWEB_LOG_DEBUG << "Boot source override will be disabled";
955             oneTimeSetting = false;
956             useBootSource = false;
957         }
958         else
959         {
960             BMCWEB_LOG_DEBUG << "Unsupported value for "
961                                 "BootSourceOverrideEnabled: "
962                              << *bootEnable;
963             messages::propertyValueNotInList(aResp->res, *bootEnable,
964                                              "BootSourceOverrideEnabled");
965             return;
966         }
967     }
968 
969     if (bootSource && useBootSource)
970     {
971         // Source target specified
972         BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
973         // Figure out which DBUS interface and property to use
974         if (assignBootParameters(aResp, *bootSource, bootSourceStr,
975                                  bootModeStr))
976         {
977             BMCWEB_LOG_DEBUG
978                 << "Invalid property value for BootSourceOverrideTarget: "
979                 << *bootSource;
980             messages::propertyValueNotInList(aResp->res, *bootSource,
981                                              "BootSourceTargetOverride");
982             return;
983         }
984     }
985 
986     // Act on validated parameters
987     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
988     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
989     const char *bootObj =
990         oneTimeSetting ? "/xyz/openbmc_project/control/host0/boot/one_time"
991                        : "/xyz/openbmc_project/control/host0/boot";
992 
993     crow::connections::systemBus->async_method_call(
994         [aResp](const boost::system::error_code ec) {
995             if (ec)
996             {
997                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
998                 messages::internalError(aResp->res);
999                 return;
1000             }
1001             BMCWEB_LOG_DEBUG << "Boot source update done.";
1002         },
1003         "xyz.openbmc_project.Settings", bootObj,
1004         "org.freedesktop.DBus.Properties", "Set",
1005         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1006         std::variant<std::string>(bootSourceStr));
1007 
1008     crow::connections::systemBus->async_method_call(
1009         [aResp](const boost::system::error_code ec) {
1010             if (ec)
1011             {
1012                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1013                 messages::internalError(aResp->res);
1014                 return;
1015             }
1016             BMCWEB_LOG_DEBUG << "Boot mode update done.";
1017         },
1018         "xyz.openbmc_project.Settings", bootObj,
1019         "org.freedesktop.DBus.Properties", "Set",
1020         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1021         std::variant<std::string>(bootModeStr));
1022 
1023     crow::connections::systemBus->async_method_call(
1024         [aResp{std::move(aResp)}](const boost::system::error_code ec) {
1025             if (ec)
1026             {
1027                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1028                 messages::internalError(aResp->res);
1029                 return;
1030             }
1031             BMCWEB_LOG_DEBUG << "Boot enable update done.";
1032         },
1033         "xyz.openbmc_project.Settings",
1034         "/xyz/openbmc_project/control/host0/boot/one_time",
1035         "org.freedesktop.DBus.Properties", "Set",
1036         "xyz.openbmc_project.Object.Enable", "Enabled",
1037         std::variant<bool>(oneTimeSetting));
1038 }
1039 
1040 /**
1041  * @brief Retrieves "One time" enabled setting over DBUS and calls function to
1042  * set boot source/boot mode properties.
1043  *
1044  * @param[in] aResp      Shared pointer for generating response message.
1045  * @param[in] bootSource The boot source from incoming RF request.
1046  * @param[in] bootEnable The boot override enable from incoming RF request.
1047  *
1048  * @return Integer error code.
1049  */
1050 static void setBootProperties(std::shared_ptr<AsyncResp> aResp,
1051                               std::optional<std::string> bootSource,
1052                               std::optional<std::string> bootEnable)
1053 {
1054     BMCWEB_LOG_DEBUG << "Set boot information.";
1055 
1056     crow::connections::systemBus->async_method_call(
1057         [aResp, bootSource{std::move(bootSource)},
1058          bootEnable{std::move(bootEnable)}](
1059             const boost::system::error_code ec,
1060             const sdbusplus::message::variant<bool> &oneTime) {
1061             if (ec)
1062             {
1063                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1064                 messages::internalError(aResp->res);
1065                 return;
1066             }
1067 
1068             const bool *oneTimePtr = std::get_if<bool>(&oneTime);
1069 
1070             if (!oneTimePtr)
1071             {
1072                 messages::internalError(aResp->res);
1073                 return;
1074             }
1075 
1076             BMCWEB_LOG_DEBUG << "Got one time: " << *oneTimePtr;
1077 
1078             setBootModeOrSource(aResp, *oneTimePtr, std::move(bootSource),
1079                                 std::move(bootEnable));
1080         },
1081         "xyz.openbmc_project.Settings",
1082         "/xyz/openbmc_project/control/host0/boot/one_time",
1083         "org.freedesktop.DBus.Properties", "Get",
1084         "xyz.openbmc_project.Object.Enable", "Enabled");
1085 }
1086 
1087 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1088 /**
1089  * @brief Retrieves provisioning status
1090  *
1091  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1092  *
1093  * @return None.
1094  */
1095 void getProvisioningStatus(std::shared_ptr<AsyncResp> aResp)
1096 {
1097     BMCWEB_LOG_DEBUG << "Get OEM information.";
1098     crow::connections::systemBus->async_method_call(
1099         [aResp](const boost::system::error_code ec,
1100                 const std::vector<std::pair<std::string, VariantType>>
1101                     &propertiesList) {
1102             if (ec)
1103             {
1104                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1105                 messages::internalError(aResp->res);
1106                 return;
1107             }
1108 
1109             const bool *provState = nullptr;
1110             const bool *lockState = nullptr;
1111             for (const std::pair<std::string, VariantType> &property :
1112                  propertiesList)
1113             {
1114                 if (property.first == "UfmProvisioned")
1115                 {
1116                     provState = std::get_if<bool>(&property.second);
1117                 }
1118                 else if (property.first == "UfmLocked")
1119                 {
1120                     lockState = std::get_if<bool>(&property.second);
1121                 }
1122             }
1123 
1124             if ((provState == nullptr) || (lockState == nullptr))
1125             {
1126                 BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
1127                 messages::internalError(aResp->res);
1128                 return;
1129             }
1130 
1131             nlohmann::json &oemPFR =
1132                 aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1133             if (*provState == true)
1134             {
1135                 if (*lockState == true)
1136                 {
1137                     oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
1138                 }
1139                 else
1140                 {
1141                     oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
1142                 }
1143             }
1144             else
1145             {
1146                 oemPFR["ProvisioningStatus"] = "NotProvisioned";
1147             }
1148         },
1149         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1150         "org.freedesktop.DBus.Properties", "GetAll",
1151         "xyz.openbmc_project.PFR.Attributes");
1152 }
1153 #endif
1154 
1155 /**
1156  * @brief Translates watchdog timeout action DBUS property value to redfish.
1157  *
1158  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1159  *
1160  * @return Returns as a string, the timeout action in Redfish terms. If
1161  * translation cannot be done, returns an empty string.
1162  */
1163 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1164 {
1165     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1166     {
1167         return "None";
1168     }
1169     else if (dbusAction ==
1170              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1171     {
1172         return "ResetSystem";
1173     }
1174     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1175     {
1176         return "PowerDown";
1177     }
1178     else if (dbusAction ==
1179              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1180     {
1181         return "PowerCycle";
1182     }
1183 
1184     return "";
1185 }
1186 
1187 /**
1188  *@brief Translates timeout action from Redfish to DBUS property value.
1189  *
1190  *@param[in] rfAction The timeout action in Redfish.
1191  *
1192  *@return Returns as a string, the time_out action as expected by DBUS.
1193  *If translation cannot be done, returns an empty string.
1194  */
1195 
1196 static std::string rfToDbusWDTTimeOutAct(const std::string &rfAction)
1197 {
1198     if (rfAction == "None")
1199     {
1200         return "xyz.openbmc_project.State.Watchdog.Action.None";
1201     }
1202     else if (rfAction == "PowerCycle")
1203     {
1204         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
1205     }
1206     else if (rfAction == "PowerDown")
1207     {
1208         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
1209     }
1210     else if (rfAction == "ResetSystem")
1211     {
1212         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
1213     }
1214 
1215     return "";
1216 }
1217 
1218 /**
1219  * @brief Retrieves host watchdog timer properties over DBUS
1220  *
1221  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1222  *
1223  * @return None.
1224  */
1225 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1226 {
1227     BMCWEB_LOG_DEBUG << "Get host watchodg";
1228     crow::connections::systemBus->async_method_call(
1229         [aResp](const boost::system::error_code ec,
1230                 PropertiesType &properties) {
1231             if (ec)
1232             {
1233                 // watchdog service is stopped
1234                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1235                 return;
1236             }
1237 
1238             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1239 
1240             nlohmann::json &hostWatchdogTimer =
1241                 aResp->res.jsonValue["HostWatchdogTimer"];
1242 
1243             // watchdog service is running/enabled
1244             hostWatchdogTimer["Status"]["State"] = "Enabled";
1245 
1246             for (const auto &property : properties)
1247             {
1248                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1249                 if (property.first == "Enabled")
1250                 {
1251                     const bool *state = std::get_if<bool>(&property.second);
1252 
1253                     if (!state)
1254                     {
1255                         messages::internalError(aResp->res);
1256                         continue;
1257                     }
1258 
1259                     hostWatchdogTimer["FunctionEnabled"] = *state;
1260                 }
1261                 else if (property.first == "ExpireAction")
1262                 {
1263                     const std::string *s =
1264                         std::get_if<std::string>(&property.second);
1265                     if (!s)
1266                     {
1267                         messages::internalError(aResp->res);
1268                         continue;
1269                     }
1270 
1271                     std::string action = dbusToRfWatchdogAction(*s);
1272                     if (action.empty())
1273                     {
1274                         messages::internalError(aResp->res);
1275                         continue;
1276                     }
1277                     hostWatchdogTimer["TimeoutAction"] = action;
1278                 }
1279             }
1280         },
1281         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1282         "org.freedesktop.DBus.Properties", "GetAll",
1283         "xyz.openbmc_project.State.Watchdog");
1284 }
1285 
1286 /**
1287  * @brief Sets Host WatchDog Timer properties.
1288  *
1289  * @param[in] aResp      Shared pointer for generating response message.
1290  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
1291  *                       RF request.
1292  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
1293  *
1294  * @return None.
1295  */
1296 static void setWDTProperties(std::shared_ptr<AsyncResp> aResp,
1297                              const std::optional<bool> wdtEnable,
1298                              const std::optional<std::string> &wdtTimeOutAction)
1299 {
1300     BMCWEB_LOG_DEBUG << "Set host watchdog";
1301 
1302     if (wdtTimeOutAction)
1303     {
1304         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
1305         // check if TimeOut Action is Valid
1306         if (wdtTimeOutActStr.empty())
1307         {
1308             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
1309                              << *wdtTimeOutAction;
1310             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
1311                                              "TimeoutAction");
1312             return;
1313         }
1314 
1315         crow::connections::systemBus->async_method_call(
1316             [aResp](const boost::system::error_code ec) {
1317                 if (ec)
1318                 {
1319                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1320                     messages::internalError(aResp->res);
1321                     return;
1322                 }
1323             },
1324             "xyz.openbmc_project.Watchdog",
1325             "/xyz/openbmc_project/watchdog/host0",
1326             "org.freedesktop.DBus.Properties", "Set",
1327             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
1328             std::variant<std::string>(wdtTimeOutActStr));
1329     }
1330 
1331     if (wdtEnable)
1332     {
1333         crow::connections::systemBus->async_method_call(
1334             [aResp](const boost::system::error_code ec) {
1335                 if (ec)
1336                 {
1337                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1338                     messages::internalError(aResp->res);
1339                     return;
1340                 }
1341             },
1342             "xyz.openbmc_project.Watchdog",
1343             "/xyz/openbmc_project/watchdog/host0",
1344             "org.freedesktop.DBus.Properties", "Set",
1345             "xyz.openbmc_project.State.Watchdog", "Enabled",
1346             std::variant<bool>(*wdtEnable));
1347     }
1348 }
1349 
1350 /**
1351  * SystemsCollection derived class for delivering ComputerSystems Collection
1352  * Schema
1353  */
1354 class SystemsCollection : public Node
1355 {
1356   public:
1357     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1358     {
1359         entityPrivileges = {
1360             {boost::beast::http::verb::get, {{"Login"}}},
1361             {boost::beast::http::verb::head, {{"Login"}}},
1362             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1363             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1364             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1365             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1366     }
1367 
1368   private:
1369     void doGet(crow::Response &res, const crow::Request &req,
1370                const std::vector<std::string> &params) override
1371     {
1372         res.jsonValue["@odata.type"] =
1373             "#ComputerSystemCollection.ComputerSystemCollection";
1374         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1375         res.jsonValue["Name"] = "Computer System Collection";
1376         res.jsonValue["Members"] = {
1377             {{"@odata.id", "/redfish/v1/Systems/system"}}};
1378         res.jsonValue["Members@odata.count"] = 1;
1379         res.end();
1380     }
1381 };
1382 
1383 /**
1384  * SystemActionsReset class supports handle POST method for Reset action.
1385  * The class retrieves and sends data directly to D-Bus.
1386  */
1387 class SystemActionsReset : public Node
1388 {
1389   public:
1390     SystemActionsReset(CrowApp &app) :
1391         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1392     {
1393         entityPrivileges = {
1394             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1395     }
1396 
1397   private:
1398     /**
1399      * Function handles POST method request.
1400      * Analyzes POST body message before sends Reset request data to D-Bus.
1401      */
1402     void doPost(crow::Response &res, const crow::Request &req,
1403                 const std::vector<std::string> &params) override
1404     {
1405         auto asyncResp = std::make_shared<AsyncResp>(res);
1406 
1407         std::string resetType;
1408         if (!json_util::readJson(req, res, "ResetType", resetType))
1409         {
1410             return;
1411         }
1412 
1413         // Get the command and host vs. chassis
1414         std::string command;
1415         bool hostCommand;
1416         if (resetType == "On")
1417         {
1418             command = "xyz.openbmc_project.State.Host.Transition.On";
1419             hostCommand = true;
1420         }
1421         else if (resetType == "ForceOff")
1422         {
1423             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1424             hostCommand = false;
1425         }
1426         else if (resetType == "ForceOn")
1427         {
1428             command = "xyz.openbmc_project.State.Host.Transition.On";
1429             hostCommand = true;
1430         }
1431         else if (resetType == "ForceRestart")
1432         {
1433             command =
1434                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1435             hostCommand = true;
1436         }
1437         else if (resetType == "GracefulShutdown")
1438         {
1439             command = "xyz.openbmc_project.State.Host.Transition.Off";
1440             hostCommand = true;
1441         }
1442         else if (resetType == "GracefulRestart")
1443         {
1444             command =
1445                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
1446             hostCommand = true;
1447         }
1448         else if (resetType == "PowerCycle")
1449         {
1450             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1451             hostCommand = true;
1452         }
1453         else if (resetType == "Nmi")
1454         {
1455             doNMI(asyncResp);
1456             return;
1457         }
1458         else
1459         {
1460             messages::actionParameterUnknown(res, "Reset", resetType);
1461             return;
1462         }
1463 
1464         if (hostCommand)
1465         {
1466             crow::connections::systemBus->async_method_call(
1467                 [asyncResp, resetType](const boost::system::error_code ec) {
1468                     if (ec)
1469                     {
1470                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1471                         if (ec.value() == boost::asio::error::invalid_argument)
1472                         {
1473                             messages::actionParameterNotSupported(
1474                                 asyncResp->res, resetType, "Reset");
1475                         }
1476                         else
1477                         {
1478                             messages::internalError(asyncResp->res);
1479                         }
1480                         return;
1481                     }
1482                     messages::success(asyncResp->res);
1483                 },
1484                 "xyz.openbmc_project.State.Host",
1485                 "/xyz/openbmc_project/state/host0",
1486                 "org.freedesktop.DBus.Properties", "Set",
1487                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1488                 std::variant<std::string>{command});
1489         }
1490         else
1491         {
1492             crow::connections::systemBus->async_method_call(
1493                 [asyncResp, resetType](const boost::system::error_code ec) {
1494                     if (ec)
1495                     {
1496                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1497                         if (ec.value() == boost::asio::error::invalid_argument)
1498                         {
1499                             messages::actionParameterNotSupported(
1500                                 asyncResp->res, resetType, "Reset");
1501                         }
1502                         else
1503                         {
1504                             messages::internalError(asyncResp->res);
1505                         }
1506                         return;
1507                     }
1508                     messages::success(asyncResp->res);
1509                 },
1510                 "xyz.openbmc_project.State.Chassis",
1511                 "/xyz/openbmc_project/state/chassis0",
1512                 "org.freedesktop.DBus.Properties", "Set",
1513                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1514                 std::variant<std::string>{command});
1515         }
1516     }
1517     /**
1518      * Function transceives data with dbus directly.
1519      */
1520     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1521     {
1522         constexpr char const *serviceName =
1523             "xyz.openbmc_project.Control.Host.NMI";
1524         constexpr char const *objectPath =
1525             "/xyz/openbmc_project/control/host0/nmi";
1526         constexpr char const *interfaceName =
1527             "xyz.openbmc_project.Control.Host.NMI";
1528         constexpr char const *method = "NMI";
1529 
1530         crow::connections::systemBus->async_method_call(
1531             [asyncResp](const boost::system::error_code ec) {
1532                 if (ec)
1533                 {
1534                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1535                     messages::internalError(asyncResp->res);
1536                     return;
1537                 }
1538                 messages::success(asyncResp->res);
1539             },
1540             serviceName, objectPath, interfaceName, method);
1541     }
1542 };
1543 
1544 /**
1545  * Systems derived class for delivering Computer Systems Schema.
1546  */
1547 class Systems : public Node
1548 {
1549   public:
1550     /*
1551      * Default Constructor
1552      */
1553     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1554     {
1555         entityPrivileges = {
1556             {boost::beast::http::verb::get, {{"Login"}}},
1557             {boost::beast::http::verb::head, {{"Login"}}},
1558             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1559             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1560             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1561             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1562     }
1563 
1564   private:
1565     /**
1566      * Functions triggers appropriate requests on DBus
1567      */
1568     void doGet(crow::Response &res, const crow::Request &req,
1569                const std::vector<std::string> &params) override
1570     {
1571         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1572         res.jsonValue["Name"] = "Computer System";
1573         res.jsonValue["Id"] = "system";
1574         res.jsonValue["SystemType"] = "Physical";
1575         res.jsonValue["Description"] = "Computer System";
1576         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1577         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1578         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = uint64_t(0);
1579         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1580         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1581 
1582         res.jsonValue["Processors"] = {
1583             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1584         res.jsonValue["Memory"] = {
1585             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1586         res.jsonValue["Storage"] = {
1587             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1588 
1589         // TODO Need to support ForceRestart.
1590         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1591             {"target",
1592              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1593             {"ResetType@Redfish.AllowableValues",
1594              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1595               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1596 
1597         res.jsonValue["LogServices"] = {
1598             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1599 
1600         res.jsonValue["Bios"] = {
1601             {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
1602 
1603         res.jsonValue["Links"]["ManagedBy"] = {
1604             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1605 
1606         res.jsonValue["Status"] = {
1607             {"Health", "OK"},
1608             {"State", "Enabled"},
1609         };
1610         auto asyncResp = std::make_shared<AsyncResp>(res);
1611 
1612         constexpr const std::array<const char *, 4> inventoryForSystems = {
1613             "xyz.openbmc_project.Inventory.Item.Dimm",
1614             "xyz.openbmc_project.Inventory.Item.Cpu",
1615             "xyz.openbmc_project.Inventory.Item.Drive",
1616             "xyz.openbmc_project.Inventory.Item.StorageController"};
1617 
1618         auto health = std::make_shared<HealthPopulate>(asyncResp);
1619         crow::connections::systemBus->async_method_call(
1620             [health](const boost::system::error_code ec,
1621                      std::vector<std::string> &resp) {
1622                 if (ec)
1623                 {
1624                     // no inventory
1625                     return;
1626                 }
1627 
1628                 health->inventory = std::move(resp);
1629             },
1630             "xyz.openbmc_project.ObjectMapper",
1631             "/xyz/openbmc_project/object_mapper",
1632             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1633             int32_t(0), inventoryForSystems);
1634 
1635         health->populate();
1636 
1637         getMainChassisId(asyncResp, [](const std::string &chassisId,
1638                                        std::shared_ptr<AsyncResp> aRsp) {
1639             aRsp->res.jsonValue["Links"]["Chassis"] = {
1640                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1641         });
1642 
1643         getIndicatorLedState(asyncResp);
1644         getComputerSystem(asyncResp, health);
1645         getHostState(asyncResp);
1646         getBootProperties(asyncResp);
1647         getPCIeDeviceList(asyncResp, "PCIeDevices");
1648         getHostWatchdogTimer(asyncResp);
1649 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1650         getProvisioningStatus(asyncResp);
1651 #endif
1652     }
1653 
1654     void doPatch(crow::Response &res, const crow::Request &req,
1655                  const std::vector<std::string> &params) override
1656     {
1657         std::optional<std::string> indicatorLed;
1658         std::optional<nlohmann::json> bootProps;
1659         std::optional<nlohmann::json> wdtTimerProps;
1660         auto asyncResp = std::make_shared<AsyncResp>(res);
1661 
1662         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1663                                  bootProps, "WatchdogTimer", wdtTimerProps))
1664         {
1665             return;
1666         }
1667 
1668         res.result(boost::beast::http::status::no_content);
1669 
1670         if (wdtTimerProps)
1671         {
1672             std::optional<bool> wdtEnable;
1673             std::optional<std::string> wdtTimeOutAction;
1674 
1675             if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
1676                                      "FunctionEnabled", wdtEnable,
1677                                      "TimeoutAction", wdtTimeOutAction))
1678             {
1679                 return;
1680             }
1681             setWDTProperties(asyncResp, std::move(wdtEnable),
1682                              std::move(wdtTimeOutAction));
1683         }
1684 
1685         if (bootProps)
1686         {
1687             std::optional<std::string> bootSource;
1688             std::optional<std::string> bootEnable;
1689 
1690             if (!json_util::readJson(*bootProps, asyncResp->res,
1691                                      "BootSourceOverrideTarget", bootSource,
1692                                      "BootSourceOverrideEnabled", bootEnable))
1693             {
1694                 return;
1695             }
1696             setBootProperties(asyncResp, std::move(bootSource),
1697                               std::move(bootEnable));
1698         }
1699 
1700         if (indicatorLed)
1701         {
1702             setIndicatorLedState(asyncResp, std::move(*indicatorLed));
1703         }
1704     }
1705 };
1706 } // namespace redfish
1707