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