xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 51709ffd22973ca2212f221e80e72984627c80c1)
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 /**
1161  * @brief Translates watchdog timeout action DBUS property value to redfish.
1162  *
1163  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
1164  *
1165  * @return Returns as a string, the timeout action in Redfish terms. If
1166  * translation cannot be done, returns an empty string.
1167  */
1168 static std::string dbusToRfWatchdogAction(const std::string &dbusAction)
1169 {
1170     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
1171     {
1172         return "None";
1173     }
1174     else if (dbusAction ==
1175              "xyz.openbmc_project.State.Watchdog.Action.HardReset")
1176     {
1177         return "ResetSystem";
1178     }
1179     else if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
1180     {
1181         return "PowerDown";
1182     }
1183     else if (dbusAction ==
1184              "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
1185     {
1186         return "PowerCycle";
1187     }
1188 
1189     return "";
1190 }
1191 
1192 /**
1193  * @brief Retrieves host watchdog timer properties over DBUS
1194  *
1195  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1196  *
1197  * @return None.
1198  */
1199 void getHostWatchdogTimer(std::shared_ptr<AsyncResp> aResp)
1200 {
1201     BMCWEB_LOG_DEBUG << "Get host watchodg";
1202     crow::connections::systemBus->async_method_call(
1203         [aResp](const boost::system::error_code ec,
1204                 PropertiesType &properties) {
1205             if (ec)
1206             {
1207                 // watchdog service is stopped
1208                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1209                 return;
1210             }
1211 
1212             BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
1213 
1214             nlohmann::json &hostWatchdogTimer =
1215                 aResp->res.jsonValue["HostWatchdogTimer"];
1216 
1217             // watchdog service is running/enabled
1218             hostWatchdogTimer["Status"]["State"] = "Enabled";
1219 
1220             for (const auto &property : properties)
1221             {
1222                 BMCWEB_LOG_DEBUG << "prop=" << property.first;
1223                 if (property.first == "Enabled")
1224                 {
1225                     const bool *state = std::get_if<bool>(&property.second);
1226 
1227                     if (!state)
1228                     {
1229                         messages::internalError(aResp->res);
1230                         continue;
1231                     }
1232 
1233                     hostWatchdogTimer["FunctionEnabled"] = *state;
1234                 }
1235                 else if (property.first == "ExpireAction")
1236                 {
1237                     const std::string *s =
1238                         std::get_if<std::string>(&property.second);
1239                     if (!s)
1240                     {
1241                         messages::internalError(aResp->res);
1242                         continue;
1243                     }
1244 
1245                     std::string action = dbusToRfWatchdogAction(*s);
1246                     if (action.empty())
1247                     {
1248                         messages::internalError(aResp->res);
1249                         continue;
1250                     }
1251                     hostWatchdogTimer["TimeoutAction"] = action;
1252                 }
1253             }
1254         },
1255         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
1256         "org.freedesktop.DBus.Properties", "GetAll",
1257         "xyz.openbmc_project.State.Watchdog");
1258 }
1259 
1260 /**
1261  * SystemsCollection derived class for delivering ComputerSystems Collection
1262  * Schema
1263  */
1264 class SystemsCollection : public Node
1265 {
1266   public:
1267     SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
1268     {
1269         entityPrivileges = {
1270             {boost::beast::http::verb::get, {{"Login"}}},
1271             {boost::beast::http::verb::head, {{"Login"}}},
1272             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1273             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1274             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1275             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1276     }
1277 
1278   private:
1279     void doGet(crow::Response &res, const crow::Request &req,
1280                const std::vector<std::string> &params) override
1281     {
1282         res.jsonValue["@odata.type"] =
1283             "#ComputerSystemCollection.ComputerSystemCollection";
1284         res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1285         res.jsonValue["@odata.context"] =
1286             "/redfish/v1/"
1287             "$metadata#ComputerSystemCollection.ComputerSystemCollection";
1288         res.jsonValue["Name"] = "Computer System Collection";
1289         res.jsonValue["Members"] = {
1290             {{"@odata.id", "/redfish/v1/Systems/system"}}};
1291         res.jsonValue["Members@odata.count"] = 1;
1292         res.end();
1293     }
1294 };
1295 
1296 /**
1297  * SystemActionsReset class supports handle POST method for Reset action.
1298  * The class retrieves and sends data directly to D-Bus.
1299  */
1300 class SystemActionsReset : public Node
1301 {
1302   public:
1303     SystemActionsReset(CrowApp &app) :
1304         Node(app, "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1305     {
1306         entityPrivileges = {
1307             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1308     }
1309 
1310   private:
1311     /**
1312      * Function handles POST method request.
1313      * Analyzes POST body message before sends Reset request data to D-Bus.
1314      */
1315     void doPost(crow::Response &res, const crow::Request &req,
1316                 const std::vector<std::string> &params) override
1317     {
1318         auto asyncResp = std::make_shared<AsyncResp>(res);
1319 
1320         std::string resetType;
1321         if (!json_util::readJson(req, res, "ResetType", resetType))
1322         {
1323             return;
1324         }
1325 
1326         // Get the command and host vs. chassis
1327         std::string command;
1328         bool hostCommand;
1329         if (resetType == "On")
1330         {
1331             command = "xyz.openbmc_project.State.Host.Transition.On";
1332             hostCommand = true;
1333         }
1334         else if (resetType == "ForceOff")
1335         {
1336             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1337             hostCommand = false;
1338         }
1339         else if (resetType == "ForceOn")
1340         {
1341             command = "xyz.openbmc_project.State.Host.Transition.On";
1342             hostCommand = true;
1343         }
1344         else if (resetType == "ForceRestart")
1345         {
1346             command = "xyz.openbmc_project.State.Chassis.Transition.Reset";
1347             hostCommand = false;
1348         }
1349         else if (resetType == "GracefulShutdown")
1350         {
1351             command = "xyz.openbmc_project.State.Host.Transition.Off";
1352             hostCommand = true;
1353         }
1354         else if (resetType == "GracefulRestart")
1355         {
1356             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1357             hostCommand = true;
1358         }
1359         else if (resetType == "PowerCycle")
1360         {
1361             command = "xyz.openbmc_project.State.Chassis.Transition.PowerCycle";
1362             hostCommand = false;
1363         }
1364         else if (resetType == "Nmi")
1365         {
1366             doNMI(asyncResp);
1367             return;
1368         }
1369         else
1370         {
1371             messages::actionParameterUnknown(res, "Reset", resetType);
1372             return;
1373         }
1374 
1375         if (hostCommand)
1376         {
1377             crow::connections::systemBus->async_method_call(
1378                 [asyncResp, resetType](const boost::system::error_code ec) {
1379                     if (ec)
1380                     {
1381                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1382                         if (ec.value() == boost::asio::error::invalid_argument)
1383                         {
1384                             messages::actionParameterNotSupported(
1385                                 asyncResp->res, resetType, "Reset");
1386                         }
1387                         else
1388                         {
1389                             messages::internalError(asyncResp->res);
1390                         }
1391                         return;
1392                     }
1393                     messages::success(asyncResp->res);
1394                 },
1395                 "xyz.openbmc_project.State.Host",
1396                 "/xyz/openbmc_project/state/host0",
1397                 "org.freedesktop.DBus.Properties", "Set",
1398                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
1399                 std::variant<std::string>{command});
1400         }
1401         else
1402         {
1403             crow::connections::systemBus->async_method_call(
1404                 [asyncResp, resetType](const boost::system::error_code ec) {
1405                     if (ec)
1406                     {
1407                         BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1408                         if (ec.value() == boost::asio::error::invalid_argument)
1409                         {
1410                             messages::actionParameterNotSupported(
1411                                 asyncResp->res, resetType, "Reset");
1412                         }
1413                         else
1414                         {
1415                             messages::internalError(asyncResp->res);
1416                         }
1417                         return;
1418                     }
1419                     messages::success(asyncResp->res);
1420                 },
1421                 "xyz.openbmc_project.State.Chassis",
1422                 "/xyz/openbmc_project/state/chassis0",
1423                 "org.freedesktop.DBus.Properties", "Set",
1424                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
1425                 std::variant<std::string>{command});
1426         }
1427     }
1428     /**
1429      * Function transceives data with dbus directly.
1430      */
1431     void doNMI(const std::shared_ptr<AsyncResp> &asyncResp)
1432     {
1433         constexpr char const *serviceName =
1434             "xyz.openbmc_project.Control.Host.NMI";
1435         constexpr char const *objectPath =
1436             "/xyz/openbmc_project/control/host0/nmi";
1437         constexpr char const *interfaceName =
1438             "xyz.openbmc_project.Control.Host.NMI";
1439         constexpr char const *method = "NMI";
1440 
1441         crow::connections::systemBus->async_method_call(
1442             [asyncResp](const boost::system::error_code ec) {
1443                 if (ec)
1444                 {
1445                     BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1446                     messages::internalError(asyncResp->res);
1447                     return;
1448                 }
1449                 messages::success(asyncResp->res);
1450             },
1451             serviceName, objectPath, interfaceName, method);
1452     }
1453 };
1454 
1455 /**
1456  * Systems derived class for delivering Computer Systems Schema.
1457  */
1458 class Systems : public Node
1459 {
1460   public:
1461     /*
1462      * Default Constructor
1463      */
1464     Systems(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/")
1465     {
1466         entityPrivileges = {
1467             {boost::beast::http::verb::get, {{"Login"}}},
1468             {boost::beast::http::verb::head, {{"Login"}}},
1469             {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
1470             {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
1471             {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
1472             {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
1473     }
1474 
1475   private:
1476     /**
1477      * Functions triggers appropriate requests on DBus
1478      */
1479     void doGet(crow::Response &res, const crow::Request &req,
1480                const std::vector<std::string> &params) override
1481     {
1482         res.jsonValue["@odata.type"] = "#ComputerSystem.v1_6_0.ComputerSystem";
1483         res.jsonValue["@odata.context"] =
1484             "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
1485         res.jsonValue["Name"] = "Computer System";
1486         res.jsonValue["Id"] = "system";
1487         res.jsonValue["SystemType"] = "Physical";
1488         res.jsonValue["Description"] = "Computer System";
1489         res.jsonValue["ProcessorSummary"]["Count"] = 0;
1490         res.jsonValue["ProcessorSummary"]["Status"]["State"] = "Disabled";
1491         res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
1492         res.jsonValue["MemorySummary"]["Status"]["State"] = "Disabled";
1493         res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
1494 
1495         res.jsonValue["Processors"] = {
1496             {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
1497         res.jsonValue["Memory"] = {
1498             {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
1499         res.jsonValue["Storage"] = {
1500             {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
1501 
1502         // TODO Need to support ForceRestart.
1503         res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
1504             {"target",
1505              "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
1506             {"ResetType@Redfish.AllowableValues",
1507              {"On", "ForceOff", "ForceOn", "ForceRestart", "GracefulRestart",
1508               "GracefulShutdown", "PowerCycle", "Nmi"}}};
1509 
1510         res.jsonValue["LogServices"] = {
1511             {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
1512 
1513         res.jsonValue["Links"]["ManagedBy"] = {
1514             {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
1515 
1516         res.jsonValue["Status"] = {
1517             {"Health", "OK"},
1518             {"State", "Enabled"},
1519         };
1520         auto asyncResp = std::make_shared<AsyncResp>(res);
1521 
1522         constexpr const std::array<const char *, 2> inventoryForSystems = {
1523             "xyz.openbmc_project.Inventory.Item.Dimm",
1524             "xyz.openbmc_project.Inventory.Item.Cpu"};
1525 
1526         auto health = std::make_shared<HealthPopulate>(asyncResp);
1527         crow::connections::systemBus->async_method_call(
1528             [health](const boost::system::error_code ec,
1529                      std::vector<std::string> &resp) {
1530                 if (ec)
1531                 {
1532                     // no inventory
1533                     return;
1534                 }
1535 
1536                 health->inventory = std::move(resp);
1537             },
1538             "xyz.openbmc_project.ObjectMapper",
1539             "/xyz/openbmc_project/object_mapper",
1540             "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
1541             int32_t(0), inventoryForSystems);
1542 
1543         health->populate();
1544 
1545         getMainChassisId(asyncResp, [](const std::string &chassisId,
1546                                        std::shared_ptr<AsyncResp> aRsp) {
1547             aRsp->res.jsonValue["Links"]["Chassis"] = {
1548                 {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
1549         });
1550         getLedGroupIdentify(
1551             asyncResp,
1552             [](const bool &asserted, const std::shared_ptr<AsyncResp> aRsp) {
1553                 if (asserted)
1554                 {
1555                     // If led group is asserted, then another call is needed to
1556                     // get led status
1557                     getLedIdentify(
1558                         aRsp, [](const std::string &ledStatus,
1559                                  const std::shared_ptr<AsyncResp> aRsp) {
1560                             if (!ledStatus.empty())
1561                             {
1562                                 aRsp->res.jsonValue["IndicatorLED"] = ledStatus;
1563                             }
1564                         });
1565                 }
1566                 else
1567                 {
1568                     aRsp->res.jsonValue["IndicatorLED"] = "Off";
1569                 }
1570             });
1571         getComputerSystem(asyncResp, health);
1572         getHostState(asyncResp);
1573         getBootProperties(asyncResp);
1574         getPCIeDeviceList(asyncResp);
1575         getHostWatchdogTimer(asyncResp);
1576     }
1577 
1578     void doPatch(crow::Response &res, const crow::Request &req,
1579                  const std::vector<std::string> &params) override
1580     {
1581         std::optional<std::string> indicatorLed;
1582         std::optional<nlohmann::json> bootProps;
1583         auto asyncResp = std::make_shared<AsyncResp>(res);
1584 
1585         if (!json_util::readJson(req, res, "IndicatorLED", indicatorLed, "Boot",
1586                                  bootProps))
1587         {
1588             return;
1589         }
1590 
1591         res.result(boost::beast::http::status::no_content);
1592         if (bootProps)
1593         {
1594             std::optional<std::string> bootSource;
1595             std::optional<std::string> bootEnable;
1596 
1597             if (!json_util::readJson(*bootProps, asyncResp->res,
1598                                      "BootSourceOverrideTarget", bootSource,
1599                                      "BootSourceOverrideEnabled", bootEnable))
1600             {
1601                 return;
1602             }
1603             setBootProperties(asyncResp, std::move(bootSource),
1604                               std::move(bootEnable));
1605         }
1606 
1607         if (indicatorLed)
1608         {
1609             std::string dbusLedState;
1610             if (*indicatorLed == "Lit")
1611             {
1612                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.On";
1613             }
1614             else if (*indicatorLed == "Blinking")
1615             {
1616                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Blink";
1617             }
1618             else if (*indicatorLed == "Off")
1619             {
1620                 dbusLedState = "xyz.openbmc_project.Led.Physical.Action.Off";
1621             }
1622             else
1623             {
1624                 messages::propertyValueNotInList(res, *indicatorLed,
1625                                                  "IndicatorLED");
1626                 return;
1627             }
1628 
1629             // Update led group
1630             BMCWEB_LOG_DEBUG << "Update led group.";
1631             crow::connections::systemBus->async_method_call(
1632                 [asyncResp](const boost::system::error_code ec) {
1633                     if (ec)
1634                     {
1635                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1636                         messages::internalError(asyncResp->res);
1637                         return;
1638                     }
1639                     BMCWEB_LOG_DEBUG << "Led group update done.";
1640                 },
1641                 "xyz.openbmc_project.LED.GroupManager",
1642                 "/xyz/openbmc_project/led/groups/enclosure_identify",
1643                 "org.freedesktop.DBus.Properties", "Set",
1644                 "xyz.openbmc_project.Led.Group", "Asserted",
1645                 std::variant<bool>(
1646                     (dbusLedState !=
1647                      "xyz.openbmc_project.Led.Physical.Action.Off")));
1648 
1649             // Update identify led status
1650             BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
1651             crow::connections::systemBus->async_method_call(
1652                 [asyncResp](const boost::system::error_code ec) {
1653                     if (ec)
1654                     {
1655                         BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1656                         messages::internalError(asyncResp->res);
1657                         return;
1658                     }
1659                     BMCWEB_LOG_DEBUG << "Led state update done.";
1660                 },
1661                 "xyz.openbmc_project.LED.Controller.identify",
1662                 "/xyz/openbmc_project/led/physical/identify",
1663                 "org.freedesktop.DBus.Properties", "Set",
1664                 "xyz.openbmc_project.Led.Physical", "State",
1665                 std::variant<std::string>(dbusLedState));
1666         }
1667     }
1668 };
1669 } // namespace redfish
1670