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