xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 0a9c11e8)
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 "bmcweb_config.h"
19 
20 #include "app.hpp"
21 #include "dbus_singleton.hpp"
22 #include "dbus_utility.hpp"
23 #include "health.hpp"
24 #include "hypervisor_system.hpp"
25 #include "led.hpp"
26 #include "query.hpp"
27 #include "redfish_util.hpp"
28 #include "registries/privilege_registry.hpp"
29 #include "utils/dbus_utils.hpp"
30 #include "utils/json_utils.hpp"
31 #include "utils/pcie_util.hpp"
32 #include "utils/sw_utils.hpp"
33 #include "utils/time_utils.hpp"
34 
35 #include <boost/container/flat_map.hpp>
36 #include <boost/system/error_code.hpp>
37 #include <boost/url/format.hpp>
38 #include <sdbusplus/asio/property.hpp>
39 #include <sdbusplus/unpack_properties.hpp>
40 
41 #include <array>
42 #include <string_view>
43 #include <variant>
44 
45 namespace redfish
46 {
47 
48 const static std::array<std::pair<std::string_view, std::string_view>, 2>
49     protocolToDBusForSystems{
50         {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}};
51 
52 /**
53  * @brief Updates the Functional State of DIMMs
54  *
55  * @param[in] aResp Shared pointer for completing asynchronous calls
56  * @param[in] dimmState Dimm's Functional state, true/false
57  *
58  * @return None.
59  */
60 inline void
61     updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
62                          bool isDimmFunctional)
63 {
64     BMCWEB_LOG_DEBUG << "Dimm Functional: " << isDimmFunctional;
65 
66     // Set it as Enabled if at least one DIMM is functional
67     // Update STATE only if previous State was DISABLED and current Dimm is
68     // ENABLED.
69     const nlohmann::json& prevMemSummary =
70         aResp->res.jsonValue["MemorySummary"]["Status"]["State"];
71     if (prevMemSummary == "Disabled")
72     {
73         if (isDimmFunctional)
74         {
75             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
76                 "Enabled";
77         }
78     }
79 }
80 
81 /*
82  * @brief Update "ProcessorSummary" "Status" "State" based on
83  *        CPU Functional State
84  *
85  * @param[in] aResp Shared pointer for completing asynchronous calls
86  * @param[in] cpuFunctionalState is CPU functional true/false
87  *
88  * @return None.
89  */
90 inline void
91     modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
92                              bool isCpuFunctional)
93 {
94     BMCWEB_LOG_DEBUG << "Cpu Functional: " << isCpuFunctional;
95 
96     const nlohmann::json& prevProcState =
97         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"];
98 
99     // Set it as Enabled if at least one CPU is functional
100     // Update STATE only if previous State was Non_Functional and current CPU is
101     // Functional.
102     if (prevProcState == "Disabled")
103     {
104         if (isCpuFunctional)
105         {
106             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
107                 "Enabled";
108         }
109     }
110 }
111 
112 /*
113  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState
114  *
115  * @param[in] aResp Shared pointer for completing asynchronous calls
116  * @param[in] cpuPresenceState CPU present or not
117  *
118  * @return None.
119  */
120 inline void
121     modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
122                            bool isCpuPresent)
123 {
124     BMCWEB_LOG_DEBUG << "Cpu Present: " << isCpuPresent;
125 
126     if (isCpuPresent)
127     {
128         nlohmann::json& procCount =
129             aResp->res.jsonValue["ProcessorSummary"]["Count"];
130         auto* procCountPtr =
131             procCount.get_ptr<nlohmann::json::number_integer_t*>();
132         if (procCountPtr != nullptr)
133         {
134             // shouldn't be possible to be nullptr
135             *procCountPtr += 1;
136         }
137     }
138 }
139 
140 inline void getProcessorProperties(
141     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
142     const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
143         properties)
144 {
145     BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties.";
146 
147     // TODO: Get Model
148 
149     const uint16_t* coreCount = nullptr;
150 
151     const bool success = sdbusplus::unpackPropertiesNoThrow(
152         dbus_utils::UnpackErrorPrinter(), properties, "CoreCount", coreCount);
153 
154     if (!success)
155     {
156         messages::internalError(aResp->res);
157         return;
158     }
159 
160     if (coreCount != nullptr)
161     {
162         nlohmann::json& coreCountJson =
163             aResp->res.jsonValue["ProcessorSummary"]["CoreCount"];
164         uint64_t* coreCountJsonPtr = coreCountJson.get_ptr<uint64_t*>();
165 
166         if (coreCountJsonPtr == nullptr)
167         {
168             coreCountJson = *coreCount;
169         }
170         else
171         {
172             *coreCountJsonPtr += *coreCount;
173         }
174     }
175 }
176 
177 /*
178  * @brief Get ProcessorSummary fields
179  *
180  * @param[in] aResp Shared pointer for completing asynchronous calls
181  * @param[in] service dbus service for Cpu Information
182  * @param[in] path dbus path for Cpu
183  *
184  * @return None.
185  */
186 inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
187                                 const std::string& service,
188                                 const std::string& path)
189 {
190     auto getCpuPresenceState = [aResp](const boost::system::error_code& ec3,
191                                        const bool cpuPresenceCheck) {
192         if (ec3)
193         {
194             BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
195             return;
196         }
197         modifyCpuPresenceState(aResp, cpuPresenceCheck);
198     };
199 
200     // Get the Presence of CPU
201     sdbusplus::asio::getProperty<bool>(
202         *crow::connections::systemBus, service, path,
203         "xyz.openbmc_project.Inventory.Item", "Present",
204         std::move(getCpuPresenceState));
205 
206     if constexpr (bmcwebEnableProcMemStatus)
207     {
208         auto getCpuFunctionalState =
209             [aResp](const boost::system::error_code& ec3,
210                     const bool cpuFunctionalCheck) {
211             if (ec3)
212             {
213                 BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
214                 return;
215             }
216             modifyCpuFunctionalState(aResp, cpuFunctionalCheck);
217         };
218 
219         // Get the Functional State
220         sdbusplus::asio::getProperty<bool>(
221             *crow::connections::systemBus, service, path,
222             "xyz.openbmc_project.State.Decorator.OperationalStatus",
223             "Functional", std::move(getCpuFunctionalState));
224     }
225 
226     sdbusplus::asio::getAllProperties(
227         *crow::connections::systemBus, service, path,
228         "xyz.openbmc_project.Inventory.Item.Cpu",
229         [aResp, service,
230          path](const boost::system::error_code& ec2,
231                const dbus::utility::DBusPropertiesMap& properties) {
232         if (ec2)
233         {
234             BMCWEB_LOG_ERROR << "DBUS response error " << ec2;
235             messages::internalError(aResp->res);
236             return;
237         }
238         getProcessorProperties(aResp, properties);
239         });
240 }
241 
242 /*
243  * @brief processMemoryProperties fields
244  *
245  * @param[in] aResp Shared pointer for completing asynchronous calls
246  * @param[in] service dbus service for memory Information
247  * @param[in] path dbus path for Memory
248  * @param[in] DBUS properties for memory
249  *
250  * @return None.
251  */
252 inline void
253     processMemoryProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
254                             [[maybe_unused]] const std::string& service,
255                             [[maybe_unused]] const std::string& path,
256                             const dbus::utility::DBusPropertiesMap& properties)
257 {
258     BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Dimm properties.";
259 
260     if (properties.empty())
261     {
262         if constexpr (bmcwebEnableProcMemStatus)
263         {
264             sdbusplus::asio::getProperty<bool>(
265                 *crow::connections::systemBus, service, path,
266                 "xyz.openbmc_project.State."
267                 "Decorator.OperationalStatus",
268                 "Functional",
269                 [aResp](const boost::system::error_code& ec3, bool dimmState) {
270                 if (ec3)
271                 {
272                     BMCWEB_LOG_ERROR << "DBUS response error " << ec3;
273                     return;
274                 }
275                 updateDimmProperties(aResp, dimmState);
276                 });
277         }
278         return;
279     }
280 
281     const size_t* memorySizeInKB = nullptr;
282 
283     const bool success = sdbusplus::unpackPropertiesNoThrow(
284         dbus_utils::UnpackErrorPrinter(), properties, "MemorySizeInKB",
285         memorySizeInKB);
286 
287     if (!success)
288     {
289         messages::internalError(aResp->res);
290         return;
291     }
292 
293     if (memorySizeInKB != nullptr)
294     {
295         nlohmann::json& totalMemory =
296             aResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"];
297         const uint64_t* preValue = totalMemory.get_ptr<const uint64_t*>();
298         if (preValue == nullptr)
299         {
300             aResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
301                 *memorySizeInKB / static_cast<size_t>(1024 * 1024);
302         }
303         else
304         {
305             aResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
306                 *memorySizeInKB / static_cast<size_t>(1024 * 1024) + *preValue;
307         }
308         if constexpr (bmcwebEnableProcMemStatus)
309         {
310             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
311                 "Enabled";
312         }
313     }
314 }
315 
316 /*
317  * @brief Get getMemorySummary fields
318  *
319  * @param[in] aResp Shared pointer for completing asynchronous calls
320  * @param[in] service dbus service for memory Information
321  * @param[in] path dbus path for memory
322  *
323  * @return None.
324  */
325 inline void getMemorySummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
326                              const std::string& service,
327                              const std::string& path)
328 {
329     sdbusplus::asio::getAllProperties(
330         *crow::connections::systemBus, service, path,
331         "xyz.openbmc_project.Inventory.Item.Dimm",
332         [aResp, service,
333          path](const boost::system::error_code& ec2,
334                const dbus::utility::DBusPropertiesMap& properties) {
335         if (ec2)
336         {
337             BMCWEB_LOG_ERROR << "DBUS response error " << ec2;
338             messages::internalError(aResp->res);
339             return;
340         }
341         processMemoryProperties(aResp, service, path, properties);
342         });
343 }
344 
345 /*
346  * @brief Retrieves computer system properties over dbus
347  *
348  * @param[in] aResp Shared pointer for completing asynchronous calls
349  * @param[in] systemHealth  Shared HealthPopulate pointer
350  *
351  * @return None.
352  */
353 inline void
354     getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
355                       const std::shared_ptr<HealthPopulate>& systemHealth)
356 {
357     BMCWEB_LOG_DEBUG << "Get available system components.";
358     constexpr std::array<std::string_view, 5> interfaces = {
359         "xyz.openbmc_project.Inventory.Decorator.Asset",
360         "xyz.openbmc_project.Inventory.Item.Cpu",
361         "xyz.openbmc_project.Inventory.Item.Dimm",
362         "xyz.openbmc_project.Inventory.Item.System",
363         "xyz.openbmc_project.Common.UUID",
364     };
365     dbus::utility::getSubTree(
366         "/xyz/openbmc_project/inventory", 0, interfaces,
367         [aResp,
368          systemHealth](const boost::system::error_code& ec,
369                        const dbus::utility::MapperGetSubTreeResponse& subtree) {
370         if (ec)
371         {
372             BMCWEB_LOG_DEBUG << "DBUS response error";
373             messages::internalError(aResp->res);
374             return;
375         }
376         // Iterate over all retrieved ObjectPaths.
377         for (const std::pair<
378                  std::string,
379                  std::vector<std::pair<std::string, std::vector<std::string>>>>&
380                  object : subtree)
381         {
382             const std::string& path = object.first;
383             BMCWEB_LOG_DEBUG << "Got path: " << path;
384             const std::vector<std::pair<std::string, std::vector<std::string>>>&
385                 connectionNames = object.second;
386             if (connectionNames.empty())
387             {
388                 continue;
389             }
390 
391             std::shared_ptr<HealthPopulate> memoryHealth = nullptr;
392             std::shared_ptr<HealthPopulate> cpuHealth = nullptr;
393 
394             if constexpr (bmcwebEnableProcMemStatus)
395             {
396                 memoryHealth = std::make_shared<HealthPopulate>(
397                     aResp, "/MemorySummary/Status"_json_pointer);
398                 systemHealth->children.emplace_back(memoryHealth);
399 
400                 if constexpr (bmcwebEnableHealthPopulate)
401                 {
402                     cpuHealth = std::make_shared<HealthPopulate>(
403                         aResp, "/ProcessorSummary/Status"_json_pointer);
404 
405                     systemHealth->children.emplace_back(cpuHealth);
406                 }
407             }
408 
409             // This is not system, so check if it's cpu, dimm, UUID or
410             // BiosVer
411             for (const auto& connection : connectionNames)
412             {
413                 for (const auto& interfaceName : connection.second)
414                 {
415                     if (interfaceName ==
416                         "xyz.openbmc_project.Inventory.Item.Dimm")
417                     {
418                         BMCWEB_LOG_DEBUG
419                             << "Found Dimm, now get its properties.";
420 
421                         getMemorySummary(aResp, connection.first, path);
422 
423                         if constexpr (bmcwebEnableProcMemStatus)
424                         {
425                             memoryHealth->inventory.emplace_back(path);
426                         }
427                     }
428                     else if (interfaceName ==
429                              "xyz.openbmc_project.Inventory.Item.Cpu")
430                     {
431                         BMCWEB_LOG_DEBUG
432                             << "Found Cpu, now get its properties.";
433 
434                         getProcessorSummary(aResp, connection.first, path);
435 
436                         if constexpr (bmcwebEnableProcMemStatus)
437                         {
438                             cpuHealth->inventory.emplace_back(path);
439                         }
440                     }
441                     else if (interfaceName == "xyz.openbmc_project.Common.UUID")
442                     {
443                         BMCWEB_LOG_DEBUG
444                             << "Found UUID, now get its properties.";
445 
446                         sdbusplus::asio::getAllProperties(
447                             *crow::connections::systemBus, connection.first,
448                             path, "xyz.openbmc_project.Common.UUID",
449                             [aResp](const boost::system::error_code& ec3,
450                                     const dbus::utility::DBusPropertiesMap&
451                                         properties) {
452                             if (ec3)
453                             {
454                                 BMCWEB_LOG_DEBUG << "DBUS response error "
455                                                  << ec3;
456                                 messages::internalError(aResp->res);
457                                 return;
458                             }
459                             BMCWEB_LOG_DEBUG << "Got " << properties.size()
460                                              << " UUID properties.";
461 
462                             const std::string* uUID = nullptr;
463 
464                             const bool success =
465                                 sdbusplus::unpackPropertiesNoThrow(
466                                     dbus_utils::UnpackErrorPrinter(),
467                                     properties, "UUID", uUID);
468 
469                             if (!success)
470                             {
471                                 messages::internalError(aResp->res);
472                                 return;
473                             }
474 
475                             if (uUID != nullptr)
476                             {
477                                 std::string valueStr = *uUID;
478                                 if (valueStr.size() == 32)
479                                 {
480                                     valueStr.insert(8, 1, '-');
481                                     valueStr.insert(13, 1, '-');
482                                     valueStr.insert(18, 1, '-');
483                                     valueStr.insert(23, 1, '-');
484                                 }
485                                 BMCWEB_LOG_DEBUG << "UUID = " << valueStr;
486                                 aResp->res.jsonValue["UUID"] = valueStr;
487                             }
488                             });
489                     }
490                     else if (interfaceName ==
491                              "xyz.openbmc_project.Inventory.Item.System")
492                     {
493                         sdbusplus::asio::getAllProperties(
494                             *crow::connections::systemBus, connection.first,
495                             path,
496                             "xyz.openbmc_project.Inventory.Decorator.Asset",
497                             [aResp](const boost::system::error_code& ec2,
498                                     const dbus::utility::DBusPropertiesMap&
499                                         propertiesList) {
500                             if (ec2)
501                             {
502                                 // doesn't have to include this
503                                 // interface
504                                 return;
505                             }
506                             BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
507                                              << " properties for system";
508 
509                             const std::string* partNumber = nullptr;
510                             const std::string* serialNumber = nullptr;
511                             const std::string* manufacturer = nullptr;
512                             const std::string* model = nullptr;
513                             const std::string* subModel = nullptr;
514 
515                             const bool success =
516                                 sdbusplus::unpackPropertiesNoThrow(
517                                     dbus_utils::UnpackErrorPrinter(),
518                                     propertiesList, "PartNumber", partNumber,
519                                     "SerialNumber", serialNumber,
520                                     "Manufacturer", manufacturer, "Model",
521                                     model, "SubModel", subModel);
522 
523                             if (!success)
524                             {
525                                 messages::internalError(aResp->res);
526                                 return;
527                             }
528 
529                             if (partNumber != nullptr)
530                             {
531                                 aResp->res.jsonValue["PartNumber"] =
532                                     *partNumber;
533                             }
534 
535                             if (serialNumber != nullptr)
536                             {
537                                 aResp->res.jsonValue["SerialNumber"] =
538                                     *serialNumber;
539                             }
540 
541                             if (manufacturer != nullptr)
542                             {
543                                 aResp->res.jsonValue["Manufacturer"] =
544                                     *manufacturer;
545                             }
546 
547                             if (model != nullptr)
548                             {
549                                 aResp->res.jsonValue["Model"] = *model;
550                             }
551 
552                             if (subModel != nullptr)
553                             {
554                                 aResp->res.jsonValue["SubModel"] = *subModel;
555                             }
556 
557                             // Grab the bios version
558                             sw_util::populateSoftwareInformation(
559                                 aResp, sw_util::biosPurpose, "BiosVersion",
560                                 false);
561                             });
562 
563                         sdbusplus::asio::getProperty<std::string>(
564                             *crow::connections::systemBus, connection.first,
565                             path,
566                             "xyz.openbmc_project.Inventory.Decorator."
567                             "AssetTag",
568                             "AssetTag",
569                             [aResp](const boost::system::error_code& ec2,
570                                     const std::string& value) {
571                             if (ec2)
572                             {
573                                 // doesn't have to include this
574                                 // interface
575                                 return;
576                             }
577 
578                             aResp->res.jsonValue["AssetTag"] = value;
579                             });
580                     }
581                 }
582             }
583         }
584         });
585 }
586 
587 /**
588  * @brief Retrieves host state properties over dbus
589  *
590  * @param[in] aResp     Shared pointer for completing asynchronous calls.
591  *
592  * @return None.
593  */
594 inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
595 {
596     BMCWEB_LOG_DEBUG << "Get host information.";
597     sdbusplus::asio::getProperty<std::string>(
598         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
599         "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host",
600         "CurrentHostState",
601         [aResp](const boost::system::error_code& ec,
602                 const std::string& hostState) {
603         if (ec)
604         {
605             if (ec == boost::system::errc::host_unreachable)
606             {
607                 // Service not available, no error, just don't return
608                 // host state info
609                 BMCWEB_LOG_DEBUG << "Service not available " << ec;
610                 return;
611             }
612             BMCWEB_LOG_ERROR << "DBUS response error " << ec;
613             messages::internalError(aResp->res);
614             return;
615         }
616 
617         BMCWEB_LOG_DEBUG << "Host state: " << hostState;
618         // Verify Host State
619         if (hostState == "xyz.openbmc_project.State.Host.HostState.Running")
620         {
621             aResp->res.jsonValue["PowerState"] = "On";
622             aResp->res.jsonValue["Status"]["State"] = "Enabled";
623         }
624         else if (hostState ==
625                  "xyz.openbmc_project.State.Host.HostState.Quiesced")
626         {
627             aResp->res.jsonValue["PowerState"] = "On";
628             aResp->res.jsonValue["Status"]["State"] = "Quiesced";
629         }
630         else if (hostState ==
631                  "xyz.openbmc_project.State.Host.HostState.DiagnosticMode")
632         {
633             aResp->res.jsonValue["PowerState"] = "On";
634             aResp->res.jsonValue["Status"]["State"] = "InTest";
635         }
636         else if (
637             hostState ==
638             "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning")
639         {
640             aResp->res.jsonValue["PowerState"] = "PoweringOn";
641             aResp->res.jsonValue["Status"]["State"] = "Starting";
642         }
643         else if (hostState ==
644                  "xyz.openbmc_project.State.Host.HostState.TransitioningToOff")
645         {
646             aResp->res.jsonValue["PowerState"] = "PoweringOff";
647             aResp->res.jsonValue["Status"]["State"] = "Disabled";
648         }
649         else
650         {
651             aResp->res.jsonValue["PowerState"] = "Off";
652             aResp->res.jsonValue["Status"]["State"] = "Disabled";
653         }
654         });
655 }
656 
657 /**
658  * @brief Translates boot source DBUS property value to redfish.
659  *
660  * @param[in] dbusSource    The boot source in DBUS speak.
661  *
662  * @return Returns as a string, the boot source in Redfish terms. If translation
663  * cannot be done, returns an empty string.
664  */
665 inline std::string dbusToRfBootSource(const std::string& dbusSource)
666 {
667     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default")
668     {
669         return "None";
670     }
671     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk")
672     {
673         return "Hdd";
674     }
675     if (dbusSource ==
676         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia")
677     {
678         return "Cd";
679     }
680     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network")
681     {
682         return "Pxe";
683     }
684     if (dbusSource ==
685         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia")
686     {
687         return "Usb";
688     }
689     return "";
690 }
691 
692 /**
693  * @brief Translates boot type DBUS property value to redfish.
694  *
695  * @param[in] dbusType    The boot type in DBUS speak.
696  *
697  * @return Returns as a string, the boot type in Redfish terms. If translation
698  * cannot be done, returns an empty string.
699  */
700 inline std::string dbusToRfBootType(const std::string& dbusType)
701 {
702     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy")
703     {
704         return "Legacy";
705     }
706     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI")
707     {
708         return "UEFI";
709     }
710     return "";
711 }
712 
713 /**
714  * @brief Translates boot mode DBUS property value to redfish.
715  *
716  * @param[in] dbusMode    The boot mode in DBUS speak.
717  *
718  * @return Returns as a string, the boot mode in Redfish terms. If translation
719  * cannot be done, returns an empty string.
720  */
721 inline std::string dbusToRfBootMode(const std::string& dbusMode)
722 {
723     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
724     {
725         return "None";
726     }
727     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe")
728     {
729         return "Diags";
730     }
731     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup")
732     {
733         return "BiosSetup";
734     }
735     return "";
736 }
737 
738 /**
739  * @brief Translates boot progress DBUS property value to redfish.
740  *
741  * @param[in] dbusBootProgress    The boot progress in DBUS speak.
742  *
743  * @return Returns as a string, the boot progress in Redfish terms. If
744  *         translation cannot be done, returns "None".
745  */
746 inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress)
747 {
748     // Now convert the D-Bus BootProgress to the appropriate Redfish
749     // enum
750     std::string rfBpLastState = "None";
751     if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress."
752                             "ProgressStages.Unspecified")
753     {
754         rfBpLastState = "None";
755     }
756     else if (dbusBootProgress ==
757              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
758              "PrimaryProcInit")
759     {
760         rfBpLastState = "PrimaryProcessorInitializationStarted";
761     }
762     else if (dbusBootProgress ==
763              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
764              "BusInit")
765     {
766         rfBpLastState = "BusInitializationStarted";
767     }
768     else if (dbusBootProgress ==
769              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
770              "MemoryInit")
771     {
772         rfBpLastState = "MemoryInitializationStarted";
773     }
774     else if (dbusBootProgress ==
775              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
776              "SecondaryProcInit")
777     {
778         rfBpLastState = "SecondaryProcessorInitializationStarted";
779     }
780     else if (dbusBootProgress ==
781              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
782              "PCIInit")
783     {
784         rfBpLastState = "PCIResourceConfigStarted";
785     }
786     else if (dbusBootProgress ==
787              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
788              "SystemSetup")
789     {
790         rfBpLastState = "SetupEntered";
791     }
792     else if (dbusBootProgress ==
793              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
794              "SystemInitComplete")
795     {
796         rfBpLastState = "SystemHardwareInitializationComplete";
797     }
798     else if (dbusBootProgress ==
799              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
800              "OSStart")
801     {
802         rfBpLastState = "OSBootStarted";
803     }
804     else if (dbusBootProgress ==
805              "xyz.openbmc_project.State.Boot.Progress.ProgressStages."
806              "OSRunning")
807     {
808         rfBpLastState = "OSRunning";
809     }
810     else
811     {
812         BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress "
813                          << dbusBootProgress;
814         // Just return the default
815     }
816     return rfBpLastState;
817 }
818 
819 /**
820  * @brief Translates boot source from Redfish to the DBus boot paths.
821  *
822  * @param[in] rfSource    The boot source in Redfish.
823  * @param[out] bootSource The DBus source
824  * @param[out] bootMode   the DBus boot mode
825  *
826  * @return Integer error code.
827  */
828 inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
829                                 const std::string& rfSource,
830                                 std::string& bootSource, std::string& bootMode)
831 {
832     bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default";
833     bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
834 
835     if (rfSource == "None")
836     {
837         return 0;
838     }
839     if (rfSource == "Pxe")
840     {
841         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network";
842     }
843     else if (rfSource == "Hdd")
844     {
845         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk";
846     }
847     else if (rfSource == "Diags")
848     {
849         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe";
850     }
851     else if (rfSource == "Cd")
852     {
853         bootSource =
854             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia";
855     }
856     else if (rfSource == "BiosSetup")
857     {
858         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup";
859     }
860     else if (rfSource == "Usb")
861     {
862         bootSource =
863             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia";
864     }
865     else
866     {
867         BMCWEB_LOG_DEBUG
868             << "Invalid property value for BootSourceOverrideTarget: "
869             << bootSource;
870         messages::propertyValueNotInList(aResp->res, rfSource,
871                                          "BootSourceTargetOverride");
872         return -1;
873     }
874     return 0;
875 }
876 
877 /**
878  * @brief Retrieves boot progress of the system
879  *
880  * @param[in] aResp  Shared pointer for generating response message.
881  *
882  * @return None.
883  */
884 inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
885 {
886     sdbusplus::asio::getProperty<std::string>(
887         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
888         "/xyz/openbmc_project/state/host0",
889         "xyz.openbmc_project.State.Boot.Progress", "BootProgress",
890         [aResp](const boost::system::error_code& ec,
891                 const std::string& bootProgressStr) {
892         if (ec)
893         {
894             // BootProgress is an optional object so just do nothing if
895             // not found
896             return;
897         }
898 
899         BMCWEB_LOG_DEBUG << "Boot Progress: " << bootProgressStr;
900 
901         aResp->res.jsonValue["BootProgress"]["LastState"] =
902             dbusToRfBootProgress(bootProgressStr);
903         });
904 }
905 
906 /**
907  * @brief Retrieves boot progress Last Update of the system
908  *
909  * @param[in] aResp  Shared pointer for generating response message.
910  *
911  * @return None.
912  */
913 inline void getBootProgressLastStateTime(
914     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
915 {
916     sdbusplus::asio::getProperty<uint64_t>(
917         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
918         "/xyz/openbmc_project/state/host0",
919         "xyz.openbmc_project.State.Boot.Progress", "BootProgressLastUpdate",
920         [aResp](const boost::system::error_code& ec,
921                 const uint64_t lastStateTime) {
922         if (ec)
923         {
924             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
925             return;
926         }
927 
928         // BootProgressLastUpdate is the last time the BootProgress property
929         // was updated. The time is the Epoch time, number of microseconds
930         // since 1 Jan 1970 00::00::00 UTC."
931         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/
932         // yaml/xyz/openbmc_project/State/Boot/Progress.interface.yaml#L11
933 
934         // Convert to ISO 8601 standard
935         aResp->res.jsonValue["BootProgress"]["LastStateTime"] =
936             redfish::time_utils::getDateTimeUintUs(lastStateTime);
937         });
938 }
939 
940 /**
941  * @brief Retrieves boot override type over DBUS and fills out the response
942  *
943  * @param[in] aResp         Shared pointer for generating response message.
944  *
945  * @return None.
946  */
947 
948 inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
949 {
950     sdbusplus::asio::getProperty<std::string>(
951         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
952         "/xyz/openbmc_project/control/host0/boot",
953         "xyz.openbmc_project.Control.Boot.Type", "BootType",
954         [aResp](const boost::system::error_code& ec,
955                 const std::string& bootType) {
956         if (ec)
957         {
958             // not an error, don't have to have the interface
959             return;
960         }
961 
962         BMCWEB_LOG_DEBUG << "Boot type: " << bootType;
963 
964         aResp->res.jsonValue["Boot"]
965                             ["BootSourceOverrideMode@Redfish.AllowableValues"] =
966             nlohmann::json::array_t({"Legacy", "UEFI"});
967 
968         auto rfType = dbusToRfBootType(bootType);
969         if (rfType.empty())
970         {
971             messages::internalError(aResp->res);
972             return;
973         }
974 
975         aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType;
976         });
977 }
978 
979 /**
980  * @brief Retrieves boot override mode over DBUS and fills out the response
981  *
982  * @param[in] aResp         Shared pointer for generating response message.
983  *
984  * @return None.
985  */
986 
987 inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
988 {
989     sdbusplus::asio::getProperty<std::string>(
990         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
991         "/xyz/openbmc_project/control/host0/boot",
992         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
993         [aResp](const boost::system::error_code& ec,
994                 const std::string& bootModeStr) {
995         if (ec)
996         {
997             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
998             messages::internalError(aResp->res);
999             return;
1000         }
1001 
1002         BMCWEB_LOG_DEBUG << "Boot mode: " << bootModeStr;
1003 
1004         aResp->res
1005             .jsonValue["Boot"]
1006                       ["BootSourceOverrideTarget@Redfish.AllowableValues"] = {
1007             "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"};
1008 
1009         if (bootModeStr !=
1010             "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular")
1011         {
1012             auto rfMode = dbusToRfBootMode(bootModeStr);
1013             if (!rfMode.empty())
1014             {
1015                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1016                     rfMode;
1017             }
1018         }
1019         });
1020 }
1021 
1022 /**
1023  * @brief Retrieves boot override source over DBUS
1024  *
1025  * @param[in] aResp         Shared pointer for generating response message.
1026  *
1027  * @return None.
1028  */
1029 
1030 inline void
1031     getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1032 {
1033     sdbusplus::asio::getProperty<std::string>(
1034         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1035         "/xyz/openbmc_project/control/host0/boot",
1036         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1037         [aResp](const boost::system::error_code& ec,
1038                 const std::string& bootSourceStr) {
1039         if (ec)
1040         {
1041             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1042             if (ec.value() == boost::asio::error::host_unreachable)
1043             {
1044                 return;
1045             }
1046             messages::internalError(aResp->res);
1047             return;
1048         }
1049 
1050         BMCWEB_LOG_DEBUG << "Boot source: " << bootSourceStr;
1051 
1052         auto rfSource = dbusToRfBootSource(bootSourceStr);
1053         if (!rfSource.empty())
1054         {
1055             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = rfSource;
1056         }
1057 
1058         // Get BootMode as BootSourceOverrideTarget is constructed
1059         // from both BootSource and BootMode
1060         getBootOverrideMode(aResp);
1061         });
1062 }
1063 
1064 /**
1065  * @brief This functions abstracts all the logic behind getting a
1066  * "BootSourceOverrideEnabled" property from an overall boot override enable
1067  * state
1068  *
1069  * @param[in] aResp     Shared pointer for generating response message.
1070  *
1071  * @return None.
1072  */
1073 
1074 inline void
1075     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1076                               const bool bootOverrideEnableSetting)
1077 {
1078     if (!bootOverrideEnableSetting)
1079     {
1080         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled";
1081         return;
1082     }
1083 
1084     // If boot source override is enabled, we need to check 'one_time'
1085     // property to set a correct value for the "BootSourceOverrideEnabled"
1086     sdbusplus::asio::getProperty<bool>(
1087         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1088         "/xyz/openbmc_project/control/host0/boot/one_time",
1089         "xyz.openbmc_project.Object.Enable", "Enabled",
1090         [aResp](const boost::system::error_code& ec, bool oneTimeSetting) {
1091         if (ec)
1092         {
1093             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1094             messages::internalError(aResp->res);
1095             return;
1096         }
1097 
1098         if (oneTimeSetting)
1099         {
1100             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Once";
1101         }
1102         else
1103         {
1104             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1105                 "Continuous";
1106         }
1107         });
1108 }
1109 
1110 /**
1111  * @brief Retrieves boot override enable over DBUS
1112  *
1113  * @param[in] aResp     Shared pointer for generating response message.
1114  *
1115  * @return None.
1116  */
1117 
1118 inline void
1119     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1120 {
1121     sdbusplus::asio::getProperty<bool>(
1122         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1123         "/xyz/openbmc_project/control/host0/boot",
1124         "xyz.openbmc_project.Object.Enable", "Enabled",
1125         [aResp](const boost::system::error_code& ec,
1126                 const bool bootOverrideEnable) {
1127         if (ec)
1128         {
1129             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1130             if (ec.value() == boost::asio::error::host_unreachable)
1131             {
1132                 return;
1133             }
1134             messages::internalError(aResp->res);
1135             return;
1136         }
1137 
1138         processBootOverrideEnable(aResp, bootOverrideEnable);
1139         });
1140 }
1141 
1142 /**
1143  * @brief Retrieves boot source override properties
1144  *
1145  * @param[in] aResp     Shared pointer for generating response message.
1146  *
1147  * @return None.
1148  */
1149 inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1150 {
1151     BMCWEB_LOG_DEBUG << "Get boot information.";
1152 
1153     getBootOverrideSource(aResp);
1154     getBootOverrideType(aResp);
1155     getBootOverrideEnable(aResp);
1156 }
1157 
1158 /**
1159  * @brief Retrieves the Last Reset Time
1160  *
1161  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1162  * and power off. Even though this is the "system" Redfish object look at the
1163  * chassis D-Bus interface for the LastStateChangeTime since this has the
1164  * last power operation time.
1165  *
1166  * @param[in] aResp     Shared pointer for generating response message.
1167  *
1168  * @return None.
1169  */
1170 inline void getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1171 {
1172     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time";
1173 
1174     sdbusplus::asio::getProperty<uint64_t>(
1175         *crow::connections::systemBus, "xyz.openbmc_project.State.Chassis",
1176         "/xyz/openbmc_project/state/chassis0",
1177         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime",
1178         [aResp](const boost::system::error_code& ec, uint64_t lastResetTime) {
1179         if (ec)
1180         {
1181             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec;
1182             return;
1183         }
1184 
1185         // LastStateChangeTime is epoch time, in milliseconds
1186         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1187         uint64_t lastResetTimeStamp = lastResetTime / 1000;
1188 
1189         // Convert to ISO 8601 standard
1190         aResp->res.jsonValue["LastResetTime"] =
1191             redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1192         });
1193 }
1194 
1195 /**
1196  * @brief Retrieves the number of automatic boot Retry attempts allowed/left.
1197  *
1198  * The total number of automatic reboot retries allowed "RetryAttempts" and its
1199  * corresponding property "AttemptsLeft" that keeps track of the amount of
1200  * automatic retry attempts left are hosted in phosphor-state-manager through
1201  * dbus.
1202  *
1203  * @param[in] aResp     Shared pointer for generating response message.
1204  *
1205  * @return None.
1206  */
1207 inline void
1208     getAutomaticRebootAttempts(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1209 {
1210     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1211 
1212     sdbusplus::asio::getAllProperties(
1213         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
1214         "/xyz/openbmc_project/state/host0",
1215         "xyz.openbmc_project.Control.Boot.RebootAttempts",
1216         [aResp{aResp}](const boost::system::error_code& ec,
1217                        const dbus::utility::DBusPropertiesMap& propertiesList) {
1218         if (ec)
1219         {
1220             if (ec.value() != EBADR)
1221             {
1222                 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1223                 messages::internalError(aResp->res);
1224             }
1225             return;
1226         }
1227 
1228         const uint32_t* attemptsLeft = nullptr;
1229         const uint32_t* retryAttempts = nullptr;
1230 
1231         const bool success = sdbusplus::unpackPropertiesNoThrow(
1232             dbus_utils::UnpackErrorPrinter(), propertiesList, "AttemptsLeft",
1233             attemptsLeft, "RetryAttempts", retryAttempts);
1234 
1235         if (!success)
1236         {
1237             messages::internalError(aResp->res);
1238             return;
1239         }
1240 
1241         if (attemptsLeft != nullptr)
1242         {
1243             aResp->res.jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1244                 *attemptsLeft;
1245         }
1246 
1247         if (retryAttempts != nullptr)
1248         {
1249             aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] =
1250                 *retryAttempts;
1251         }
1252         });
1253 }
1254 
1255 /**
1256  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1257  *
1258  * @param[in] aResp     Shared pointer for generating response message.
1259  *
1260  * @return None.
1261  */
1262 inline void
1263     getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1264 {
1265     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy";
1266 
1267     sdbusplus::asio::getProperty<bool>(
1268         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1269         "/xyz/openbmc_project/control/host0/auto_reboot",
1270         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1271         [aResp](const boost::system::error_code& ec, bool autoRebootEnabled) {
1272         if (ec)
1273         {
1274             if (ec.value() != EBADR)
1275             {
1276                 BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
1277                 messages::internalError(aResp->res);
1278             }
1279             return;
1280         }
1281 
1282         BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled;
1283         if (autoRebootEnabled)
1284         {
1285             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1286                 "RetryAttempts";
1287         }
1288         else
1289         {
1290             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled";
1291         }
1292         getAutomaticRebootAttempts(aResp);
1293 
1294         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1295         // and RetryAttempts. OpenBMC only supports Disabled and
1296         // RetryAttempts.
1297         aResp->res.jsonValue["Boot"]
1298                             ["AutomaticRetryConfig@Redfish.AllowableValues"] = {
1299             "Disabled", "RetryAttempts"};
1300         });
1301 }
1302 
1303 /**
1304  * @brief Sets RetryAttempts
1305  *
1306  * @param[in] aResp   Shared pointer for generating response message.
1307  * @param[in] retryAttempts  "AutomaticRetryAttempts" from request.
1308  *
1309  *@return None.
1310  */
1311 
1312 inline void
1313     setAutomaticRetryAttempts(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1314                               const uint32_t retryAttempts)
1315 {
1316     BMCWEB_LOG_DEBUG << "Set Automatic Retry Attempts.";
1317     crow::connections::systemBus->async_method_call(
1318         [aResp](const boost::system::error_code& ec) {
1319         if (ec)
1320         {
1321             BMCWEB_LOG_ERROR
1322                 << "DBUS response error: Set setAutomaticRetryAttempts" << ec;
1323             messages::internalError(aResp->res);
1324             return;
1325         }
1326         },
1327         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
1328         "org.freedesktop.DBus.Properties", "Set",
1329         "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts",
1330         std::variant<uint32_t>(retryAttempts));
1331 }
1332 
1333 /**
1334  * @brief Retrieves power restore policy over DBUS.
1335  *
1336  * @param[in] aResp     Shared pointer for generating response message.
1337  *
1338  * @return None.
1339  */
1340 inline void
1341     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1342 {
1343     BMCWEB_LOG_DEBUG << "Get power restore policy";
1344 
1345     sdbusplus::asio::getProperty<std::string>(
1346         *crow::connections::systemBus, "xyz.openbmc_project.Settings",
1347         "/xyz/openbmc_project/control/host0/power_restore_policy",
1348         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1349         [aResp](const boost::system::error_code& ec,
1350                 const std::string& policy) {
1351         if (ec)
1352         {
1353             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1354             return;
1355         }
1356 
1357         const boost::container::flat_map<std::string, std::string> policyMaps = {
1358             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn",
1359              "AlwaysOn"},
1360             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff",
1361              "AlwaysOff"},
1362             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore",
1363              "LastState"},
1364             // Return `AlwaysOff` when power restore policy set to "None"
1365             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None",
1366              "AlwaysOff"}};
1367 
1368         auto policyMapsIt = policyMaps.find(policy);
1369         if (policyMapsIt == policyMaps.end())
1370         {
1371             messages::internalError(aResp->res);
1372             return;
1373         }
1374 
1375         aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second;
1376         });
1377 }
1378 
1379 /**
1380  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1381  * TPM is required for booting the host.
1382  *
1383  * @param[in] aResp     Shared pointer for generating response message.
1384  *
1385  * @return None.
1386  */
1387 inline void getTrustedModuleRequiredToBoot(
1388     const std::shared_ptr<bmcweb::AsyncResp>& aResp)
1389 {
1390     BMCWEB_LOG_DEBUG << "Get TPM required to boot.";
1391     constexpr std::array<std::string_view, 1> interfaces = {
1392         "xyz.openbmc_project.Control.TPM.Policy"};
1393     dbus::utility::getSubTree(
1394         "/", 0, interfaces,
1395         [aResp](const boost::system::error_code& ec,
1396                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1397         if (ec)
1398         {
1399             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1400                              << ec;
1401             // This is an optional D-Bus object so just return if
1402             // error occurs
1403             return;
1404         }
1405         if (subtree.empty())
1406         {
1407             // As noted above, this is an optional interface so just return
1408             // if there is no instance found
1409             return;
1410         }
1411 
1412         /* When there is more than one TPMEnable object... */
1413         if (subtree.size() > 1)
1414         {
1415             BMCWEB_LOG_DEBUG
1416                 << "DBUS response has more than 1 TPM Enable object:"
1417                 << subtree.size();
1418             // Throw an internal Error and return
1419             messages::internalError(aResp->res);
1420             return;
1421         }
1422 
1423         // Make sure the Dbus response map has a service and objectPath
1424         // field
1425         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1426         {
1427             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1428             messages::internalError(aResp->res);
1429             return;
1430         }
1431 
1432         const std::string& path = subtree[0].first;
1433         const std::string& serv = subtree[0].second.begin()->first;
1434 
1435         // Valid TPM Enable object found, now reading the current value
1436         sdbusplus::asio::getProperty<bool>(
1437             *crow::connections::systemBus, serv, path,
1438             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1439             [aResp](const boost::system::error_code& ec2, bool tpmRequired) {
1440             if (ec2)
1441             {
1442                 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get"
1443                                  << ec2;
1444                 messages::internalError(aResp->res);
1445                 return;
1446             }
1447 
1448             if (tpmRequired)
1449             {
1450                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1451                     "Required";
1452             }
1453             else
1454             {
1455                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1456                     "Disabled";
1457             }
1458             });
1459         });
1460 }
1461 
1462 /**
1463  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1464  * TPM is required for booting the host.
1465  *
1466  * @param[in] aResp         Shared pointer for generating response message.
1467  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1468  *
1469  * @return None.
1470  */
1471 inline void setTrustedModuleRequiredToBoot(
1472     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired)
1473 {
1474     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot.";
1475     constexpr std::array<std::string_view, 1> interfaces = {
1476         "xyz.openbmc_project.Control.TPM.Policy"};
1477     dbus::utility::getSubTree(
1478         "/", 0, interfaces,
1479         [aResp,
1480          tpmRequired](const boost::system::error_code& ec,
1481                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
1482         if (ec)
1483         {
1484             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree"
1485                              << ec;
1486             messages::internalError(aResp->res);
1487             return;
1488         }
1489         if (subtree.empty())
1490         {
1491             messages::propertyValueNotInList(aResp->res, "ComputerSystem",
1492                                              "TrustedModuleRequiredToBoot");
1493             return;
1494         }
1495 
1496         /* When there is more than one TPMEnable object... */
1497         if (subtree.size() > 1)
1498         {
1499             BMCWEB_LOG_DEBUG
1500                 << "DBUS response has more than 1 TPM Enable object:"
1501                 << subtree.size();
1502             // Throw an internal Error and return
1503             messages::internalError(aResp->res);
1504             return;
1505         }
1506 
1507         // Make sure the Dbus response map has a service and objectPath
1508         // field
1509         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1510         {
1511             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!";
1512             messages::internalError(aResp->res);
1513             return;
1514         }
1515 
1516         const std::string& path = subtree[0].first;
1517         const std::string& serv = subtree[0].second.begin()->first;
1518 
1519         if (serv.empty())
1520         {
1521             BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!";
1522             messages::internalError(aResp->res);
1523             return;
1524         }
1525 
1526         // Valid TPM Enable object found, now setting the value
1527         crow::connections::systemBus->async_method_call(
1528             [aResp](const boost::system::error_code& ec2) {
1529             if (ec2)
1530             {
1531                 BMCWEB_LOG_DEBUG
1532                     << "DBUS response error: Set TrustedModuleRequiredToBoot"
1533                     << ec2;
1534                 messages::internalError(aResp->res);
1535                 return;
1536             }
1537             BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done.";
1538             },
1539             serv, path, "org.freedesktop.DBus.Properties", "Set",
1540             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable",
1541             dbus::utility::DbusVariantType(tpmRequired));
1542         });
1543 }
1544 
1545 /**
1546  * @brief Sets boot properties into DBUS object(s).
1547  *
1548  * @param[in] aResp           Shared pointer for generating response message.
1549  * @param[in] bootType        The boot type to set.
1550  * @return Integer error code.
1551  */
1552 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1553                         const std::optional<std::string>& bootType)
1554 {
1555     std::string bootTypeStr;
1556 
1557     if (!bootType)
1558     {
1559         return;
1560     }
1561 
1562     // Source target specified
1563     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType;
1564     // Figure out which DBUS interface and property to use
1565     if (*bootType == "Legacy")
1566     {
1567         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1568     }
1569     else if (*bootType == "UEFI")
1570     {
1571         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1572     }
1573     else
1574     {
1575         BMCWEB_LOG_DEBUG << "Invalid property value for "
1576                             "BootSourceOverrideMode: "
1577                          << *bootType;
1578         messages::propertyValueNotInList(aResp->res, *bootType,
1579                                          "BootSourceOverrideMode");
1580         return;
1581     }
1582 
1583     // Act on validated parameters
1584     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr;
1585 
1586     crow::connections::systemBus->async_method_call(
1587         [aResp](const boost::system::error_code& ec) {
1588         if (ec)
1589         {
1590             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1591             if (ec.value() == boost::asio::error::host_unreachable)
1592             {
1593                 messages::resourceNotFound(aResp->res, "Set", "BootType");
1594                 return;
1595             }
1596             messages::internalError(aResp->res);
1597             return;
1598         }
1599         BMCWEB_LOG_DEBUG << "Boot type update done.";
1600         },
1601         "xyz.openbmc_project.Settings",
1602         "/xyz/openbmc_project/control/host0/boot",
1603         "org.freedesktop.DBus.Properties", "Set",
1604         "xyz.openbmc_project.Control.Boot.Type", "BootType",
1605         dbus::utility::DbusVariantType(bootTypeStr));
1606 }
1607 
1608 /**
1609  * @brief Sets boot properties into DBUS object(s).
1610  *
1611  * @param[in] aResp           Shared pointer for generating response message.
1612  * @param[in] bootType        The boot type to set.
1613  * @return Integer error code.
1614  */
1615 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1616                           const std::optional<std::string>& bootEnable)
1617 {
1618     if (!bootEnable)
1619     {
1620         return;
1621     }
1622     // Source target specified
1623     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable;
1624 
1625     bool bootOverrideEnable = false;
1626     bool bootOverridePersistent = false;
1627     // Figure out which DBUS interface and property to use
1628     if (*bootEnable == "Disabled")
1629     {
1630         bootOverrideEnable = false;
1631     }
1632     else if (*bootEnable == "Once")
1633     {
1634         bootOverrideEnable = true;
1635         bootOverridePersistent = false;
1636     }
1637     else if (*bootEnable == "Continuous")
1638     {
1639         bootOverrideEnable = true;
1640         bootOverridePersistent = true;
1641     }
1642     else
1643     {
1644         BMCWEB_LOG_DEBUG
1645             << "Invalid property value for BootSourceOverrideEnabled: "
1646             << *bootEnable;
1647         messages::propertyValueNotInList(aResp->res, *bootEnable,
1648                                          "BootSourceOverrideEnabled");
1649         return;
1650     }
1651 
1652     // Act on validated parameters
1653     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable;
1654 
1655     crow::connections::systemBus->async_method_call(
1656         [aResp](const boost::system::error_code& ec2) {
1657         if (ec2)
1658         {
1659             BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
1660             messages::internalError(aResp->res);
1661             return;
1662         }
1663         BMCWEB_LOG_DEBUG << "Boot override enable update done.";
1664         },
1665         "xyz.openbmc_project.Settings",
1666         "/xyz/openbmc_project/control/host0/boot",
1667         "org.freedesktop.DBus.Properties", "Set",
1668         "xyz.openbmc_project.Object.Enable", "Enabled",
1669         dbus::utility::DbusVariantType(bootOverrideEnable));
1670 
1671     if (!bootOverrideEnable)
1672     {
1673         return;
1674     }
1675 
1676     // In case boot override is enabled we need to set correct value for the
1677     // 'one_time' enable DBus interface
1678     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: "
1679                      << bootOverridePersistent;
1680 
1681     crow::connections::systemBus->async_method_call(
1682         [aResp](const boost::system::error_code& ec) {
1683         if (ec)
1684         {
1685             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1686             messages::internalError(aResp->res);
1687             return;
1688         }
1689         BMCWEB_LOG_DEBUG << "Boot one_time update done.";
1690         },
1691         "xyz.openbmc_project.Settings",
1692         "/xyz/openbmc_project/control/host0/boot/one_time",
1693         "org.freedesktop.DBus.Properties", "Set",
1694         "xyz.openbmc_project.Object.Enable", "Enabled",
1695         dbus::utility::DbusVariantType(!bootOverridePersistent));
1696 }
1697 
1698 /**
1699  * @brief Sets boot properties into DBUS object(s).
1700  *
1701  * @param[in] aResp           Shared pointer for generating response message.
1702  * @param[in] bootSource      The boot source to set.
1703  *
1704  * @return Integer error code.
1705  */
1706 inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1707                                 const std::optional<std::string>& bootSource)
1708 {
1709     std::string bootSourceStr;
1710     std::string bootModeStr;
1711 
1712     if (!bootSource)
1713     {
1714         return;
1715     }
1716 
1717     // Source target specified
1718     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource;
1719     // Figure out which DBUS interface and property to use
1720     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) !=
1721         0)
1722     {
1723         BMCWEB_LOG_DEBUG
1724             << "Invalid property value for BootSourceOverrideTarget: "
1725             << *bootSource;
1726         messages::propertyValueNotInList(aResp->res, *bootSource,
1727                                          "BootSourceTargetOverride");
1728         return;
1729     }
1730 
1731     // Act on validated parameters
1732     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr;
1733     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr;
1734 
1735     crow::connections::systemBus->async_method_call(
1736         [aResp](const boost::system::error_code& ec) {
1737         if (ec)
1738         {
1739             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1740             messages::internalError(aResp->res);
1741             return;
1742         }
1743         BMCWEB_LOG_DEBUG << "Boot source update done.";
1744         },
1745         "xyz.openbmc_project.Settings",
1746         "/xyz/openbmc_project/control/host0/boot",
1747         "org.freedesktop.DBus.Properties", "Set",
1748         "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1749         dbus::utility::DbusVariantType(bootSourceStr));
1750 
1751     crow::connections::systemBus->async_method_call(
1752         [aResp](const boost::system::error_code& ec) {
1753         if (ec)
1754         {
1755             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1756             messages::internalError(aResp->res);
1757             return;
1758         }
1759         BMCWEB_LOG_DEBUG << "Boot mode update done.";
1760         },
1761         "xyz.openbmc_project.Settings",
1762         "/xyz/openbmc_project/control/host0/boot",
1763         "org.freedesktop.DBus.Properties", "Set",
1764         "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1765         dbus::utility::DbusVariantType(bootModeStr));
1766 }
1767 
1768 /**
1769  * @brief Sets Boot source override properties.
1770  *
1771  * @param[in] aResp      Shared pointer for generating response message.
1772  * @param[in] bootSource The boot source from incoming RF request.
1773  * @param[in] bootType   The boot type from incoming RF request.
1774  * @param[in] bootEnable The boot override enable from incoming RF request.
1775  *
1776  * @return Integer error code.
1777  */
1778 
1779 inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1780                               const std::optional<std::string>& bootSource,
1781                               const std::optional<std::string>& bootType,
1782                               const std::optional<std::string>& bootEnable)
1783 {
1784     BMCWEB_LOG_DEBUG << "Set boot information.";
1785 
1786     setBootModeOrSource(aResp, bootSource);
1787     setBootType(aResp, bootType);
1788     setBootEnable(aResp, bootEnable);
1789 }
1790 
1791 /**
1792  * @brief Sets AssetTag
1793  *
1794  * @param[in] aResp   Shared pointer for generating response message.
1795  * @param[in] assetTag  "AssetTag" from request.
1796  *
1797  * @return None.
1798  */
1799 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1800                         const std::string& assetTag)
1801 {
1802     constexpr std::array<std::string_view, 1> interfaces = {
1803         "xyz.openbmc_project.Inventory.Item.System"};
1804     dbus::utility::getSubTree(
1805         "/xyz/openbmc_project/inventory", 0, interfaces,
1806         [aResp,
1807          assetTag](const boost::system::error_code& ec,
1808                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
1809         if (ec)
1810         {
1811             BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec;
1812             messages::internalError(aResp->res);
1813             return;
1814         }
1815         if (subtree.empty())
1816         {
1817             BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!";
1818             messages::internalError(aResp->res);
1819             return;
1820         }
1821         // Assume only 1 system D-Bus object
1822         // Throw an error if there is more than 1
1823         if (subtree.size() > 1)
1824         {
1825             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!";
1826             messages::internalError(aResp->res);
1827             return;
1828         }
1829         if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1830         {
1831             BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!";
1832             messages::internalError(aResp->res);
1833             return;
1834         }
1835 
1836         const std::string& path = subtree[0].first;
1837         const std::string& service = subtree[0].second.begin()->first;
1838 
1839         if (service.empty())
1840         {
1841             BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!";
1842             messages::internalError(aResp->res);
1843             return;
1844         }
1845 
1846         crow::connections::systemBus->async_method_call(
1847             [aResp](const boost::system::error_code& ec2) {
1848             if (ec2)
1849             {
1850                 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set "
1851                                  << ec2;
1852                 messages::internalError(aResp->res);
1853                 return;
1854             }
1855             },
1856             service, path, "org.freedesktop.DBus.Properties", "Set",
1857             "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag",
1858             dbus::utility::DbusVariantType(assetTag));
1859         });
1860 }
1861 
1862 /**
1863  * @brief Sets automaticRetry (Auto Reboot)
1864  *
1865  * @param[in] aResp   Shared pointer for generating response message.
1866  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1867  *
1868  * @return None.
1869  */
1870 inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1871                               const std::string& automaticRetryConfig)
1872 {
1873     BMCWEB_LOG_DEBUG << "Set Automatic Retry.";
1874 
1875     // OpenBMC only supports "Disabled" and "RetryAttempts".
1876     bool autoRebootEnabled = false;
1877 
1878     if (automaticRetryConfig == "Disabled")
1879     {
1880         autoRebootEnabled = false;
1881     }
1882     else if (automaticRetryConfig == "RetryAttempts")
1883     {
1884         autoRebootEnabled = true;
1885     }
1886     else
1887     {
1888         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: "
1889                          << automaticRetryConfig;
1890         messages::propertyValueNotInList(aResp->res, automaticRetryConfig,
1891                                          "AutomaticRetryConfig");
1892         return;
1893     }
1894 
1895     crow::connections::systemBus->async_method_call(
1896         [aResp](const boost::system::error_code& ec) {
1897         if (ec)
1898         {
1899             messages::internalError(aResp->res);
1900             return;
1901         }
1902         },
1903         "xyz.openbmc_project.Settings",
1904         "/xyz/openbmc_project/control/host0/auto_reboot",
1905         "org.freedesktop.DBus.Properties", "Set",
1906         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1907         dbus::utility::DbusVariantType(autoRebootEnabled));
1908 }
1909 
1910 /**
1911  * @brief Sets power restore policy properties.
1912  *
1913  * @param[in] aResp   Shared pointer for generating response message.
1914  * @param[in] policy  power restore policy properties from request.
1915  *
1916  * @return None.
1917  */
1918 inline void
1919     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
1920                           const std::string& policy)
1921 {
1922     BMCWEB_LOG_DEBUG << "Set power restore policy.";
1923 
1924     const boost::container::flat_map<std::string, std::string> policyMaps = {
1925         {"AlwaysOn",
1926          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"},
1927         {"AlwaysOff",
1928          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"},
1929         {"LastState",
1930          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}};
1931 
1932     std::string powerRestorPolicy;
1933 
1934     auto policyMapsIt = policyMaps.find(policy);
1935     if (policyMapsIt == policyMaps.end())
1936     {
1937         messages::propertyValueNotInList(aResp->res, policy,
1938                                          "PowerRestorePolicy");
1939         return;
1940     }
1941 
1942     powerRestorPolicy = policyMapsIt->second;
1943 
1944     crow::connections::systemBus->async_method_call(
1945         [aResp](const boost::system::error_code& ec) {
1946         if (ec)
1947         {
1948             messages::internalError(aResp->res);
1949             return;
1950         }
1951         },
1952         "xyz.openbmc_project.Settings",
1953         "/xyz/openbmc_project/control/host0/power_restore_policy",
1954         "org.freedesktop.DBus.Properties", "Set",
1955         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1956         dbus::utility::DbusVariantType(powerRestorPolicy));
1957 }
1958 
1959 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
1960 /**
1961  * @brief Retrieves provisioning status
1962  *
1963  * @param[in] aResp     Shared pointer for completing asynchronous calls.
1964  *
1965  * @return None.
1966  */
1967 inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp)
1968 {
1969     BMCWEB_LOG_DEBUG << "Get OEM information.";
1970     sdbusplus::asio::getAllProperties(
1971         *crow::connections::systemBus, "xyz.openbmc_project.PFR.Manager",
1972         "/xyz/openbmc_project/pfr", "xyz.openbmc_project.PFR.Attributes",
1973         [aResp](const boost::system::error_code& ec,
1974                 const dbus::utility::DBusPropertiesMap& propertiesList) {
1975         nlohmann::json& oemPFR =
1976             aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1977         aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1978             "#OemComputerSystem.OpenBmc";
1979         oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning";
1980 
1981         if (ec)
1982         {
1983             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
1984             // not an error, don't have to have the interface
1985             oemPFR["ProvisioningStatus"] = "NotProvisioned";
1986             return;
1987         }
1988 
1989         const bool* provState = nullptr;
1990         const bool* lockState = nullptr;
1991 
1992         const bool success = sdbusplus::unpackPropertiesNoThrow(
1993             dbus_utils::UnpackErrorPrinter(), propertiesList, "UfmProvisioned",
1994             provState, "UfmLocked", lockState);
1995 
1996         if (!success)
1997         {
1998             messages::internalError(aResp->res);
1999             return;
2000         }
2001 
2002         if ((provState == nullptr) || (lockState == nullptr))
2003         {
2004             BMCWEB_LOG_DEBUG << "Unable to get PFR attributes.";
2005             messages::internalError(aResp->res);
2006             return;
2007         }
2008 
2009         if (*provState == true)
2010         {
2011             if (*lockState == true)
2012             {
2013                 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked";
2014             }
2015             else
2016             {
2017                 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked";
2018             }
2019         }
2020         else
2021         {
2022             oemPFR["ProvisioningStatus"] = "NotProvisioned";
2023         }
2024         });
2025 }
2026 #endif
2027 
2028 /**
2029  * @brief Translate the PowerMode to a response message.
2030  *
2031  * @param[in] aResp  Shared pointer for generating response message.
2032  * @param[in] modeValue  PowerMode value to be translated
2033  *
2034  * @return None.
2035  */
2036 inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2037                                const std::string& modeValue)
2038 {
2039     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
2040     {
2041         aResp->res.jsonValue["PowerMode"] = "Static";
2042     }
2043     else if (
2044         modeValue ==
2045         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
2046     {
2047         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance";
2048     }
2049     else if (modeValue ==
2050              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
2051     {
2052         aResp->res.jsonValue["PowerMode"] = "PowerSaving";
2053     }
2054     else if (modeValue ==
2055              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
2056     {
2057         aResp->res.jsonValue["PowerMode"] = "OEM";
2058     }
2059     else
2060     {
2061         // Any other values would be invalid
2062         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue;
2063         messages::internalError(aResp->res);
2064     }
2065 }
2066 
2067 /**
2068  * @brief Retrieves system power mode
2069  *
2070  * @param[in] aResp  Shared pointer for generating response message.
2071  *
2072  * @return None.
2073  */
2074 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2075 {
2076     BMCWEB_LOG_DEBUG << "Get power mode.";
2077 
2078     // Get Power Mode object path:
2079     constexpr std::array<std::string_view, 1> interfaces = {
2080         "xyz.openbmc_project.Control.Power.Mode"};
2081     dbus::utility::getSubTree(
2082         "/", 0, interfaces,
2083         [aResp](const boost::system::error_code& ec,
2084                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2085         if (ec)
2086         {
2087             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
2088                              << ec;
2089             // This is an optional D-Bus object so just return if
2090             // error occurs
2091             return;
2092         }
2093         if (subtree.empty())
2094         {
2095             // As noted above, this is an optional interface so just return
2096             // if there is no instance found
2097             return;
2098         }
2099         if (subtree.size() > 1)
2100         {
2101             // More then one PowerMode object is not supported and is an
2102             // error
2103             BMCWEB_LOG_DEBUG
2104                 << "Found more than 1 system D-Bus Power.Mode objects: "
2105                 << subtree.size();
2106             messages::internalError(aResp->res);
2107             return;
2108         }
2109         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2110         {
2111             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2112             messages::internalError(aResp->res);
2113             return;
2114         }
2115         const std::string& path = subtree[0].first;
2116         const std::string& service = subtree[0].second.begin()->first;
2117         if (service.empty())
2118         {
2119             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2120             messages::internalError(aResp->res);
2121             return;
2122         }
2123         // Valid Power Mode object found, now read the current value
2124         sdbusplus::asio::getProperty<std::string>(
2125             *crow::connections::systemBus, service, path,
2126             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2127             [aResp](const boost::system::error_code& ec2,
2128                     const std::string& pmode) {
2129             if (ec2)
2130             {
2131                 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: "
2132                                  << ec2;
2133                 messages::internalError(aResp->res);
2134                 return;
2135             }
2136 
2137             aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = {
2138                 "Static", "MaximumPerformance", "PowerSaving"};
2139 
2140             BMCWEB_LOG_DEBUG << "Current power mode: " << pmode;
2141             translatePowerMode(aResp, pmode);
2142             });
2143         });
2144 }
2145 
2146 /**
2147  * @brief Validate the specified mode is valid and return the PowerMode
2148  * name associated with that string
2149  *
2150  * @param[in] aResp   Shared pointer for generating response message.
2151  * @param[in] modeString  String representing the desired PowerMode
2152  *
2153  * @return PowerMode value or empty string if mode is not valid
2154  */
2155 inline std::string
2156     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2157                       const std::string& modeString)
2158 {
2159     std::string mode;
2160 
2161     if (modeString == "Static")
2162     {
2163         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2164     }
2165     else if (modeString == "MaximumPerformance")
2166     {
2167         mode =
2168             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2169     }
2170     else if (modeString == "PowerSaving")
2171     {
2172         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2173     }
2174     else
2175     {
2176         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode");
2177     }
2178     return mode;
2179 }
2180 
2181 /**
2182  * @brief Sets system power mode.
2183  *
2184  * @param[in] aResp   Shared pointer for generating response message.
2185  * @param[in] pmode   System power mode from request.
2186  *
2187  * @return None.
2188  */
2189 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2190                          const std::string& pmode)
2191 {
2192     BMCWEB_LOG_DEBUG << "Set power mode.";
2193 
2194     std::string powerMode = validatePowerMode(aResp, pmode);
2195     if (powerMode.empty())
2196     {
2197         return;
2198     }
2199 
2200     // Get Power Mode object path:
2201     constexpr std::array<std::string_view, 1> interfaces = {
2202         "xyz.openbmc_project.Control.Power.Mode"};
2203     dbus::utility::getSubTree(
2204         "/", 0, interfaces,
2205         [aResp,
2206          powerMode](const boost::system::error_code& ec,
2207                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2208         if (ec)
2209         {
2210             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree "
2211                              << ec;
2212             // This is an optional D-Bus object, but user attempted to patch
2213             messages::internalError(aResp->res);
2214             return;
2215         }
2216         if (subtree.empty())
2217         {
2218             // This is an optional D-Bus object, but user attempted to patch
2219             messages::resourceNotFound(aResp->res, "ComputerSystem",
2220                                        "PowerMode");
2221             return;
2222         }
2223         if (subtree.size() > 1)
2224         {
2225             // More then one PowerMode object is not supported and is an
2226             // error
2227             BMCWEB_LOG_DEBUG
2228                 << "Found more than 1 system D-Bus Power.Mode objects: "
2229                 << subtree.size();
2230             messages::internalError(aResp->res);
2231             return;
2232         }
2233         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2234         {
2235             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!";
2236             messages::internalError(aResp->res);
2237             return;
2238         }
2239         const std::string& path = subtree[0].first;
2240         const std::string& service = subtree[0].second.begin()->first;
2241         if (service.empty())
2242         {
2243             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!";
2244             messages::internalError(aResp->res);
2245             return;
2246         }
2247 
2248         BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> "
2249                          << path;
2250 
2251         // Set the Power Mode property
2252         crow::connections::systemBus->async_method_call(
2253             [aResp](const boost::system::error_code& ec2) {
2254             if (ec2)
2255             {
2256                 messages::internalError(aResp->res);
2257                 return;
2258             }
2259             },
2260             service, path, "org.freedesktop.DBus.Properties", "Set",
2261             "xyz.openbmc_project.Control.Power.Mode", "PowerMode",
2262             dbus::utility::DbusVariantType(powerMode));
2263         });
2264 }
2265 
2266 /**
2267  * @brief Translates watchdog timeout action DBUS property value to redfish.
2268  *
2269  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2270  *
2271  * @return Returns as a string, the timeout action in Redfish terms. If
2272  * translation cannot be done, returns an empty string.
2273  */
2274 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2275 {
2276     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2277     {
2278         return "None";
2279     }
2280     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2281     {
2282         return "ResetSystem";
2283     }
2284     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2285     {
2286         return "PowerDown";
2287     }
2288     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2289     {
2290         return "PowerCycle";
2291     }
2292 
2293     return "";
2294 }
2295 
2296 /**
2297  *@brief Translates timeout action from Redfish to DBUS property value.
2298  *
2299  *@param[in] rfAction The timeout action in Redfish.
2300  *
2301  *@return Returns as a string, the time_out action as expected by DBUS.
2302  *If translation cannot be done, returns an empty string.
2303  */
2304 
2305 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2306 {
2307     if (rfAction == "None")
2308     {
2309         return "xyz.openbmc_project.State.Watchdog.Action.None";
2310     }
2311     if (rfAction == "PowerCycle")
2312     {
2313         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2314     }
2315     if (rfAction == "PowerDown")
2316     {
2317         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2318     }
2319     if (rfAction == "ResetSystem")
2320     {
2321         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2322     }
2323 
2324     return "";
2325 }
2326 
2327 /**
2328  * @brief Retrieves host watchdog timer properties over DBUS
2329  *
2330  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2331  *
2332  * @return None.
2333  */
2334 inline void
2335     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2336 {
2337     BMCWEB_LOG_DEBUG << "Get host watchodg";
2338     sdbusplus::asio::getAllProperties(
2339         *crow::connections::systemBus, "xyz.openbmc_project.Watchdog",
2340         "/xyz/openbmc_project/watchdog/host0",
2341         "xyz.openbmc_project.State.Watchdog",
2342         [aResp](const boost::system::error_code& ec,
2343                 const dbus::utility::DBusPropertiesMap& properties) {
2344         if (ec)
2345         {
2346             // watchdog service is stopped
2347             BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2348             return;
2349         }
2350 
2351         BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop.";
2352 
2353         nlohmann::json& hostWatchdogTimer =
2354             aResp->res.jsonValue["HostWatchdogTimer"];
2355 
2356         // watchdog service is running/enabled
2357         hostWatchdogTimer["Status"]["State"] = "Enabled";
2358 
2359         const bool* enabled = nullptr;
2360         const std::string* expireAction = nullptr;
2361 
2362         const bool success = sdbusplus::unpackPropertiesNoThrow(
2363             dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2364             "ExpireAction", expireAction);
2365 
2366         if (!success)
2367         {
2368             messages::internalError(aResp->res);
2369             return;
2370         }
2371 
2372         if (enabled != nullptr)
2373         {
2374             hostWatchdogTimer["FunctionEnabled"] = *enabled;
2375         }
2376 
2377         if (expireAction != nullptr)
2378         {
2379             std::string action = dbusToRfWatchdogAction(*expireAction);
2380             if (action.empty())
2381             {
2382                 messages::internalError(aResp->res);
2383                 return;
2384             }
2385             hostWatchdogTimer["TimeoutAction"] = action;
2386         }
2387         });
2388 }
2389 
2390 /**
2391  * @brief Sets Host WatchDog Timer properties.
2392  *
2393  * @param[in] aResp      Shared pointer for generating response message.
2394  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2395  *                       RF request.
2396  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2397  *
2398  * @return None.
2399  */
2400 inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2401                              const std::optional<bool> wdtEnable,
2402                              const std::optional<std::string>& wdtTimeOutAction)
2403 {
2404     BMCWEB_LOG_DEBUG << "Set host watchdog";
2405 
2406     if (wdtTimeOutAction)
2407     {
2408         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2409         // check if TimeOut Action is Valid
2410         if (wdtTimeOutActStr.empty())
2411         {
2412             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: "
2413                              << *wdtTimeOutAction;
2414             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction,
2415                                              "TimeoutAction");
2416             return;
2417         }
2418 
2419         crow::connections::systemBus->async_method_call(
2420             [aResp](const boost::system::error_code& ec) {
2421             if (ec)
2422             {
2423                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2424                 messages::internalError(aResp->res);
2425                 return;
2426             }
2427             },
2428             "xyz.openbmc_project.Watchdog",
2429             "/xyz/openbmc_project/watchdog/host0",
2430             "org.freedesktop.DBus.Properties", "Set",
2431             "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2432             dbus::utility::DbusVariantType(wdtTimeOutActStr));
2433     }
2434 
2435     if (wdtEnable)
2436     {
2437         crow::connections::systemBus->async_method_call(
2438             [aResp](const boost::system::error_code& ec) {
2439             if (ec)
2440             {
2441                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
2442                 messages::internalError(aResp->res);
2443                 return;
2444             }
2445             },
2446             "xyz.openbmc_project.Watchdog",
2447             "/xyz/openbmc_project/watchdog/host0",
2448             "org.freedesktop.DBus.Properties", "Set",
2449             "xyz.openbmc_project.State.Watchdog", "Enabled",
2450             dbus::utility::DbusVariantType(*wdtEnable));
2451     }
2452 }
2453 
2454 /**
2455  * @brief Parse the Idle Power Saver properties into json
2456  *
2457  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2458  * @param[in] properties  IPS property data from DBus.
2459  *
2460  * @return true if successful
2461  */
2462 inline bool
2463     parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2464                        const dbus::utility::DBusPropertiesMap& properties)
2465 {
2466     const bool* enabled = nullptr;
2467     const uint8_t* enterUtilizationPercent = nullptr;
2468     const uint64_t* enterDwellTime = nullptr;
2469     const uint8_t* exitUtilizationPercent = nullptr;
2470     const uint64_t* exitDwellTime = nullptr;
2471 
2472     const bool success = sdbusplus::unpackPropertiesNoThrow(
2473         dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2474         "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime",
2475         enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent,
2476         "ExitDwellTime", exitDwellTime);
2477 
2478     if (!success)
2479     {
2480         return false;
2481     }
2482 
2483     if (enabled != nullptr)
2484     {
2485         aResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled;
2486     }
2487 
2488     if (enterUtilizationPercent != nullptr)
2489     {
2490         aResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] =
2491             *enterUtilizationPercent;
2492     }
2493 
2494     if (enterDwellTime != nullptr)
2495     {
2496         const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime);
2497         aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2498             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2499                 .count();
2500     }
2501 
2502     if (exitUtilizationPercent != nullptr)
2503     {
2504         aResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] =
2505             *exitUtilizationPercent;
2506     }
2507 
2508     if (exitDwellTime != nullptr)
2509     {
2510         const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime);
2511         aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2512             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2513                 .count();
2514     }
2515 
2516     return true;
2517 }
2518 
2519 /**
2520  * @brief Retrieves host watchdog timer properties over DBUS
2521  *
2522  * @param[in] aResp     Shared pointer for completing asynchronous calls.
2523  *
2524  * @return None.
2525  */
2526 inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp)
2527 {
2528     BMCWEB_LOG_DEBUG << "Get idle power saver parameters";
2529 
2530     // Get IdlePowerSaver object path:
2531     constexpr std::array<std::string_view, 1> interfaces = {
2532         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2533     dbus::utility::getSubTree(
2534         "/", 0, interfaces,
2535         [aResp](const boost::system::error_code& ec,
2536                 const dbus::utility::MapperGetSubTreeResponse& subtree) {
2537         if (ec)
2538         {
2539             BMCWEB_LOG_DEBUG
2540                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2541                 << ec;
2542             messages::internalError(aResp->res);
2543             return;
2544         }
2545         if (subtree.empty())
2546         {
2547             // This is an optional interface so just return
2548             // if there is no instance found
2549             BMCWEB_LOG_DEBUG << "No instances found";
2550             return;
2551         }
2552         if (subtree.size() > 1)
2553         {
2554             // More then one PowerIdlePowerSaver object is not supported and
2555             // is an error
2556             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus "
2557                                 "Power.IdlePowerSaver objects: "
2558                              << subtree.size();
2559             messages::internalError(aResp->res);
2560             return;
2561         }
2562         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2563         {
2564             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2565             messages::internalError(aResp->res);
2566             return;
2567         }
2568         const std::string& path = subtree[0].first;
2569         const std::string& service = subtree[0].second.begin()->first;
2570         if (service.empty())
2571         {
2572             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2573             messages::internalError(aResp->res);
2574             return;
2575         }
2576 
2577         // Valid IdlePowerSaver object found, now read the current values
2578         sdbusplus::asio::getAllProperties(
2579             *crow::connections::systemBus, service, path,
2580             "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2581             [aResp](const boost::system::error_code& ec2,
2582                     const dbus::utility::DBusPropertiesMap& properties) {
2583             if (ec2)
2584             {
2585                 BMCWEB_LOG_ERROR
2586                     << "DBUS response error on IdlePowerSaver GetAll: " << ec2;
2587                 messages::internalError(aResp->res);
2588                 return;
2589             }
2590 
2591             if (!parseIpsProperties(aResp, properties))
2592             {
2593                 messages::internalError(aResp->res);
2594                 return;
2595             }
2596             });
2597         });
2598 
2599     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters";
2600 }
2601 
2602 /**
2603  * @brief Sets Idle Power Saver properties.
2604  *
2605  * @param[in] aResp      Shared pointer for generating response message.
2606  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2607  *                       RF request.
2608  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2609  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2610  * before entering idle state.
2611  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2612  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2613  * before exiting idle state
2614  *
2615  * @return None.
2616  */
2617 inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
2618                               const std::optional<bool> ipsEnable,
2619                               const std::optional<uint8_t> ipsEnterUtil,
2620                               const std::optional<uint64_t> ipsEnterTime,
2621                               const std::optional<uint8_t> ipsExitUtil,
2622                               const std::optional<uint64_t> ipsExitTime)
2623 {
2624     BMCWEB_LOG_DEBUG << "Set idle power saver properties";
2625 
2626     // Get IdlePowerSaver object path:
2627     constexpr std::array<std::string_view, 1> interfaces = {
2628         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2629     dbus::utility::getSubTree(
2630         "/", 0, interfaces,
2631         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2632          ipsExitTime](const boost::system::error_code& ec,
2633                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
2634         if (ec)
2635         {
2636             BMCWEB_LOG_DEBUG
2637                 << "DBUS response error on Power.IdlePowerSaver GetSubTree "
2638                 << ec;
2639             messages::internalError(aResp->res);
2640             return;
2641         }
2642         if (subtree.empty())
2643         {
2644             // This is an optional D-Bus object, but user attempted to patch
2645             messages::resourceNotFound(aResp->res, "ComputerSystem",
2646                                        "IdlePowerSaver");
2647             return;
2648         }
2649         if (subtree.size() > 1)
2650         {
2651             // More then one PowerIdlePowerSaver object is not supported and
2652             // is an error
2653             BMCWEB_LOG_DEBUG
2654                 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: "
2655                 << subtree.size();
2656             messages::internalError(aResp->res);
2657             return;
2658         }
2659         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2660         {
2661             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!";
2662             messages::internalError(aResp->res);
2663             return;
2664         }
2665         const std::string& path = subtree[0].first;
2666         const std::string& service = subtree[0].second.begin()->first;
2667         if (service.empty())
2668         {
2669             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!";
2670             messages::internalError(aResp->res);
2671             return;
2672         }
2673 
2674         // Valid Power IdlePowerSaver object found, now set any values that
2675         // need to be updated
2676 
2677         if (ipsEnable)
2678         {
2679             crow::connections::systemBus->async_method_call(
2680                 [aResp](const boost::system::error_code& ec2) {
2681                 if (ec2)
2682                 {
2683                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2684                     messages::internalError(aResp->res);
2685                     return;
2686                 }
2687                 },
2688                 service, path, "org.freedesktop.DBus.Properties", "Set",
2689                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled",
2690                 dbus::utility::DbusVariantType(*ipsEnable));
2691         }
2692         if (ipsEnterUtil)
2693         {
2694             crow::connections::systemBus->async_method_call(
2695                 [aResp](const boost::system::error_code& ec2) {
2696                 if (ec2)
2697                 {
2698                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2699                     messages::internalError(aResp->res);
2700                     return;
2701                 }
2702                 },
2703                 service, path, "org.freedesktop.DBus.Properties", "Set",
2704                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2705                 "EnterUtilizationPercent",
2706                 dbus::utility::DbusVariantType(*ipsEnterUtil));
2707         }
2708         if (ipsEnterTime)
2709         {
2710             // Convert from seconds into milliseconds for DBus
2711             const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2712             crow::connections::systemBus->async_method_call(
2713                 [aResp](const boost::system::error_code& ec2) {
2714                 if (ec2)
2715                 {
2716                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2717                     messages::internalError(aResp->res);
2718                     return;
2719                 }
2720                 },
2721                 service, path, "org.freedesktop.DBus.Properties", "Set",
2722                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2723                 "EnterDwellTime",
2724                 dbus::utility::DbusVariantType(timeMilliseconds));
2725         }
2726         if (ipsExitUtil)
2727         {
2728             crow::connections::systemBus->async_method_call(
2729                 [aResp](const boost::system::error_code& ec2) {
2730                 if (ec2)
2731                 {
2732                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2733                     messages::internalError(aResp->res);
2734                     return;
2735                 }
2736                 },
2737                 service, path, "org.freedesktop.DBus.Properties", "Set",
2738                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2739                 "ExitUtilizationPercent",
2740                 dbus::utility::DbusVariantType(*ipsExitUtil));
2741         }
2742         if (ipsExitTime)
2743         {
2744             // Convert from seconds into milliseconds for DBus
2745             const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2746             crow::connections::systemBus->async_method_call(
2747                 [aResp](const boost::system::error_code& ec2) {
2748                 if (ec2)
2749                 {
2750                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2;
2751                     messages::internalError(aResp->res);
2752                     return;
2753                 }
2754                 },
2755                 service, path, "org.freedesktop.DBus.Properties", "Set",
2756                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2757                 "ExitDwellTime",
2758                 dbus::utility::DbusVariantType(timeMilliseconds));
2759         }
2760         });
2761 
2762     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters";
2763 }
2764 
2765 inline void handleComputerSystemHead(
2766     crow::App& app, const crow::Request& req,
2767     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2768 {
2769     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2770     {
2771         return;
2772     }
2773     asyncResp->res.addHeader(
2774         boost::beast::http::field::link,
2775         "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby");
2776 }
2777 
2778 /**
2779  * SystemsCollection derived class for delivering ComputerSystems Collection
2780  * Schema
2781  */
2782 inline void requestRoutesSystemsCollection(App& app)
2783 {
2784     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2785         .privileges(redfish::privileges::headComputerSystemCollection)
2786         .methods(boost::beast::http::verb::head)(
2787             std::bind_front(handleComputerSystemHead, std::ref(app)));
2788 
2789     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
2790         .privileges(redfish::privileges::getComputerSystemCollection)
2791         .methods(boost::beast::http::verb::get)(
2792             [&app](const crow::Request& req,
2793                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2794         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2795         {
2796             return;
2797         }
2798 
2799         asyncResp->res.addHeader(
2800             boost::beast::http::field::link,
2801             "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby");
2802         asyncResp->res.jsonValue["@odata.type"] =
2803             "#ComputerSystemCollection.ComputerSystemCollection";
2804         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2805         asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2806 
2807         sdbusplus::asio::getProperty<std::string>(
2808             *crow::connections::systemBus, "xyz.openbmc_project.Settings",
2809             "/xyz/openbmc_project/network/hypervisor",
2810             "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
2811             [asyncResp](const boost::system::error_code& ec2,
2812                         const std::string& /*hostName*/) {
2813             nlohmann::json& ifaceArray = asyncResp->res.jsonValue["Members"];
2814             ifaceArray = nlohmann::json::array();
2815             auto& count = asyncResp->res.jsonValue["Members@odata.count"];
2816 
2817             nlohmann::json::object_t system;
2818             system["@odata.id"] = "/redfish/v1/Systems/system";
2819             ifaceArray.emplace_back(std::move(system));
2820             count = ifaceArray.size();
2821             if (!ec2)
2822             {
2823                 BMCWEB_LOG_DEBUG << "Hypervisor is available";
2824                 nlohmann::json::object_t hypervisor;
2825                 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor";
2826                 ifaceArray.emplace_back(std::move(hypervisor));
2827                 count = ifaceArray.size();
2828             }
2829             });
2830         });
2831 }
2832 
2833 /**
2834  * Function transceives data with dbus directly.
2835  */
2836 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2837 {
2838     constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2839     constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2840     constexpr const char* interfaceName =
2841         "xyz.openbmc_project.Control.Host.NMI";
2842     constexpr const char* method = "NMI";
2843 
2844     crow::connections::systemBus->async_method_call(
2845         [asyncResp](const boost::system::error_code& ec) {
2846         if (ec)
2847         {
2848             BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec;
2849             messages::internalError(asyncResp->res);
2850             return;
2851         }
2852         messages::success(asyncResp->res);
2853         },
2854         serviceName, objectPath, interfaceName, method);
2855 }
2856 
2857 /**
2858  * SystemActionsReset class supports handle POST method for Reset action.
2859  * The class retrieves and sends data directly to D-Bus.
2860  */
2861 inline void requestRoutesSystemActionsReset(App& app)
2862 {
2863     /**
2864      * Function handles POST method request.
2865      * Analyzes POST body message before sends Reset request data to D-Bus.
2866      */
2867     BMCWEB_ROUTE(app,
2868                  "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset/")
2869         .privileges(redfish::privileges::postComputerSystem)
2870         .methods(boost::beast::http::verb::post)(
2871             [&app](const crow::Request& req,
2872                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2873         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2874         {
2875             return;
2876         }
2877         std::string resetType;
2878         if (!json_util::readJsonAction(req, asyncResp->res, "ResetType",
2879                                        resetType))
2880         {
2881             return;
2882         }
2883 
2884         // Get the command and host vs. chassis
2885         std::string command;
2886         bool hostCommand = true;
2887         if ((resetType == "On") || (resetType == "ForceOn"))
2888         {
2889             command = "xyz.openbmc_project.State.Host.Transition.On";
2890             hostCommand = true;
2891         }
2892         else if (resetType == "ForceOff")
2893         {
2894             command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2895             hostCommand = false;
2896         }
2897         else if (resetType == "ForceRestart")
2898         {
2899             command =
2900                 "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2901             hostCommand = true;
2902         }
2903         else if (resetType == "GracefulShutdown")
2904         {
2905             command = "xyz.openbmc_project.State.Host.Transition.Off";
2906             hostCommand = true;
2907         }
2908         else if (resetType == "GracefulRestart")
2909         {
2910             command =
2911                 "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2912             hostCommand = true;
2913         }
2914         else if (resetType == "PowerCycle")
2915         {
2916             command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2917             hostCommand = true;
2918         }
2919         else if (resetType == "Nmi")
2920         {
2921             doNMI(asyncResp);
2922             return;
2923         }
2924         else
2925         {
2926             messages::actionParameterUnknown(asyncResp->res, "Reset",
2927                                              resetType);
2928             return;
2929         }
2930 
2931         if (hostCommand)
2932         {
2933             crow::connections::systemBus->async_method_call(
2934                 [asyncResp, resetType](const boost::system::error_code& ec) {
2935                 if (ec)
2936                 {
2937                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2938                     if (ec.value() == boost::asio::error::invalid_argument)
2939                     {
2940                         messages::actionParameterNotSupported(
2941                             asyncResp->res, resetType, "Reset");
2942                     }
2943                     else
2944                     {
2945                         messages::internalError(asyncResp->res);
2946                     }
2947                     return;
2948                 }
2949                 messages::success(asyncResp->res);
2950                 },
2951                 "xyz.openbmc_project.State.Host",
2952                 "/xyz/openbmc_project/state/host0",
2953                 "org.freedesktop.DBus.Properties", "Set",
2954                 "xyz.openbmc_project.State.Host", "RequestedHostTransition",
2955                 dbus::utility::DbusVariantType{command});
2956         }
2957         else
2958         {
2959             crow::connections::systemBus->async_method_call(
2960                 [asyncResp, resetType](const boost::system::error_code& ec) {
2961                 if (ec)
2962                 {
2963                     BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec;
2964                     if (ec.value() == boost::asio::error::invalid_argument)
2965                     {
2966                         messages::actionParameterNotSupported(
2967                             asyncResp->res, resetType, "Reset");
2968                     }
2969                     else
2970                     {
2971                         messages::internalError(asyncResp->res);
2972                     }
2973                     return;
2974                 }
2975                 messages::success(asyncResp->res);
2976                 },
2977                 "xyz.openbmc_project.State.Chassis",
2978                 "/xyz/openbmc_project/state/chassis0",
2979                 "org.freedesktop.DBus.Properties", "Set",
2980                 "xyz.openbmc_project.State.Chassis", "RequestedPowerTransition",
2981                 dbus::utility::DbusVariantType{command});
2982         }
2983         });
2984 }
2985 
2986 inline void handleComputerSystemCollectionHead(
2987     App& app, const crow::Request& req,
2988     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2989 {
2990     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2991     {
2992         return;
2993     }
2994 
2995     asyncResp->res.addHeader(
2996         boost::beast::http::field::link,
2997         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
2998 }
2999 
3000 inline void afterPortRequest(
3001     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3002     const boost::system::error_code& ec,
3003     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
3004 {
3005     if (ec)
3006     {
3007         messages::internalError(asyncResp->res);
3008         return;
3009     }
3010     for (const auto& data : socketData)
3011     {
3012         const std::string& socketPath = get<0>(data);
3013         const std::string& protocolName = get<1>(data);
3014         bool isProtocolEnabled = get<2>(data);
3015         nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"];
3016         dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled;
3017         // need to retrieve port number for
3018         // obmc-console-ssh service
3019         if (protocolName == "SSH")
3020         {
3021             getPortNumber(socketPath, [asyncResp, protocolName](
3022                                           const boost::system::error_code& ec1,
3023                                           int portNumber) {
3024                 if (ec1)
3025                 {
3026                     messages::internalError(asyncResp->res);
3027                     return;
3028                 }
3029                 nlohmann::json& dataJson1 =
3030                     asyncResp->res.jsonValue["SerialConsole"];
3031                 dataJson1[protocolName]["Port"] = portNumber;
3032             });
3033         }
3034     }
3035 }
3036 /**
3037  * Systems derived class for delivering Computer Systems Schema.
3038  */
3039 inline void requestRoutesSystems(App& app)
3040 {
3041     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/")
3042         .privileges(redfish::privileges::headComputerSystem)
3043         .methods(boost::beast::http::verb::head)(
3044             std::bind_front(handleComputerSystemCollectionHead, std::ref(app)));
3045     /**
3046      * Functions triggers appropriate requests on DBus
3047      */
3048     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3049         .privileges(redfish::privileges::getComputerSystem)
3050         .methods(boost::beast::http::verb::get)(
3051             [&app](const crow::Request& req,
3052                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3053                    const std::string& systemName) {
3054         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3055         {
3056             return;
3057         }
3058 
3059         if (systemName == "hypervisor")
3060         {
3061             handleHypervisorSystemGet(asyncResp);
3062             return;
3063         }
3064 
3065         if (systemName != "system")
3066         {
3067             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3068                                        systemName);
3069             return;
3070         }
3071         asyncResp->res.addHeader(
3072             boost::beast::http::field::link,
3073             "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3074         asyncResp->res.jsonValue["@odata.type"] =
3075             "#ComputerSystem.v1_16_0.ComputerSystem";
3076         asyncResp->res.jsonValue["Name"] = "system";
3077         asyncResp->res.jsonValue["Id"] = "system";
3078         asyncResp->res.jsonValue["SystemType"] = "Physical";
3079         asyncResp->res.jsonValue["Description"] = "Computer System";
3080         asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
3081         if constexpr (bmcwebEnableProcMemStatus)
3082         {
3083             asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] =
3084                 "Disabled";
3085             asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] =
3086                 "Disabled";
3087         }
3088         asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
3089             uint64_t(0);
3090         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system";
3091 
3092         asyncResp->res.jsonValue["Processors"]["@odata.id"] =
3093             "/redfish/v1/Systems/system/Processors";
3094         asyncResp->res.jsonValue["Memory"]["@odata.id"] =
3095             "/redfish/v1/Systems/system/Memory";
3096         asyncResp->res.jsonValue["Storage"]["@odata.id"] =
3097             "/redfish/v1/Systems/system/Storage";
3098         asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] =
3099             "/redfish/v1/Systems/system/FabricAdapters";
3100 
3101         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
3102             "/redfish/v1/Systems/system/Actions/ComputerSystem.Reset";
3103         asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]
3104                                 ["@Redfish.ActionInfo"] =
3105             "/redfish/v1/Systems/system/ResetActionInfo";
3106 
3107         asyncResp->res.jsonValue["LogServices"]["@odata.id"] =
3108             "/redfish/v1/Systems/system/LogServices";
3109         asyncResp->res.jsonValue["Bios"]["@odata.id"] =
3110             "/redfish/v1/Systems/system/Bios";
3111 
3112         nlohmann::json::array_t managedBy;
3113         nlohmann::json& manager = managedBy.emplace_back();
3114         manager["@odata.id"] = "/redfish/v1/Managers/bmc";
3115         asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
3116         asyncResp->res.jsonValue["Status"]["Health"] = "OK";
3117         asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
3118 
3119         // Fill in SerialConsole info
3120         asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
3121         asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] =
3122             true;
3123 
3124         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] =
3125             true;
3126         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
3127         asyncResp->res
3128             .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
3129             "Press ~. to exit console";
3130         getPortStatusAndPath(std::span{protocolToDBusForSystems},
3131                              std::bind_front(afterPortRequest, asyncResp));
3132 
3133 #ifdef BMCWEB_ENABLE_KVM
3134         // Fill in GraphicalConsole info
3135         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
3136         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
3137             4;
3138         asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
3139             nlohmann::json::array_t({"KVMIP"});
3140 
3141 #endif // BMCWEB_ENABLE_KVM
3142 
3143         auto health = std::make_shared<HealthPopulate>(asyncResp);
3144         if constexpr (bmcwebEnableHealthPopulate)
3145         {
3146             constexpr std::array<std::string_view, 4> inventoryForSystems{
3147                 "xyz.openbmc_project.Inventory.Item.Dimm",
3148                 "xyz.openbmc_project.Inventory.Item.Cpu",
3149                 "xyz.openbmc_project.Inventory.Item.Drive",
3150                 "xyz.openbmc_project.Inventory.Item.StorageController"};
3151 
3152             dbus::utility::getSubTreePaths(
3153                 "/", 0, inventoryForSystems,
3154                 [health](const boost::system::error_code& ec,
3155                          const std::vector<std::string>& resp) {
3156                 if (ec)
3157                 {
3158                     // no inventory
3159                     return;
3160                 }
3161 
3162                 health->inventory = resp;
3163                 });
3164             health->populate();
3165         }
3166 
3167         getMainChassisId(asyncResp,
3168                          [](const std::string& chassisId,
3169                             const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3170             nlohmann::json::array_t chassisArray;
3171             nlohmann::json& chassis = chassisArray.emplace_back();
3172             chassis["@odata.id"] = boost::urls::format("/redfish/v1/Chassis/{}",
3173                                                        chassisId);
3174             aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
3175         });
3176 
3177         getLocationIndicatorActive(asyncResp);
3178         // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3179         getIndicatorLedState(asyncResp);
3180         getComputerSystem(asyncResp, health);
3181         getHostState(asyncResp);
3182         getBootProperties(asyncResp);
3183         getBootProgress(asyncResp);
3184         getBootProgressLastStateTime(asyncResp);
3185         pcie_util::getPCIeDeviceList(asyncResp, "PCIeDevices");
3186         getHostWatchdogTimer(asyncResp);
3187         getPowerRestorePolicy(asyncResp);
3188         getAutomaticRetryPolicy(asyncResp);
3189         getLastResetTime(asyncResp);
3190 #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE
3191         getProvisioningStatus(asyncResp);
3192 #endif
3193         getTrustedModuleRequiredToBoot(asyncResp);
3194         getPowerMode(asyncResp);
3195         getIdlePowerSaver(asyncResp);
3196         });
3197 
3198     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3199         .privileges(redfish::privileges::patchComputerSystem)
3200         .methods(boost::beast::http::verb::patch)(
3201             [&app](const crow::Request& req,
3202                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3203                    const std::string& systemName) {
3204         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3205         {
3206             return;
3207         }
3208         if (systemName != "system")
3209         {
3210             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3211                                        systemName);
3212             return;
3213         }
3214 
3215         asyncResp->res.addHeader(
3216             boost::beast::http::field::link,
3217             "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3218 
3219         std::optional<bool> locationIndicatorActive;
3220         std::optional<std::string> indicatorLed;
3221         std::optional<std::string> assetTag;
3222         std::optional<std::string> powerRestorePolicy;
3223         std::optional<std::string> powerMode;
3224         std::optional<bool> wdtEnable;
3225         std::optional<std::string> wdtTimeOutAction;
3226         std::optional<std::string> bootSource;
3227         std::optional<std::string> bootType;
3228         std::optional<std::string> bootEnable;
3229         std::optional<std::string> bootAutomaticRetry;
3230         std::optional<uint32_t> bootAutomaticRetryAttempts;
3231         std::optional<bool> bootTrustedModuleRequired;
3232         std::optional<bool> ipsEnable;
3233         std::optional<uint8_t> ipsEnterUtil;
3234         std::optional<uint64_t> ipsEnterTime;
3235         std::optional<uint8_t> ipsExitUtil;
3236         std::optional<uint64_t> ipsExitTime;
3237 
3238         // clang-format off
3239                 if (!json_util::readJsonPatch(
3240                         req, asyncResp->res,
3241                         "IndicatorLED", indicatorLed,
3242                         "LocationIndicatorActive", locationIndicatorActive,
3243                         "AssetTag", assetTag,
3244                         "PowerRestorePolicy", powerRestorePolicy,
3245                         "PowerMode", powerMode,
3246                         "HostWatchdogTimer/FunctionEnabled", wdtEnable,
3247                         "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
3248                         "Boot/BootSourceOverrideTarget", bootSource,
3249                         "Boot/BootSourceOverrideMode", bootType,
3250                         "Boot/BootSourceOverrideEnabled", bootEnable,
3251                         "Boot/AutomaticRetryConfig", bootAutomaticRetry,
3252                         "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts,
3253                         "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
3254                         "IdlePowerSaver/Enabled", ipsEnable,
3255                         "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
3256                         "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3257                         "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3258                         "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3259                 {
3260                     return;
3261                 }
3262         // clang-format on
3263 
3264         asyncResp->res.result(boost::beast::http::status::no_content);
3265 
3266         if (assetTag)
3267         {
3268             setAssetTag(asyncResp, *assetTag);
3269         }
3270 
3271         if (wdtEnable || wdtTimeOutAction)
3272         {
3273             setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3274         }
3275 
3276         if (bootSource || bootType || bootEnable)
3277         {
3278             setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3279         }
3280         if (bootAutomaticRetry)
3281         {
3282             setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3283         }
3284 
3285         if (bootAutomaticRetryAttempts)
3286         {
3287             setAutomaticRetryAttempts(asyncResp,
3288                                       bootAutomaticRetryAttempts.value());
3289         }
3290 
3291         if (bootTrustedModuleRequired)
3292         {
3293             setTrustedModuleRequiredToBoot(asyncResp,
3294                                            *bootTrustedModuleRequired);
3295         }
3296 
3297         if (locationIndicatorActive)
3298         {
3299             setLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3300         }
3301 
3302         // TODO (Gunnar): Remove IndicatorLED after enough time has
3303         // passed
3304         if (indicatorLed)
3305         {
3306             setIndicatorLedState(asyncResp, *indicatorLed);
3307             asyncResp->res.addHeader(boost::beast::http::field::warning,
3308                                      "299 - \"IndicatorLED is deprecated. Use "
3309                                      "LocationIndicatorActive instead.\"");
3310         }
3311 
3312         if (powerRestorePolicy)
3313         {
3314             setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3315         }
3316 
3317         if (powerMode)
3318         {
3319             setPowerMode(asyncResp, *powerMode);
3320         }
3321 
3322         if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil ||
3323             ipsExitTime)
3324         {
3325             setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3326                               ipsExitUtil, ipsExitTime);
3327         }
3328         });
3329 }
3330 
3331 inline void handleSystemCollectionResetActionHead(
3332     crow::App& app, const crow::Request& req,
3333     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
3334 {
3335     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3336     {
3337         return;
3338     }
3339     asyncResp->res.addHeader(
3340         boost::beast::http::field::link,
3341         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3342 }
3343 
3344 /**
3345  * SystemResetActionInfo derived class for delivering Computer Systems
3346  * ResetType AllowableValues using ResetInfo schema.
3347  */
3348 inline void requestRoutesSystemResetActionInfo(App& app)
3349 {
3350     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/")
3351         .privileges(redfish::privileges::headActionInfo)
3352         .methods(boost::beast::http::verb::head)(std::bind_front(
3353             handleSystemCollectionResetActionHead, std::ref(app)));
3354     /**
3355      * Functions triggers appropriate requests on DBus
3356      */
3357     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3358         .privileges(redfish::privileges::getActionInfo)
3359         .methods(boost::beast::http::verb::get)(
3360             [&app](const crow::Request& req,
3361                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3362                    const std::string& systemName) {
3363         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3364         {
3365             return;
3366         }
3367 
3368         if (systemName == "hypervisor")
3369         {
3370             handleHypervisorResetActionGet(asyncResp);
3371             return;
3372         }
3373 
3374         if (systemName != "system")
3375         {
3376             messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3377                                        systemName);
3378             return;
3379         }
3380 
3381         asyncResp->res.addHeader(
3382             boost::beast::http::field::link,
3383             "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3384 
3385         asyncResp->res.jsonValue["@odata.id"] =
3386             "/redfish/v1/Systems/system/ResetActionInfo";
3387         asyncResp->res.jsonValue["@odata.type"] =
3388             "#ActionInfo.v1_1_2.ActionInfo";
3389         asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3390         asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3391 
3392         nlohmann::json::array_t parameters;
3393         nlohmann::json::object_t parameter;
3394 
3395         parameter["Name"] = "ResetType";
3396         parameter["Required"] = true;
3397         parameter["DataType"] = "String";
3398         nlohmann::json::array_t allowableValues;
3399         allowableValues.emplace_back("On");
3400         allowableValues.emplace_back("ForceOff");
3401         allowableValues.emplace_back("ForceOn");
3402         allowableValues.emplace_back("ForceRestart");
3403         allowableValues.emplace_back("GracefulRestart");
3404         allowableValues.emplace_back("GracefulShutdown");
3405         allowableValues.emplace_back("PowerCycle");
3406         allowableValues.emplace_back("Nmi");
3407         parameter["AllowableValues"] = std::move(allowableValues);
3408         parameters.emplace_back(std::move(parameter));
3409 
3410         asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3411         });
3412 }
3413 } // namespace redfish
3414