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