xref: /openbmc/bmcweb/features/redfish/lib/systems.hpp (revision 432a890cfca335e565b770b1604ed4e547c5a732)
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 <app.hpp>
24 #include <boost/container/flat_map.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 inline void requestRoutesSystemsCollection(App& app)
1862 {
1863     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
1864         .privileges({{"Login"}})
1865         .methods(boost::beast::http::verb::get)(
1866             [](const crow::Request& req,
1867                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1868                 asyncResp->res.jsonValue["@odata.type"] =
1869                     "#ComputerSystemCollection.ComputerSystemCollection";
1870                 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
1871                 asyncResp->res.jsonValue["Name"] = "Computer System Collection";
1872 
1873                 crow::connections::systemBus->async_method_call(
1874                     [asyncResp,
1875                      &req](const boost::system::error_code ec,
1876                            const std::variant<std::string>& /*hostName*/) {
1877                         nlohmann::json& ifaceArray =
1878                             asyncResp->res.jsonValue["Members"];
1879                         ifaceArray = nlohmann::json::array();
1880                         auto& count =
1881                             asyncResp->res.jsonValue["Members@odata.count"];
1882                         ifaceArray.push_back(
1883                             {{"@odata.id", "/redfish/v1/Systems/system"}});
1884                         count = ifaceArray.size();
1885                         if (!ec)
1886                         {
1887                             BMCWEB_LOG_DEBUG << "Hypervisor is available";
1888                             ifaceArray.push_back(
1889                                 {{"@odata.id",
1890                                   "/redfish/v1/Systems/hypervisor"}});
1891                             count = ifaceArray.size();
1892                         }
1893                     },
1894                     "xyz.openbmc_project.Settings",
1895                     "/xyz/openbmc_project/network/hypervisor",
1896                     "org.freedesktop.DBus.Properties", "Get",
1897                     "xyz.openbmc_project.Network.SystemConfiguration",
1898                     "HostName");
1899             });
1900 }
1901 
1902 /**
1903  * Function transceives data with dbus directly.
1904  */
1905 void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1906 {
1907     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI";
1908     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi";
1909     constexpr char const* interfaceName =
1910         "xyz.openbmc_project.Control.Host.NMI";
1911     constexpr char const* method = "NMI";
1912 
1913     crow::connections::systemBus->async_method_call(
1914         [asyncResp](const boost::system::error_code ec) {
1915             if (ec)
1916             {
1917                 BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
1918                 messages::internalError(asyncResp->res);
1919                 return;
1920             }
1921             messages::success(asyncResp->res);
1922         },
1923         serviceName, objectPath, interfaceName, method);
1924 }
1925 
1926 /**
1927  * SystemActionsReset class supports handle POST method for Reset action.
1928  * The class retrieves and sends data directly to D-Bus.
1929  */
1930 inline void requestRoutesSystemActionsReset(App& app)
1931 {
1932     /**
1933      * Function handles POST method request.
1934      * Analyzes POST body message before sends Reset request data to D-Bus.
1935      */
1936     BMCWEB_ROUTE(app,
1937                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
1938         .privileges({{"ConfigureComponent"}})
1939         .methods(
1940             boost::beast::http::verb::
1941                 post)([](const crow::Request& req,
1942                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1943             std::string resetType;
1944             if (!json_util::readJson(req, asyncResp->res, "ResetType",
1945                                      resetType))
1946             {
1947                 return;
1948             }
1949 
1950             // Get the command and host vs. chassis
1951             std::string command;
1952             bool hostCommand;
1953             if ((resetType == "On") || (resetType == "ForceOn"))
1954             {
1955                 command = "xyz.openbmc_project.State.Host.Transition.On";
1956                 hostCommand = true;
1957             }
1958             else if (resetType == "ForceOff")
1959             {
1960                 command = "xyz.openbmc_project.State.Chassis.Transition.Off";
1961                 hostCommand = false;
1962             }
1963             else if (resetType == "ForceRestart")
1964             {
1965                 command =
1966                     "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
1967                 hostCommand = true;
1968             }
1969             else if (resetType == "GracefulShutdown")
1970             {
1971                 command = "xyz.openbmc_project.State.Host.Transition.Off";
1972                 hostCommand = true;
1973             }
1974             else if (resetType == "GracefulRestart")
1975             {
1976                 command = "xyz.openbmc_project.State.Host.Transition."
1977                           "GracefulWarmReboot";
1978                 hostCommand = true;
1979             }
1980             else if (resetType == "PowerCycle")
1981             {
1982                 command = "xyz.openbmc_project.State.Host.Transition.Reboot";
1983                 hostCommand = true;
1984             }
1985             else if (resetType == "Nmi")
1986             {
1987                 doNMI(asyncResp);
1988                 return;
1989             }
1990             else
1991             {
1992                 messages::actionParameterUnknown(asyncResp->res, "Reset",
1993                                                  resetType);
1994                 return;
1995             }
1996 
1997             if (hostCommand)
1998             {
1999                 crow::connections::systemBus->async_method_call(
2000                     [asyncResp, resetType](const boost::system::error_code ec) {
2001                         if (ec)
2002                         {
2003                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2004                             if (ec.value() ==
2005                                 boost::asio::error::invalid_argument)
2006                             {
2007                                 messages::actionParameterNotSupported(
2008                                     asyncResp->res, resetType, "Reset");
2009                             }
2010                             else
2011                             {
2012                                 messages::internalError(asyncResp->res);
2013                             }
2014                             return;
2015                         }
2016                         messages::success(asyncResp->res);
2017                     },
2018                     "xyz.openbmc_project.State.Host",
2019                     "/xyz/openbmc_project/state/host0",
2020                     "org.freedesktop.DBus.Properties", "Set",
2021                     "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2022                     std::variant<std::string>{command});
2023             }
2024             else
2025             {
2026                 crow::connections::systemBus->async_method_call(
2027                     [asyncResp, resetType](const boost::system::error_code ec) {
2028                         if (ec)
2029                         {
2030                             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2031                             if (ec.value() ==
2032                                 boost::asio::error::invalid_argument)
2033                             {
2034                                 messages::actionParameterNotSupported(
2035                                     asyncResp->res, resetType, "Reset");
2036                             }
2037                             else
2038                             {
2039                                 messages::internalError(asyncResp->res);
2040                             }
2041                             return;
2042                         }
2043                         messages::success(asyncResp->res);
2044                     },
2045                     "xyz.openbmc_project.State.Chassis",
2046                     "/xyz/openbmc_project/state/chassis0",
2047                     "org.freedesktop.DBus.Properties", "Set",
2048                     "xyz.openbmc_project.State.Chassis",
2049                     "RequestedPowerTransition",
2050                     std::variant<std::string>{command});
2051             }
2052         });
2053 }
2054 
2055 /**
2056  * Systems derived class for delivering Computer Systems Schema.
2057  */
2058 inline void requestRoutesSystems(App& app)
2059 {
2060 
2061     /**
2062      * Functions triggers appropriate requests on DBus
2063      */
2064     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2065         .privileges({{"Login"}})
2066         .methods(
2067             boost::beast::http::verb::
2068                 get)([](const crow::Request&,
2069                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2070             asyncResp->res.jsonValue["@odata.type"] =
2071                 "#ComputerSystem.v1_13_0.ComputerSystem";
2072             asyncResp->res.jsonValue["Name"] = "system";
2073             asyncResp->res.jsonValue["Id"] = "system";
2074             asyncResp->res.jsonValue["SystemType"] = "Physical";
2075             asyncResp->res.jsonValue["Description"] = "Computer System";
2076             asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
2077             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
2078                 "Disabled";
2079             asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
2080                 uint64_t(0);
2081             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
2082                 "Disabled";
2083             asyncResp->res.jsonValue["@odata.id"] =
2084                 "/redfish/v1/Systems/system";
2085 
2086             asyncResp->res.jsonValue["Processors"] = {
2087                 {"@odata.id", "/redfish/v1/Systems/system/Processors"}};
2088             asyncResp->res.jsonValue["Memory"] = {
2089                 {"@odata.id", "/redfish/v1/Systems/system/Memory"}};
2090             asyncResp->res.jsonValue["Storage"] = {
2091                 {"@odata.id", "/redfish/v1/Systems/system/Storage"}};
2092 
2093             asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"] = {
2094                 {"target",
2095                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset"},
2096                 {"@Redfish.ActionInfo",
2097                  "/redfish/v1/Systems/system/ResetActionInfo"}};
2098 
2099             asyncResp->res.jsonValue["LogServices"] = {
2100                 {"@odata.id", "/redfish/v1/Systems/system/LogServices"}};
2101 
2102             asyncResp->res.jsonValue["Bios"] = {
2103                 {"@odata.id", "/redfish/v1/Systems/system/Bios"}};
2104 
2105             asyncResp->res.jsonValue["Links"]["ManagedBy"] = {
2106                 {{"@odata.id", "/redfish/v1/Managers/bmc"}}};
2107 
2108             asyncResp->res.jsonValue["Status"] = {
2109                 {"Health", "OK"},
2110                 {"State", "Enabled"},
2111             };
2112             constexpr const std::array<const char*, 4> inventoryForSystems = {
2113                 "xyz.openbmc_project.Inventory.Item.Dimm",
2114                 "xyz.openbmc_project.Inventory.Item.Cpu",
2115                 "xyz.openbmc_project.Inventory.Item.Drive",
2116                 "xyz.openbmc_project.Inventory.Item.StorageController"};
2117 
2118             auto health = std::make_shared<HealthPopulate>(asyncResp);
2119             crow::connections::systemBus->async_method_call(
2120                 [health](const boost::system::error_code ec,
2121                          std::vector<std::string>& resp) {
2122                     if (ec)
2123                     {
2124                         // no inventory
2125                         return;
2126                     }
2127 
2128                     health->inventory = std::move(resp);
2129                 },
2130                 "xyz.openbmc_project.ObjectMapper",
2131                 "/xyz/openbmc_project/object_mapper",
2132                 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
2133                 int32_t(0), inventoryForSystems);
2134 
2135             health->populate();
2136 
2137             getMainChassisId(
2138                 asyncResp, [](const std::string& chassisId,
2139                               const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
2140                     aRsp->res.jsonValue["Links"]["Chassis"] = {
2141                         {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}};
2142                 });
2143 
2144             getLocationIndicatorActive(asyncResp);
2145             // TODO (Gunnar): Remove IndicatorLED after enough time has passed
2146             getIndicatorLedState(asyncResp);
2147             getComputerSystem(asyncResp, health);
2148             getHostState(asyncResp);
2149             getBootProperties(asyncResp);
2150             getBootProgress(asyncResp);
2151             getPCIeDeviceList(asyncResp, "PCIeDevices");
2152             getHostWatchdogTimer(asyncResp);
2153             getPowerRestorePolicy(asyncResp);
2154             getAutomaticRetry(asyncResp);
2155             getLastResetTime(asyncResp);
2156 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
2157             getProvisioningStatus(asyncResp);
2158 #endif
2159         });
2160     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
2161         .privileges({{"ConfigureComponent"}})
2162         .methods(boost::beast::http::verb::patch)(
2163             [](const crow::Request& req,
2164                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2165                 std::optional<bool> locationIndicatorActive;
2166                 std::optional<std::string> indicatorLed;
2167                 std::optional<nlohmann::json> bootProps;
2168                 std::optional<nlohmann::json> wdtTimerProps;
2169                 std::optional<std::string> assetTag;
2170                 std::optional<std::string> powerRestorePolicy;
2171 
2172                 if (!json_util::readJson(
2173                         req, asyncResp->res, "IndicatorLED", indicatorLed,
2174                         "LocationIndicatorActive", locationIndicatorActive,
2175                         "Boot", bootProps, "WatchdogTimer", wdtTimerProps,
2176                         "PowerRestorePolicy", powerRestorePolicy, "AssetTag",
2177                         assetTag))
2178                 {
2179                     return;
2180                 }
2181 
2182                 asyncResp->res.result(boost::beast::http::status::no_content);
2183 
2184                 if (assetTag)
2185                 {
2186                     setAssetTag(asyncResp, *assetTag);
2187                 }
2188 
2189                 if (wdtTimerProps)
2190                 {
2191                     std::optional<bool> wdtEnable;
2192                     std::optional<std::string> wdtTimeOutAction;
2193 
2194                     if (!json_util::readJson(*wdtTimerProps, asyncResp->res,
2195                                              "FunctionEnabled", wdtEnable,
2196                                              "TimeoutAction", wdtTimeOutAction))
2197                     {
2198                         return;
2199                     }
2200                     setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
2201                 }
2202 
2203                 if (bootProps)
2204                 {
2205                     std::optional<std::string> bootSource;
2206                     std::optional<std::string> bootEnable;
2207                     std::optional<std::string> automaticRetryConfig;
2208 
2209                     if (!json_util::readJson(
2210                             *bootProps, asyncResp->res,
2211                             "BootSourceOverrideTarget", bootSource,
2212                             "BootSourceOverrideEnabled", bootEnable,
2213                             "AutomaticRetryConfig", automaticRetryConfig))
2214                     {
2215                         return;
2216                     }
2217                     if (bootSource || bootEnable)
2218                     {
2219                         setBootSourceProperties(asyncResp,
2220                                                 std::move(bootSource),
2221                                                 std::move(bootEnable));
2222                     }
2223                     if (automaticRetryConfig)
2224                     {
2225                         setAutomaticRetry(asyncResp, *automaticRetryConfig);
2226                     }
2227                 }
2228 
2229                 if (locationIndicatorActive)
2230                 {
2231                     setLocationIndicatorActive(asyncResp,
2232                                                *locationIndicatorActive);
2233                 }
2234 
2235                 // TODO (Gunnar): Remove IndicatorLED after enough time has
2236                 // passed
2237                 if (indicatorLed)
2238                 {
2239                     setIndicatorLedState(asyncResp, *indicatorLed);
2240                     asyncResp->res.addHeader(
2241                         boost::beast::http::field::warning,
2242                         "299 - \"IndicatorLED is deprecated. Use "
2243                         "LocationIndicatorActive instead.\"");
2244                 }
2245 
2246                 if (powerRestorePolicy)
2247                 {
2248                     setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
2249                 }
2250             });
2251 }
2252 
2253 /**
2254  * SystemResetActionInfo derived class for delivering Computer Systems
2255  * ResetType AllowableValues using ResetInfo schema.
2256  */
2257 inline void requestRoutesSystemResetActionInfo(App& app)
2258 {
2259 
2260     /**
2261      * Functions triggers appropriate requests on DBus
2262      */
2263     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
2264         .privileges({{"Login"}})
2265         .methods(boost::beast::http::verb::get)(
2266             [](const crow::Request&,
2267                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2268                 asyncResp->res.jsonValue = {
2269                     {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"},
2270                     {"@odata.id", "/redfish/v1/Systems/system/ResetActionInfo"},
2271                     {"Name", "Reset Action Info"},
2272                     {"Id", "ResetActionInfo"},
2273                     {"Parameters",
2274                      {{{"Name", "ResetType"},
2275                        {"Required", true},
2276                        {"DataType", "String"},
2277                        {"AllowableValues",
2278                         {"On", "ForceOff", "ForceOn", "ForceRestart",
2279                          "GracefulRestart", "GracefulShutdown", "PowerCycle",
2280                          "Nmi"}}}}}};
2281             });
2282 }
2283 } // namespace redfish
2284