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