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