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