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