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