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