xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision 8f1a35b9f9046b4c84a5002d0a16b93624a76f22)
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                 // Service not available, no error, just don't return
1000                 // Boot Override Source information
1001                 if (ec.value() != EBADR &&
1002                     ec.value() != boost::asio::error::host_unreachable)
1003                 {
1004                     BMCWEB_LOG_ERROR("D-Bus response error: {}", ec);
1005                     messages::internalError(asyncResp->res);
1006                 }
1007                 return;
1008             }
1009 
1010             BMCWEB_LOG_DEBUG("Boot source: {}", bootSourceStr);
1011 
1012             auto rfSource = dbusToRfBootSource(bootSourceStr);
1013             if (!rfSource.empty())
1014             {
1015                 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] =
1016                     rfSource;
1017             }
1018 
1019             // Get BootMode as BootSourceOverrideTarget is constructed
1020             // from both BootSource and BootMode
1021             getBootOverrideMode(asyncResp);
1022         });
1023 }
1024 
1025 /**
1026  * @brief This functions abstracts all the logic behind getting a
1027  * "BootSourceOverrideEnabled" property from an overall boot override enable
1028  * state
1029  *
1030  * @param[in] asyncResp     Shared pointer for generating response message.
1031  *
1032  * @return None.
1033  */
1034 
processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool bootOverrideEnableSetting)1035 inline void processBootOverrideEnable(
1036     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1037     const bool bootOverrideEnableSetting)
1038 {
1039     if (!bootOverrideEnableSetting)
1040     {
1041         asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1042             "Disabled";
1043         return;
1044     }
1045 
1046     // If boot source override is enabled, we need to check 'one_time'
1047     // property to set a correct value for the "BootSourceOverrideEnabled"
1048     dbus::utility::getProperty<bool>(
1049         "xyz.openbmc_project.Settings",
1050         "/xyz/openbmc_project/control/host0/boot/one_time",
1051         "xyz.openbmc_project.Object.Enable", "Enabled",
1052         [asyncResp](const boost::system::error_code& ec, bool oneTimeSetting) {
1053             if (ec)
1054             {
1055                 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1056                 messages::internalError(asyncResp->res);
1057                 return;
1058             }
1059 
1060             if (oneTimeSetting)
1061             {
1062                 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1063                     "Once";
1064             }
1065             else
1066             {
1067                 asyncResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] =
1068                     "Continuous";
1069             }
1070         });
1071 }
1072 
1073 /**
1074  * @brief Retrieves boot override enable over DBUS
1075  *
1076  * @param[in] asyncResp     Shared pointer for generating response message.
1077  *
1078  * @return None.
1079  */
1080 
getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1081 inline void getBootOverrideEnable(
1082     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1083 {
1084     dbus::utility::getProperty<bool>(
1085         "xyz.openbmc_project.Settings",
1086         "/xyz/openbmc_project/control/host0/boot",
1087         "xyz.openbmc_project.Object.Enable", "Enabled",
1088         [asyncResp](const boost::system::error_code& ec,
1089                     const bool bootOverrideEnable) {
1090             if (ec)
1091             {
1092                 // Service not available, no error, just don't return
1093                 // Boot Override Enable information
1094                 if (ec.value() != EBADR &&
1095                     ec.value() != boost::asio::error::host_unreachable)
1096                 {
1097                     BMCWEB_LOG_ERROR("D-Bus response error: {}", ec);
1098                     messages::internalError(asyncResp->res);
1099                 }
1100                 return;
1101             }
1102 
1103             processBootOverrideEnable(asyncResp, bootOverrideEnable);
1104         });
1105 }
1106 
1107 /**
1108  * @brief Retrieves boot source override properties
1109  *
1110  * @param[in] asyncResp     Shared pointer for generating response message.
1111  *
1112  * @return None.
1113  */
getBootProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1114 inline void getBootProperties(
1115     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1116 {
1117     BMCWEB_LOG_DEBUG("Get boot information.");
1118 
1119     getBootOverrideSource(asyncResp);
1120     getBootOverrideType(asyncResp);
1121     getBootOverrideEnable(asyncResp);
1122 }
1123 
1124 /**
1125  * @brief Retrieves the Last Reset Time
1126  *
1127  * "Reset" is an overloaded term in Redfish, "Reset" includes power on
1128  * and power off. Even though this is the "system" Redfish object look at the
1129  * chassis D-Bus interface for the LastStateChangeTime since this has the
1130  * last power operation time.
1131  *
1132  * @param[in] asyncResp     Shared pointer for generating response message.
1133  *
1134  * @return None.
1135  */
getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1136 inline void getLastResetTime(
1137     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1138 {
1139     BMCWEB_LOG_DEBUG("Getting System Last Reset Time");
1140 
1141     dbus::utility::getProperty<uint64_t>(
1142         "xyz.openbmc_project.State.Chassis",
1143         "/xyz/openbmc_project/state/chassis0",
1144         "xyz.openbmc_project.State.Chassis", "LastStateChangeTime",
1145         [asyncResp](const boost::system::error_code& ec,
1146                     uint64_t lastResetTime) {
1147             if (ec)
1148             {
1149                 BMCWEB_LOG_DEBUG("D-BUS response error {}", ec);
1150                 return;
1151             }
1152 
1153             // LastStateChangeTime is epoch time, in milliseconds
1154             // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19
1155             uint64_t lastResetTimeStamp = lastResetTime / 1000;
1156 
1157             // Convert to ISO 8601 standard
1158             asyncResp->res.jsonValue["LastResetTime"] =
1159                 redfish::time_utils::getDateTimeUint(lastResetTimeStamp);
1160         });
1161 }
1162 
1163 /**
1164  * @brief Retrieves the number of automatic boot Retry attempts allowed/left.
1165  *
1166  * The total number of automatic reboot retries allowed "RetryAttempts" and its
1167  * corresponding property "AttemptsLeft" that keeps track of the amount of
1168  * automatic retry attempts left are hosted in phosphor-state-manager through
1169  * dbus.
1170  *
1171  * @param[in] asyncResp     Shared pointer for generating response message.
1172  *
1173  * @return None.
1174  */
getAutomaticRebootAttempts(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1175 inline void getAutomaticRebootAttempts(
1176     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1177 {
1178     BMCWEB_LOG_DEBUG("Get Automatic Retry policy");
1179 
1180     dbus::utility::getAllProperties(
1181         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
1182         "xyz.openbmc_project.Control.Boot.RebootAttempts",
1183         [asyncResp{asyncResp}](
1184             const boost::system::error_code& ec,
1185             const dbus::utility::DBusPropertiesMap& propertiesList) {
1186             if (ec)
1187             {
1188                 if (ec.value() != EBADR &&
1189                     ec.value() != boost::asio::error::host_unreachable)
1190                 {
1191                     // Service not available, no error, just don't return
1192                     // RebootAttempts information
1193                     BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
1194                     messages::internalError(asyncResp->res);
1195                 }
1196                 return;
1197             }
1198 
1199             const uint32_t* attemptsLeft = nullptr;
1200             const uint32_t* retryAttempts = nullptr;
1201 
1202             const bool success = sdbusplus::unpackPropertiesNoThrow(
1203                 dbus_utils::UnpackErrorPrinter(), propertiesList,
1204                 "AttemptsLeft", attemptsLeft, "RetryAttempts", retryAttempts);
1205 
1206             if (!success)
1207             {
1208                 messages::internalError(asyncResp->res);
1209                 return;
1210             }
1211 
1212             if (attemptsLeft != nullptr)
1213             {
1214                 asyncResp->res
1215                     .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] =
1216                     *attemptsLeft;
1217             }
1218 
1219             if (retryAttempts != nullptr)
1220             {
1221                 asyncResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] =
1222                     *retryAttempts;
1223             }
1224         });
1225 }
1226 
1227 /**
1228  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot.
1229  *
1230  * @param[in] asyncResp     Shared pointer for generating response message.
1231  *
1232  * @return None.
1233  */
getAutomaticRetryPolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1234 inline void getAutomaticRetryPolicy(
1235     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1236 {
1237     BMCWEB_LOG_DEBUG("Get Automatic Retry policy");
1238 
1239     dbus::utility::getProperty<bool>(
1240         "xyz.openbmc_project.Settings",
1241         "/xyz/openbmc_project/control/host0/auto_reboot",
1242         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot",
1243         [asyncResp](const boost::system::error_code& ec,
1244                     bool autoRebootEnabled) {
1245             if (ec)
1246             {
1247                 // Service not available, no error, just don't return
1248                 // AutoReboot information
1249                 if (ec.value() != EBADR &&
1250                     ec.value() != boost::asio::error::host_unreachable)
1251                 {
1252                     BMCWEB_LOG_ERROR("D-Bus responses error: {}", ec);
1253                     messages::internalError(asyncResp->res);
1254                 }
1255                 return;
1256             }
1257 
1258             BMCWEB_LOG_DEBUG("Auto Reboot: {}", autoRebootEnabled);
1259             if (autoRebootEnabled)
1260             {
1261                 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1262                     "RetryAttempts";
1263             }
1264             else
1265             {
1266                 asyncResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] =
1267                     "Disabled";
1268             }
1269             getAutomaticRebootAttempts(asyncResp);
1270 
1271             // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways,
1272             // and RetryAttempts. OpenBMC only supports Disabled and
1273             // RetryAttempts.
1274             nlohmann::json::array_t allowed;
1275             allowed.emplace_back("Disabled");
1276             allowed.emplace_back("RetryAttempts");
1277             asyncResp->res
1278                 .jsonValue["Boot"]
1279                           ["AutomaticRetryConfig@Redfish.AllowableValues"] =
1280                 std::move(allowed);
1281         });
1282 }
1283 
1284 /**
1285  * @brief Sets RetryAttempts
1286  *
1287  * @param[in] asyncResp   Shared pointer for generating response message.
1288  * @param[in] retryAttempts  "AutomaticRetryAttempts" from request.
1289  *
1290  *@return None.
1291  */
1292 
setAutomaticRetryAttempts(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const uint32_t retryAttempts)1293 inline void setAutomaticRetryAttempts(
1294     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1295     const uint32_t retryAttempts)
1296 {
1297     BMCWEB_LOG_DEBUG("Set Automatic Retry Attempts.");
1298     setDbusProperty(
1299         asyncResp, "Boot/AutomaticRetryAttempts",
1300         "xyz.openbmc_project.State.Host",
1301         sdbusplus::message::object_path("/xyz/openbmc_project/state/host0"),
1302         "xyz.openbmc_project.Control.Boot.RebootAttempts", "RetryAttempts",
1303         retryAttempts);
1304 }
1305 
1306 inline computer_system::PowerRestorePolicyTypes
redfishPowerRestorePolicyFromDbus(std::string_view value)1307     redfishPowerRestorePolicyFromDbus(std::string_view value)
1308 {
1309     if (value ==
1310         "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn")
1311     {
1312         return computer_system::PowerRestorePolicyTypes::AlwaysOn;
1313     }
1314     if (value ==
1315         "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff")
1316     {
1317         return computer_system::PowerRestorePolicyTypes::AlwaysOff;
1318     }
1319     if (value ==
1320         "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore")
1321     {
1322         return computer_system::PowerRestorePolicyTypes::LastState;
1323     }
1324     if (value == "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None")
1325     {
1326         return computer_system::PowerRestorePolicyTypes::AlwaysOff;
1327     }
1328     return computer_system::PowerRestorePolicyTypes::Invalid;
1329 }
1330 /**
1331  * @brief Retrieves power restore policy over DBUS.
1332  *
1333  * @param[in] asyncResp     Shared pointer for generating response message.
1334  *
1335  * @return None.
1336  */
getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1337 inline void getPowerRestorePolicy(
1338     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1339 {
1340     BMCWEB_LOG_DEBUG("Get power restore policy");
1341 
1342     dbus::utility::getProperty<std::string>(
1343         "xyz.openbmc_project.Settings",
1344         "/xyz/openbmc_project/control/host0/power_restore_policy",
1345         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1346         [asyncResp](const boost::system::error_code& ec,
1347                     const std::string& policy) {
1348             if (ec)
1349             {
1350                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
1351                 return;
1352             }
1353             computer_system::PowerRestorePolicyTypes restore =
1354                 redfishPowerRestorePolicyFromDbus(policy);
1355             if (restore == computer_system::PowerRestorePolicyTypes::Invalid)
1356             {
1357                 messages::internalError(asyncResp->res);
1358                 return;
1359             }
1360 
1361             asyncResp->res.jsonValue["PowerRestorePolicy"] = restore;
1362         });
1363 }
1364 
1365 /**
1366  * @brief Stop Boot On Fault over DBUS.
1367  *
1368  * @param[in] asyncResp     Shared pointer for generating response message.
1369  *
1370  * @return None.
1371  */
getStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1372 inline void getStopBootOnFault(
1373     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1374 {
1375     BMCWEB_LOG_DEBUG("Get Stop Boot On Fault");
1376 
1377     dbus::utility::getProperty<bool>(
1378         "xyz.openbmc_project.Settings", "/xyz/openbmc_project/logging/settings",
1379         "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError",
1380         [asyncResp](const boost::system::error_code& ec, bool value) {
1381             if (ec)
1382             {
1383                 // Service not available, no error, just don't return
1384                 // StopBootOnFault information
1385                 if (ec.value() != EBADR ||
1386                     ec.value() != boost::asio::error::host_unreachable)
1387                 {
1388                     BMCWEB_LOG_ERROR("DBUS response error {}", ec);
1389                     messages::internalError(asyncResp->res);
1390                 }
1391                 return;
1392             }
1393 
1394             if (value)
1395             {
1396                 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] =
1397                     computer_system::StopBootOnFault::AnyFault;
1398             }
1399             else
1400             {
1401                 asyncResp->res.jsonValue["Boot"]["StopBootOnFault"] =
1402                     computer_system::StopBootOnFault::Never;
1403             }
1404         });
1405 }
1406 
1407 /**
1408  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not
1409  * TPM is required for booting the host.
1410  *
1411  * @param[in] asyncResp     Shared pointer for generating response message.
1412  *
1413  * @return None.
1414  */
getTrustedModuleRequiredToBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1415 inline void getTrustedModuleRequiredToBoot(
1416     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1417 {
1418     BMCWEB_LOG_DEBUG("Get TPM required to boot.");
1419     constexpr std::array<std::string_view, 1> interfaces = {
1420         "xyz.openbmc_project.Control.TPM.Policy"};
1421     dbus::utility::getSubTree(
1422         "/", 0, interfaces,
1423         [asyncResp](const boost::system::error_code& ec,
1424                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
1425             if (ec)
1426             {
1427                 BMCWEB_LOG_DEBUG(
1428                     "DBUS response error on TPM.Policy GetSubTree{}", ec);
1429                 // This is an optional D-Bus object so just return if
1430                 // error occurs
1431                 return;
1432             }
1433             if (subtree.empty())
1434             {
1435                 // As noted above, this is an optional interface so just return
1436                 // if there is no instance found
1437                 return;
1438             }
1439 
1440             /* When there is more than one TPMEnable object... */
1441             if (subtree.size() > 1)
1442             {
1443                 BMCWEB_LOG_DEBUG(
1444                     "DBUS response has more than 1 TPM Enable object:{}",
1445                     subtree.size());
1446                 // Throw an internal Error and return
1447                 messages::internalError(asyncResp->res);
1448                 return;
1449             }
1450 
1451             // Make sure the Dbus response map has a service and objectPath
1452             // field
1453             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1454             {
1455                 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!");
1456                 messages::internalError(asyncResp->res);
1457                 return;
1458             }
1459 
1460             const std::string& path = subtree[0].first;
1461             const std::string& serv = subtree[0].second.begin()->first;
1462 
1463             // Valid TPM Enable object found, now reading the current value
1464             dbus::utility::getProperty<bool>(
1465                 serv, path, "xyz.openbmc_project.Control.TPM.Policy",
1466                 "TPMEnable",
1467                 [asyncResp](const boost::system::error_code& ec2,
1468                             bool tpmRequired) {
1469                     if (ec2)
1470                     {
1471                         BMCWEB_LOG_ERROR(
1472                             "D-BUS response error on TPM.Policy Get{}", ec2);
1473                         messages::internalError(asyncResp->res);
1474                         return;
1475                     }
1476 
1477                     if (tpmRequired)
1478                     {
1479                         asyncResp->res
1480                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1481                             "Required";
1482                     }
1483                     else
1484                     {
1485                         asyncResp->res
1486                             .jsonValue["Boot"]["TrustedModuleRequiredToBoot"] =
1487                             "Disabled";
1488                     }
1489                 });
1490         });
1491 }
1492 
1493 /**
1494  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not
1495  * TPM is required for booting the host.
1496  *
1497  * @param[in] asyncResp     Shared pointer for generating response message.
1498  * @param[in] tpmRequired   Value to set TPM Required To Boot property to.
1499  *
1500  * @return None.
1501  */
setTrustedModuleRequiredToBoot(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const bool tpmRequired)1502 inline void setTrustedModuleRequiredToBoot(
1503     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const bool tpmRequired)
1504 {
1505     BMCWEB_LOG_DEBUG("Set TrustedModuleRequiredToBoot.");
1506     constexpr std::array<std::string_view, 1> interfaces = {
1507         "xyz.openbmc_project.Control.TPM.Policy"};
1508     dbus::utility::getSubTree(
1509         "/", 0, interfaces,
1510         [asyncResp,
1511          tpmRequired](const boost::system::error_code& ec,
1512                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
1513             if (ec)
1514             {
1515                 BMCWEB_LOG_ERROR(
1516                     "DBUS response error on TPM.Policy GetSubTree{}", ec);
1517                 messages::internalError(asyncResp->res);
1518                 return;
1519             }
1520             if (subtree.empty())
1521             {
1522                 messages::propertyValueNotInList(asyncResp->res,
1523                                                  "ComputerSystem",
1524                                                  "TrustedModuleRequiredToBoot");
1525                 return;
1526             }
1527 
1528             /* When there is more than one TPMEnable object... */
1529             if (subtree.size() > 1)
1530             {
1531                 BMCWEB_LOG_DEBUG(
1532                     "DBUS response has more than 1 TPM Enable object:{}",
1533                     subtree.size());
1534                 // Throw an internal Error and return
1535                 messages::internalError(asyncResp->res);
1536                 return;
1537             }
1538 
1539             // Make sure the Dbus response map has a service and objectPath
1540             // field
1541             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1542             {
1543                 BMCWEB_LOG_DEBUG("TPM.Policy mapper error!");
1544                 messages::internalError(asyncResp->res);
1545                 return;
1546             }
1547 
1548             const std::string& path = subtree[0].first;
1549             const std::string& serv = subtree[0].second.begin()->first;
1550 
1551             if (serv.empty())
1552             {
1553                 BMCWEB_LOG_DEBUG("TPM.Policy service mapper error!");
1554                 messages::internalError(asyncResp->res);
1555                 return;
1556             }
1557 
1558             // Valid TPM Enable object found, now setting the value
1559             setDbusProperty(asyncResp, "Boot/TrustedModuleRequiredToBoot", serv,
1560                             path, "xyz.openbmc_project.Control.TPM.Policy",
1561                             "TPMEnable", tpmRequired);
1562         });
1563 }
1564 
1565 /**
1566  * @brief Sets boot properties into DBUS object(s).
1567  *
1568  * @param[in] asyncResp       Shared pointer for generating response message.
1569  * @param[in] bootType        The boot type to set.
1570  * @return Integer error code.
1571  */
setBootType(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootType)1572 inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1573                         const std::optional<std::string>& bootType)
1574 {
1575     std::string bootTypeStr;
1576 
1577     if (!bootType)
1578     {
1579         return;
1580     }
1581 
1582     // Source target specified
1583     BMCWEB_LOG_DEBUG("Boot type: {}", *bootType);
1584     // Figure out which DBUS interface and property to use
1585     if (*bootType == "Legacy")
1586     {
1587         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy";
1588     }
1589     else if (*bootType == "UEFI")
1590     {
1591         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI";
1592     }
1593     else
1594     {
1595         BMCWEB_LOG_DEBUG("Invalid property value for "
1596                          "BootSourceOverrideMode: {}",
1597                          *bootType);
1598         messages::propertyValueNotInList(asyncResp->res, *bootType,
1599                                          "BootSourceOverrideMode");
1600         return;
1601     }
1602 
1603     // Act on validated parameters
1604     BMCWEB_LOG_DEBUG("DBUS boot type: {}", bootTypeStr);
1605 
1606     setDbusProperty(asyncResp, "Boot/BootSourceOverrideMode",
1607                     "xyz.openbmc_project.Settings",
1608                     sdbusplus::message::object_path(
1609                         "/xyz/openbmc_project/control/host0/boot"),
1610                     "xyz.openbmc_project.Control.Boot.Type", "BootType",
1611                     bootTypeStr);
1612 }
1613 
1614 /**
1615  * @brief Sets boot properties into DBUS object(s).
1616  *
1617  * @param[in] asyncResp           Shared pointer for generating response
1618  * message.
1619  * @param[in] bootType        The boot type to set.
1620  * @return Integer error code.
1621  */
setBootEnable(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootEnable)1622 inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1623                           const std::optional<std::string>& bootEnable)
1624 {
1625     if (!bootEnable)
1626     {
1627         return;
1628     }
1629     // Source target specified
1630     BMCWEB_LOG_DEBUG("Boot enable: {}", *bootEnable);
1631 
1632     bool bootOverrideEnable = false;
1633     bool bootOverridePersistent = false;
1634     // Figure out which DBUS interface and property to use
1635     if (*bootEnable == "Disabled")
1636     {
1637         bootOverrideEnable = false;
1638     }
1639     else if (*bootEnable == "Once")
1640     {
1641         bootOverrideEnable = true;
1642         bootOverridePersistent = false;
1643     }
1644     else if (*bootEnable == "Continuous")
1645     {
1646         bootOverrideEnable = true;
1647         bootOverridePersistent = true;
1648     }
1649     else
1650     {
1651         BMCWEB_LOG_DEBUG(
1652             "Invalid property value for BootSourceOverrideEnabled: {}",
1653             *bootEnable);
1654         messages::propertyValueNotInList(asyncResp->res, *bootEnable,
1655                                          "BootSourceOverrideEnabled");
1656         return;
1657     }
1658 
1659     // Act on validated parameters
1660     BMCWEB_LOG_DEBUG("DBUS boot override enable: {}", bootOverrideEnable);
1661 
1662     setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled",
1663                     "xyz.openbmc_project.Settings",
1664                     sdbusplus::message::object_path(
1665                         "/xyz/openbmc_project/control/host0/boot"),
1666                     "xyz.openbmc_project.Object.Enable", "Enabled",
1667                     bootOverrideEnable);
1668 
1669     if (!bootOverrideEnable)
1670     {
1671         return;
1672     }
1673 
1674     // In case boot override is enabled we need to set correct value for the
1675     // 'one_time' enable DBus interface
1676     BMCWEB_LOG_DEBUG("DBUS boot override persistent: {}",
1677                      bootOverridePersistent);
1678 
1679     setDbusProperty(asyncResp, "Boot/BootSourceOverrideEnabled",
1680                     "xyz.openbmc_project.Settings",
1681                     sdbusplus::message::object_path(
1682                         "/xyz/openbmc_project/control/host0/boot/one_time"),
1683                     "xyz.openbmc_project.Object.Enable", "Enabled",
1684                     !bootOverridePersistent);
1685 }
1686 
1687 /**
1688  * @brief Sets boot properties into DBUS object(s).
1689  *
1690  * @param[in] asyncResp       Shared pointer for generating response message.
1691  * @param[in] bootSource      The boot source to set.
1692  *
1693  * @return Integer error code.
1694  */
setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<std::string> & bootSource)1695 inline void setBootModeOrSource(
1696     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1697     const std::optional<std::string>& bootSource)
1698 {
1699     std::string bootSourceStr;
1700     std::string bootModeStr;
1701 
1702     if (!bootSource)
1703     {
1704         return;
1705     }
1706 
1707     // Source target specified
1708     BMCWEB_LOG_DEBUG("Boot source: {}", *bootSource);
1709     // Figure out which DBUS interface and property to use
1710     if (assignBootParameters(asyncResp, *bootSource, bootSourceStr,
1711                              bootModeStr) != 0)
1712     {
1713         BMCWEB_LOG_DEBUG(
1714             "Invalid property value for BootSourceOverrideTarget: {}",
1715             *bootSource);
1716         messages::propertyValueNotInList(asyncResp->res, *bootSource,
1717                                          "BootSourceTargetOverride");
1718         return;
1719     }
1720 
1721     // Act on validated parameters
1722     BMCWEB_LOG_DEBUG("DBUS boot source: {}", bootSourceStr);
1723     BMCWEB_LOG_DEBUG("DBUS boot mode: {}", bootModeStr);
1724 
1725     setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget",
1726                     "xyz.openbmc_project.Settings",
1727                     sdbusplus::message::object_path(
1728                         "/xyz/openbmc_project/control/host0/boot"),
1729                     "xyz.openbmc_project.Control.Boot.Source", "BootSource",
1730                     bootSourceStr);
1731     setDbusProperty(asyncResp, "Boot/BootSourceOverrideTarget",
1732                     "xyz.openbmc_project.Settings",
1733                     sdbusplus::message::object_path(
1734                         "/xyz/openbmc_project/control/host0/boot"),
1735                     "xyz.openbmc_project.Control.Boot.Mode", "BootMode",
1736                     bootModeStr);
1737 }
1738 
1739 /**
1740  * @brief Sets Boot source override properties.
1741  *
1742  * @param[in] asyncResp  Shared pointer for generating response message.
1743  * @param[in] bootSource The boot source from incoming RF request.
1744  * @param[in] bootType   The boot type from incoming RF request.
1745  * @param[in] bootEnable The boot override enable from incoming RF request.
1746  *
1747  * @return Integer error code.
1748  */
1749 
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)1750 inline void setBootProperties(
1751     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1752     const std::optional<std::string>& bootSource,
1753     const std::optional<std::string>& bootType,
1754     const std::optional<std::string>& bootEnable)
1755 {
1756     BMCWEB_LOG_DEBUG("Set boot information.");
1757 
1758     setBootModeOrSource(asyncResp, bootSource);
1759     setBootType(asyncResp, bootType);
1760     setBootEnable(asyncResp, bootEnable);
1761 }
1762 
1763 /**
1764  * @brief Sets AssetTag
1765  *
1766  * @param[in] asyncResp Shared pointer for generating response message.
1767  * @param[in] assetTag  "AssetTag" from request.
1768  *
1769  * @return None.
1770  */
setAssetTag(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & assetTag)1771 inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1772                         const std::string& assetTag)
1773 {
1774     constexpr std::array<std::string_view, 1> interfaces = {
1775         "xyz.openbmc_project.Inventory.Item.System"};
1776     dbus::utility::getSubTree(
1777         "/xyz/openbmc_project/inventory", 0, interfaces,
1778         [asyncResp,
1779          assetTag](const boost::system::error_code& ec,
1780                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
1781             if (ec)
1782             {
1783                 BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec);
1784                 messages::internalError(asyncResp->res);
1785                 return;
1786             }
1787             if (subtree.empty())
1788             {
1789                 BMCWEB_LOG_DEBUG("Can't find system D-Bus object!");
1790                 messages::internalError(asyncResp->res);
1791                 return;
1792             }
1793             // Assume only 1 system D-Bus object
1794             // Throw an error if there is more than 1
1795             if (subtree.size() > 1)
1796             {
1797                 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus object!");
1798                 messages::internalError(asyncResp->res);
1799                 return;
1800             }
1801             if (subtree[0].first.empty() || subtree[0].second.size() != 1)
1802             {
1803                 BMCWEB_LOG_DEBUG("Asset Tag Set mapper error!");
1804                 messages::internalError(asyncResp->res);
1805                 return;
1806             }
1807 
1808             const std::string& path = subtree[0].first;
1809             const std::string& service = subtree[0].second.begin()->first;
1810 
1811             if (service.empty())
1812             {
1813                 BMCWEB_LOG_DEBUG("Asset Tag Set service mapper error!");
1814                 messages::internalError(asyncResp->res);
1815                 return;
1816             }
1817 
1818             setDbusProperty(asyncResp, "AssetTag", service, path,
1819                             "xyz.openbmc_project.Inventory.Decorator.AssetTag",
1820                             "AssetTag", assetTag);
1821         });
1822 }
1823 
1824 /**
1825  * @brief Validate the specified stopBootOnFault is valid and return the
1826  * stopBootOnFault name associated with that string
1827  *
1828  * @param[in] stopBootOnFaultString  String representing the desired
1829  * stopBootOnFault
1830  *
1831  * @return stopBootOnFault value or empty  if incoming value is not valid
1832  */
validstopBootOnFault(const std::string & stopBootOnFaultString)1833 inline std::optional<bool> validstopBootOnFault(
1834     const std::string& stopBootOnFaultString)
1835 {
1836     if (stopBootOnFaultString == "AnyFault")
1837     {
1838         return true;
1839     }
1840 
1841     if (stopBootOnFaultString == "Never")
1842     {
1843         return false;
1844     }
1845 
1846     return std::nullopt;
1847 }
1848 
1849 /**
1850  * @brief Sets stopBootOnFault
1851  *
1852  * @param[in] asyncResp   Shared pointer for generating response message.
1853  * @param[in] stopBootOnFault  "StopBootOnFault" from request.
1854  *
1855  * @return None.
1856  */
setStopBootOnFault(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & stopBootOnFault)1857 inline void setStopBootOnFault(
1858     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1859     const std::string& stopBootOnFault)
1860 {
1861     BMCWEB_LOG_DEBUG("Set Stop Boot On Fault.");
1862 
1863     std::optional<bool> stopBootEnabled = validstopBootOnFault(stopBootOnFault);
1864     if (!stopBootEnabled)
1865     {
1866         BMCWEB_LOG_DEBUG("Invalid property value for StopBootOnFault: {}",
1867                          stopBootOnFault);
1868         messages::propertyValueNotInList(asyncResp->res, stopBootOnFault,
1869                                          "StopBootOnFault");
1870         return;
1871     }
1872 
1873     setDbusProperty(asyncResp, "Boot/StopBootOnFault",
1874                     "xyz.openbmc_project.Settings",
1875                     sdbusplus::message::object_path(
1876                         "/xyz/openbmc_project/logging/settings"),
1877                     "xyz.openbmc_project.Logging.Settings", "QuiesceOnHwError",
1878                     *stopBootEnabled);
1879 }
1880 
1881 /**
1882  * @brief Sets automaticRetry (Auto Reboot)
1883  *
1884  * @param[in] asyncResp   Shared pointer for generating response message.
1885  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request.
1886  *
1887  * @return None.
1888  */
setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & automaticRetryConfig)1889 inline void setAutomaticRetry(
1890     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1891     const std::string& automaticRetryConfig)
1892 {
1893     BMCWEB_LOG_DEBUG("Set Automatic Retry.");
1894 
1895     // OpenBMC only supports "Disabled" and "RetryAttempts".
1896     bool autoRebootEnabled = false;
1897 
1898     if (automaticRetryConfig == "Disabled")
1899     {
1900         autoRebootEnabled = false;
1901     }
1902     else if (automaticRetryConfig == "RetryAttempts")
1903     {
1904         autoRebootEnabled = true;
1905     }
1906     else
1907     {
1908         BMCWEB_LOG_DEBUG("Invalid property value for AutomaticRetryConfig: {}",
1909                          automaticRetryConfig);
1910         messages::propertyValueNotInList(asyncResp->res, automaticRetryConfig,
1911                                          "AutomaticRetryConfig");
1912         return;
1913     }
1914 
1915     setDbusProperty(asyncResp, "Boot/AutomaticRetryConfig",
1916                     "xyz.openbmc_project.Settings",
1917                     sdbusplus::message::object_path(
1918                         "/xyz/openbmc_project/control/host0/auto_reboot"),
1919                     "xyz.openbmc_project.Control.Boot.RebootPolicy",
1920                     "AutoReboot", autoRebootEnabled);
1921 }
1922 
dbusPowerRestorePolicyFromRedfish(std::string_view policy)1923 inline std::string dbusPowerRestorePolicyFromRedfish(std::string_view policy)
1924 {
1925     if (policy == "AlwaysOn")
1926     {
1927         return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn";
1928     }
1929     if (policy == "AlwaysOff")
1930     {
1931         return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff";
1932     }
1933     if (policy == "LastState")
1934     {
1935         return "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore";
1936     }
1937     return "";
1938 }
1939 
1940 /**
1941  * @brief Sets power restore policy properties.
1942  *
1943  * @param[in] asyncResp   Shared pointer for generating response message.
1944  * @param[in] policy  power restore policy properties from request.
1945  *
1946  * @return None.
1947  */
setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view policy)1948 inline void setPowerRestorePolicy(
1949     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1950     std::string_view policy)
1951 {
1952     BMCWEB_LOG_DEBUG("Set power restore policy.");
1953 
1954     std::string powerRestorePolicy = dbusPowerRestorePolicyFromRedfish(policy);
1955 
1956     if (powerRestorePolicy.empty())
1957     {
1958         messages::propertyValueNotInList(asyncResp->res, policy,
1959                                          "PowerRestorePolicy");
1960         return;
1961     }
1962 
1963     setDbusProperty(
1964         asyncResp, "PowerRestorePolicy", "xyz.openbmc_project.Settings",
1965         sdbusplus::message::object_path(
1966             "/xyz/openbmc_project/control/host0/power_restore_policy"),
1967         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy",
1968         powerRestorePolicy);
1969 }
1970 
1971 /**
1972  * @brief Retrieves provisioning status
1973  *
1974  * @param[in] asyncResp     Shared pointer for completing asynchronous
1975  * calls.
1976  *
1977  * @return None.
1978  */
getProvisioningStatus(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1979 inline void getProvisioningStatus(
1980     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1981 {
1982     BMCWEB_LOG_DEBUG("Get OEM information.");
1983     dbus::utility::getAllProperties(
1984         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr",
1985         "xyz.openbmc_project.PFR.Attributes",
1986         [asyncResp](const boost::system::error_code& ec,
1987                     const dbus::utility::DBusPropertiesMap& propertiesList) {
1988             nlohmann::json& oemPFR =
1989                 asyncResp->res
1990                     .jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"];
1991             asyncResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] =
1992                 "#OpenBMCComputerSystem.v1_0_0.OpenBmc";
1993             oemPFR["@odata.type"] =
1994                 "#OpenBMCComputerSystem.FirmwareProvisioning";
1995 
1996             if (ec)
1997             {
1998                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
1999                 // not an error, don't have to have the interface
2000                 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2001                     FirmwareProvisioningStatus::NotProvisioned;
2002                 return;
2003             }
2004 
2005             const bool* provState = nullptr;
2006             const bool* lockState = nullptr;
2007 
2008             const bool success = sdbusplus::unpackPropertiesNoThrow(
2009                 dbus_utils::UnpackErrorPrinter(), propertiesList,
2010                 "UfmProvisioned", provState, "UfmLocked", lockState);
2011 
2012             if (!success)
2013             {
2014                 messages::internalError(asyncResp->res);
2015                 return;
2016             }
2017 
2018             if ((provState == nullptr) || (lockState == nullptr))
2019             {
2020                 BMCWEB_LOG_DEBUG("Unable to get PFR attributes.");
2021                 messages::internalError(asyncResp->res);
2022                 return;
2023             }
2024 
2025             if (*provState)
2026             {
2027                 if (*lockState)
2028                 {
2029                     oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2030                         FirmwareProvisioningStatus::ProvisionedAndLocked;
2031                 }
2032                 else
2033                 {
2034                     oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2035                         FirmwareProvisioningStatus::ProvisionedButNotLocked;
2036                 }
2037             }
2038             else
2039             {
2040                 oemPFR["ProvisioningStatus"] = open_bmc_computer_system::
2041                     FirmwareProvisioningStatus::NotProvisioned;
2042             }
2043         });
2044 }
2045 
2046 /**
2047  * @brief Translate the PowerMode string to enum value
2048  *
2049  * @param[in]  modeString PowerMode string to be translated
2050  *
2051  * @return PowerMode enum
2052  */
translatePowerModeString(const std::string & modeString)2053 inline computer_system::PowerMode translatePowerModeString(
2054     const std::string& modeString)
2055 {
2056     using PowerMode = computer_system::PowerMode;
2057 
2058     if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static")
2059     {
2060         return PowerMode::Static;
2061     }
2062     if (modeString ==
2063         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance")
2064     {
2065         return PowerMode::MaximumPerformance;
2066     }
2067     if (modeString ==
2068         "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving")
2069     {
2070         return PowerMode::PowerSaving;
2071     }
2072     if (modeString ==
2073         "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance")
2074     {
2075         return PowerMode::BalancedPerformance;
2076     }
2077     if (modeString ==
2078         "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance")
2079     {
2080         return PowerMode::EfficiencyFavorPerformance;
2081     }
2082     if (modeString ==
2083         "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower")
2084     {
2085         return PowerMode::EfficiencyFavorPower;
2086     }
2087     if (modeString == "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM")
2088     {
2089         return PowerMode::OEM;
2090     }
2091     // Any other values would be invalid
2092     BMCWEB_LOG_ERROR("PowerMode value was not valid: {}", modeString);
2093     return PowerMode::Invalid;
2094 }
2095 
afterGetPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const dbus::utility::DBusPropertiesMap & properties)2096 inline void afterGetPowerMode(
2097     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2098     const boost::system::error_code& ec,
2099     const dbus::utility::DBusPropertiesMap& properties)
2100 {
2101     if (ec)
2102     {
2103         BMCWEB_LOG_ERROR("DBUS response error on PowerMode GetAll: {}", ec);
2104         messages::internalError(asyncResp->res);
2105         return;
2106     }
2107 
2108     std::string powerMode;
2109     const std::vector<std::string>* allowedModes = nullptr;
2110     const bool success = sdbusplus::unpackPropertiesNoThrow(
2111         dbus_utils::UnpackErrorPrinter(), properties, "PowerMode", powerMode,
2112         "AllowedPowerModes", allowedModes);
2113 
2114     if (!success)
2115     {
2116         messages::internalError(asyncResp->res);
2117         return;
2118     }
2119 
2120     nlohmann::json::array_t modeList;
2121     if (allowedModes == nullptr)
2122     {
2123         modeList.emplace_back("Static");
2124         modeList.emplace_back("MaximumPerformance");
2125         modeList.emplace_back("PowerSaving");
2126     }
2127     else
2128     {
2129         for (const auto& aMode : *allowedModes)
2130         {
2131             computer_system::PowerMode modeValue =
2132                 translatePowerModeString(aMode);
2133             if (modeValue == computer_system::PowerMode::Invalid)
2134             {
2135                 messages::internalError(asyncResp->res);
2136                 continue;
2137             }
2138             modeList.emplace_back(modeValue);
2139         }
2140     }
2141     asyncResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = modeList;
2142 
2143     BMCWEB_LOG_DEBUG("Current power mode: {}", powerMode);
2144     const computer_system::PowerMode modeValue =
2145         translatePowerModeString(powerMode);
2146     if (modeValue == computer_system::PowerMode::Invalid)
2147     {
2148         messages::internalError(asyncResp->res);
2149         return;
2150     }
2151     asyncResp->res.jsonValue["PowerMode"] = modeValue;
2152 }
2153 /**
2154  * @brief Retrieves system power mode
2155  *
2156  * @param[in] asyncResp  Shared pointer for generating response message.
2157  *
2158  * @return None.
2159  */
getPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2160 inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2161 {
2162     BMCWEB_LOG_DEBUG("Get power mode.");
2163 
2164     // Get Power Mode object path:
2165     constexpr std::array<std::string_view, 1> interfaces = {
2166         "xyz.openbmc_project.Control.Power.Mode"};
2167     dbus::utility::getSubTree(
2168         "/", 0, interfaces,
2169         [asyncResp](const boost::system::error_code& ec,
2170                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2171             if (ec)
2172             {
2173                 BMCWEB_LOG_DEBUG(
2174                     "DBUS response error on Power.Mode GetSubTree {}", ec);
2175                 // This is an optional D-Bus object so just return if
2176                 // error occurs
2177                 return;
2178             }
2179             if (subtree.empty())
2180             {
2181                 // As noted above, this is an optional interface so just return
2182                 // if there is no instance found
2183                 return;
2184             }
2185             if (subtree.size() > 1)
2186             {
2187                 // More then one PowerMode object is not supported and is an
2188                 // error
2189                 BMCWEB_LOG_DEBUG(
2190                     "Found more than 1 system D-Bus Power.Mode objects: {}",
2191                     subtree.size());
2192                 messages::internalError(asyncResp->res);
2193                 return;
2194             }
2195             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2196             {
2197                 BMCWEB_LOG_DEBUG("Power.Mode mapper error!");
2198                 messages::internalError(asyncResp->res);
2199                 return;
2200             }
2201             const std::string& path = subtree[0].first;
2202             const std::string& service = subtree[0].second.begin()->first;
2203             if (service.empty())
2204             {
2205                 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!");
2206                 messages::internalError(asyncResp->res);
2207                 return;
2208             }
2209 
2210             // Valid Power Mode object found, now read the mode properties
2211             dbus::utility::getAllProperties(
2212                 *crow::connections::systemBus, service, path,
2213                 "xyz.openbmc_project.Control.Power.Mode",
2214                 [asyncResp](
2215                     const boost::system::error_code& ec2,
2216                     const dbus::utility::DBusPropertiesMap& properties) {
2217                     afterGetPowerMode(asyncResp, ec2, properties);
2218                 });
2219         });
2220 }
2221 
2222 /**
2223  * @brief Validate the specified mode is valid and return the PowerMode
2224  * name associated with that string
2225  *
2226  * @param[in] asyncResp   Shared pointer for generating response message.
2227  * @param[in] modeValue   String representing the desired PowerMode
2228  *
2229  * @return PowerMode value or empty string if mode is not valid
2230  */
validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const nlohmann::json & modeValue)2231 inline std::string validatePowerMode(
2232     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2233     const nlohmann::json& modeValue)
2234 {
2235     using PowerMode = computer_system::PowerMode;
2236     std::string mode;
2237 
2238     if (modeValue == PowerMode::Static)
2239     {
2240         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static";
2241     }
2242     else if (modeValue == PowerMode::MaximumPerformance)
2243     {
2244         mode =
2245             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance";
2246     }
2247     else if (modeValue == PowerMode::PowerSaving)
2248     {
2249         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving";
2250     }
2251     else if (modeValue == PowerMode::BalancedPerformance)
2252     {
2253         mode =
2254             "xyz.openbmc_project.Control.Power.Mode.PowerMode.BalancedPerformance";
2255     }
2256     else if (modeValue == PowerMode::EfficiencyFavorPerformance)
2257     {
2258         mode =
2259             "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPerformance";
2260     }
2261     else if (modeValue == PowerMode::EfficiencyFavorPower)
2262     {
2263         mode =
2264             "xyz.openbmc_project.Control.Power.Mode.PowerMode.EfficiencyFavorPower";
2265     }
2266     else
2267     {
2268         messages::propertyValueNotInList(asyncResp->res, modeValue.dump(),
2269                                          "PowerMode");
2270     }
2271     return mode;
2272 }
2273 
2274 /**
2275  * @brief Sets system power mode.
2276  *
2277  * @param[in] asyncResp   Shared pointer for generating response message.
2278  * @param[in] pmode   System power mode from request.
2279  *
2280  * @return None.
2281  */
setPowerMode(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & pmode)2282 inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2283                          const std::string& pmode)
2284 {
2285     BMCWEB_LOG_DEBUG("Set power mode.");
2286 
2287     std::string powerMode = validatePowerMode(asyncResp, pmode);
2288     if (powerMode.empty())
2289     {
2290         return;
2291     }
2292 
2293     // Get Power Mode object path:
2294     constexpr std::array<std::string_view, 1> interfaces = {
2295         "xyz.openbmc_project.Control.Power.Mode"};
2296     dbus::utility::getSubTree(
2297         "/", 0, interfaces,
2298         [asyncResp,
2299          powerMode](const boost::system::error_code& ec,
2300                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2301             if (ec)
2302             {
2303                 BMCWEB_LOG_ERROR(
2304                     "DBUS response error on Power.Mode GetSubTree {}", ec);
2305                 // This is an optional D-Bus object, but user attempted to patch
2306                 messages::internalError(asyncResp->res);
2307                 return;
2308             }
2309             if (subtree.empty())
2310             {
2311                 // This is an optional D-Bus object, but user attempted to patch
2312                 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2313                                            "PowerMode");
2314                 return;
2315             }
2316             if (subtree.size() > 1)
2317             {
2318                 // More then one PowerMode object is not supported and is an
2319                 // error
2320                 BMCWEB_LOG_DEBUG(
2321                     "Found more than 1 system D-Bus Power.Mode objects: {}",
2322                     subtree.size());
2323                 messages::internalError(asyncResp->res);
2324                 return;
2325             }
2326             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2327             {
2328                 BMCWEB_LOG_DEBUG("Power.Mode mapper error!");
2329                 messages::internalError(asyncResp->res);
2330                 return;
2331             }
2332             const std::string& path = subtree[0].first;
2333             const std::string& service = subtree[0].second.begin()->first;
2334             if (service.empty())
2335             {
2336                 BMCWEB_LOG_DEBUG("Power.Mode service mapper error!");
2337                 messages::internalError(asyncResp->res);
2338                 return;
2339             }
2340 
2341             BMCWEB_LOG_DEBUG("Setting power mode({}) -> {}", powerMode, path);
2342 
2343             // Set the Power Mode property
2344             setDbusProperty(asyncResp, "PowerMode", service, path,
2345                             "xyz.openbmc_project.Control.Power.Mode",
2346                             "PowerMode", powerMode);
2347         });
2348 }
2349 
2350 /**
2351  * @brief Translates watchdog timeout action DBUS property value to redfish.
2352  *
2353  * @param[in] dbusAction    The watchdog timeout action in D-BUS.
2354  *
2355  * @return Returns as a string, the timeout action in Redfish terms. If
2356  * translation cannot be done, returns an empty string.
2357  */
dbusToRfWatchdogAction(const std::string & dbusAction)2358 inline std::string dbusToRfWatchdogAction(const std::string& dbusAction)
2359 {
2360     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None")
2361     {
2362         return "None";
2363     }
2364     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset")
2365     {
2366         return "ResetSystem";
2367     }
2368     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff")
2369     {
2370         return "PowerDown";
2371     }
2372     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle")
2373     {
2374         return "PowerCycle";
2375     }
2376 
2377     return "";
2378 }
2379 
2380 /**
2381  *@brief Translates timeout action from Redfish to DBUS property value.
2382  *
2383  *@param[in] rfAction The timeout action in Redfish.
2384  *
2385  *@return Returns as a string, the time_out action as expected by DBUS.
2386  *If translation cannot be done, returns an empty string.
2387  */
2388 
rfToDbusWDTTimeOutAct(const std::string & rfAction)2389 inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction)
2390 {
2391     if (rfAction == "None")
2392     {
2393         return "xyz.openbmc_project.State.Watchdog.Action.None";
2394     }
2395     if (rfAction == "PowerCycle")
2396     {
2397         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle";
2398     }
2399     if (rfAction == "PowerDown")
2400     {
2401         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff";
2402     }
2403     if (rfAction == "ResetSystem")
2404     {
2405         return "xyz.openbmc_project.State.Watchdog.Action.HardReset";
2406     }
2407 
2408     return "";
2409 }
2410 
2411 /**
2412  * @brief Retrieves host watchdog timer properties over DBUS
2413  *
2414  * @param[in] asyncResp     Shared pointer for completing asynchronous calls.
2415  *
2416  * @return None.
2417  */
getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2418 inline void getHostWatchdogTimer(
2419     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2420 {
2421     BMCWEB_LOG_DEBUG("Get host watchodg");
2422     dbus::utility::getAllProperties(
2423         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0",
2424         "xyz.openbmc_project.State.Watchdog",
2425         [asyncResp](const boost::system::error_code& ec,
2426                     const dbus::utility::DBusPropertiesMap& properties) {
2427             if (ec)
2428             {
2429                 // watchdog service is stopped
2430                 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
2431                 return;
2432             }
2433 
2434             BMCWEB_LOG_DEBUG("Got {} wdt prop.", properties.size());
2435 
2436             nlohmann::json& hostWatchdogTimer =
2437                 asyncResp->res.jsonValue["HostWatchdogTimer"];
2438 
2439             // watchdog service is running/enabled
2440             hostWatchdogTimer["Status"]["State"] = resource::State::Enabled;
2441 
2442             const bool* enabled = nullptr;
2443             const std::string* expireAction = nullptr;
2444 
2445             const bool success = sdbusplus::unpackPropertiesNoThrow(
2446                 dbus_utils::UnpackErrorPrinter(), properties, "Enabled",
2447                 enabled, "ExpireAction", expireAction);
2448 
2449             if (!success)
2450             {
2451                 messages::internalError(asyncResp->res);
2452                 return;
2453             }
2454 
2455             if (enabled != nullptr)
2456             {
2457                 hostWatchdogTimer["FunctionEnabled"] = *enabled;
2458             }
2459 
2460             if (expireAction != nullptr)
2461             {
2462                 std::string action = dbusToRfWatchdogAction(*expireAction);
2463                 if (action.empty())
2464                 {
2465                     messages::internalError(asyncResp->res);
2466                     return;
2467                 }
2468                 hostWatchdogTimer["TimeoutAction"] = action;
2469             }
2470         });
2471 }
2472 
2473 /**
2474  * @brief Sets Host WatchDog Timer properties.
2475  *
2476  * @param[in] asyncResp  Shared pointer for generating response message.
2477  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming
2478  *                       RF request.
2479  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request.
2480  *
2481  * @return None.
2482  */
setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::optional<bool> wdtEnable,const std::optional<std::string> & wdtTimeOutAction)2483 inline void setWDTProperties(
2484     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2485     const std::optional<bool> wdtEnable,
2486     const std::optional<std::string>& wdtTimeOutAction)
2487 {
2488     BMCWEB_LOG_DEBUG("Set host watchdog");
2489 
2490     if (wdtTimeOutAction)
2491     {
2492         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction);
2493         // check if TimeOut Action is Valid
2494         if (wdtTimeOutActStr.empty())
2495         {
2496             BMCWEB_LOG_DEBUG("Unsupported value for TimeoutAction: {}",
2497                              *wdtTimeOutAction);
2498             messages::propertyValueNotInList(asyncResp->res, *wdtTimeOutAction,
2499                                              "TimeoutAction");
2500             return;
2501         }
2502 
2503         setDbusProperty(asyncResp, "HostWatchdogTimer/TimeoutAction",
2504                         "xyz.openbmc_project.Watchdog",
2505                         sdbusplus::message::object_path(
2506                             "/xyz/openbmc_project/watchdog/host0"),
2507                         "xyz.openbmc_project.State.Watchdog", "ExpireAction",
2508                         wdtTimeOutActStr);
2509     }
2510 
2511     if (wdtEnable)
2512     {
2513         setDbusProperty(asyncResp, "HostWatchdogTimer/FunctionEnabled",
2514                         "xyz.openbmc_project.Watchdog",
2515                         sdbusplus::message::object_path(
2516                             "/xyz/openbmc_project/watchdog/host0"),
2517                         "xyz.openbmc_project.State.Watchdog", "Enabled",
2518                         *wdtEnable);
2519     }
2520 }
2521 
2522 /**
2523  * @brief Parse the Idle Power Saver properties into json
2524  *
2525  * @param[in] asyncResp   Shared pointer for completing asynchronous calls.
2526  * @param[in] properties  IPS property data from DBus.
2527  *
2528  * @return true if successful
2529  */
parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const dbus::utility::DBusPropertiesMap & properties)2530 inline bool parseIpsProperties(
2531     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2532     const dbus::utility::DBusPropertiesMap& properties)
2533 {
2534     const bool* enabled = nullptr;
2535     const uint8_t* enterUtilizationPercent = nullptr;
2536     const uint64_t* enterDwellTime = nullptr;
2537     const uint8_t* exitUtilizationPercent = nullptr;
2538     const uint64_t* exitDwellTime = nullptr;
2539 
2540     const bool success = sdbusplus::unpackPropertiesNoThrow(
2541         dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled,
2542         "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime",
2543         enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent,
2544         "ExitDwellTime", exitDwellTime);
2545 
2546     if (!success)
2547     {
2548         return false;
2549     }
2550 
2551     if (enabled != nullptr)
2552     {
2553         asyncResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled;
2554     }
2555 
2556     if (enterUtilizationPercent != nullptr)
2557     {
2558         asyncResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] =
2559             *enterUtilizationPercent;
2560     }
2561 
2562     if (enterDwellTime != nullptr)
2563     {
2564         const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime);
2565         asyncResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] =
2566             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2567                 .count();
2568     }
2569 
2570     if (exitUtilizationPercent != nullptr)
2571     {
2572         asyncResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] =
2573             *exitUtilizationPercent;
2574     }
2575 
2576     if (exitDwellTime != nullptr)
2577     {
2578         const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime);
2579         asyncResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] =
2580             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms)
2581                 .count();
2582     }
2583 
2584     return true;
2585 }
2586 
2587 /**
2588  * @brief Retrieves host watchdog timer properties over DBUS
2589  *
2590  * @param[in] asyncResp     Shared pointer for completing asynchronous calls.
2591  *
2592  * @return None.
2593  */
getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2594 inline void getIdlePowerSaver(
2595     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2596 {
2597     BMCWEB_LOG_DEBUG("Get idle power saver parameters");
2598 
2599     // Get IdlePowerSaver object path:
2600     constexpr std::array<std::string_view, 1> interfaces = {
2601         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2602     dbus::utility::getSubTree(
2603         "/", 0, interfaces,
2604         [asyncResp](const boost::system::error_code& ec,
2605                     const dbus::utility::MapperGetSubTreeResponse& subtree) {
2606             if (ec)
2607             {
2608                 BMCWEB_LOG_ERROR(
2609                     "DBUS response error on Power.IdlePowerSaver GetSubTree {}",
2610                     ec);
2611                 messages::internalError(asyncResp->res);
2612                 return;
2613             }
2614             if (subtree.empty())
2615             {
2616                 // This is an optional interface so just return
2617                 // if there is no instance found
2618                 BMCWEB_LOG_DEBUG("No instances found");
2619                 return;
2620             }
2621             if (subtree.size() > 1)
2622             {
2623                 // More then one PowerIdlePowerSaver object is not supported and
2624                 // is an error
2625                 BMCWEB_LOG_DEBUG("Found more than 1 system D-Bus "
2626                                  "Power.IdlePowerSaver objects: {}",
2627                                  subtree.size());
2628                 messages::internalError(asyncResp->res);
2629                 return;
2630             }
2631             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2632             {
2633                 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!");
2634                 messages::internalError(asyncResp->res);
2635                 return;
2636             }
2637             const std::string& path = subtree[0].first;
2638             const std::string& service = subtree[0].second.begin()->first;
2639             if (service.empty())
2640             {
2641                 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!");
2642                 messages::internalError(asyncResp->res);
2643                 return;
2644             }
2645 
2646             // Valid IdlePowerSaver object found, now read the current values
2647             dbus::utility::getAllProperties(
2648                 *crow::connections::systemBus, service, path,
2649                 "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2650                 [asyncResp](
2651                     const boost::system::error_code& ec2,
2652                     const dbus::utility::DBusPropertiesMap& properties) {
2653                     if (ec2)
2654                     {
2655                         BMCWEB_LOG_ERROR(
2656                             "DBUS response error on IdlePowerSaver GetAll: {}",
2657                             ec2);
2658                         messages::internalError(asyncResp->res);
2659                         return;
2660                     }
2661 
2662                     if (!parseIpsProperties(asyncResp, properties))
2663                     {
2664                         messages::internalError(asyncResp->res);
2665                         return;
2666                     }
2667                 });
2668         });
2669 
2670     BMCWEB_LOG_DEBUG("EXIT: Get idle power saver parameters");
2671 }
2672 
2673 /**
2674  * @brief Sets Idle Power Saver properties.
2675  *
2676  * @param[in] asyncResp  Shared pointer for generating response message.
2677  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming
2678  *                       RF request.
2679  * @param[in] ipsEnterUtil The utilization limit to enter idle state.
2680  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil
2681  * before entering idle state.
2682  * @param[in] ipsExitUtil The utilization limit when exiting idle state.
2683  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil
2684  * before exiting idle state
2685  *
2686  * @return None.
2687  */
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)2688 inline void setIdlePowerSaver(
2689     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2690     const std::optional<bool> ipsEnable,
2691     const std::optional<uint8_t> ipsEnterUtil,
2692     const std::optional<uint64_t> ipsEnterTime,
2693     const std::optional<uint8_t> ipsExitUtil,
2694     const std::optional<uint64_t> ipsExitTime)
2695 {
2696     BMCWEB_LOG_DEBUG("Set idle power saver properties");
2697 
2698     // Get IdlePowerSaver object path:
2699     constexpr std::array<std::string_view, 1> interfaces = {
2700         "xyz.openbmc_project.Control.Power.IdlePowerSaver"};
2701     dbus::utility::getSubTree(
2702         "/", 0, interfaces,
2703         [asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil,
2704          ipsExitTime](const boost::system::error_code& ec,
2705                       const dbus::utility::MapperGetSubTreeResponse& subtree) {
2706             if (ec)
2707             {
2708                 BMCWEB_LOG_ERROR(
2709                     "DBUS response error on Power.IdlePowerSaver GetSubTree {}",
2710                     ec);
2711                 messages::internalError(asyncResp->res);
2712                 return;
2713             }
2714             if (subtree.empty())
2715             {
2716                 // This is an optional D-Bus object, but user attempted to patch
2717                 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2718                                            "IdlePowerSaver");
2719                 return;
2720             }
2721             if (subtree.size() > 1)
2722             {
2723                 // More then one PowerIdlePowerSaver object is not supported and
2724                 // is an error
2725                 BMCWEB_LOG_DEBUG(
2726                     "Found more than 1 system D-Bus Power.IdlePowerSaver objects: {}",
2727                     subtree.size());
2728                 messages::internalError(asyncResp->res);
2729                 return;
2730             }
2731             if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1))
2732             {
2733                 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver mapper error!");
2734                 messages::internalError(asyncResp->res);
2735                 return;
2736             }
2737             const std::string& path = subtree[0].first;
2738             const std::string& service = subtree[0].second.begin()->first;
2739             if (service.empty())
2740             {
2741                 BMCWEB_LOG_DEBUG("Power.IdlePowerSaver service mapper error!");
2742                 messages::internalError(asyncResp->res);
2743                 return;
2744             }
2745 
2746             // Valid Power IdlePowerSaver object found, now set any values that
2747             // need to be updated
2748 
2749             if (ipsEnable)
2750             {
2751                 setDbusProperty(
2752                     asyncResp, "IdlePowerSaver/Enabled", service, path,
2753                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2754                     "Enabled", *ipsEnable);
2755             }
2756             if (ipsEnterUtil)
2757             {
2758                 setDbusProperty(
2759                     asyncResp, "IdlePowerSaver/EnterUtilizationPercent",
2760                     service, path,
2761                     "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2762                     "EnterUtilizationPercent", *ipsEnterUtil);
2763             }
2764             if (ipsEnterTime)
2765             {
2766                 // Convert from seconds into milliseconds for DBus
2767                 const uint64_t timeMilliseconds = *ipsEnterTime * 1000;
2768                 setDbusProperty(
2769                     asyncResp, "IdlePowerSaver/EnterDwellTimeSeconds", service,
2770                     path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2771                     "EnterDwellTime", timeMilliseconds);
2772             }
2773             if (ipsExitUtil)
2774             {
2775                 setDbusProperty(
2776                     asyncResp, "IdlePowerSaver/ExitUtilizationPercent", service,
2777                     path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2778                     "ExitUtilizationPercent", *ipsExitUtil);
2779             }
2780             if (ipsExitTime)
2781             {
2782                 // Convert from seconds into milliseconds for DBus
2783                 const uint64_t timeMilliseconds = *ipsExitTime * 1000;
2784                 setDbusProperty(
2785                     asyncResp, "IdlePowerSaver/ExitDwellTimeSeconds", service,
2786                     path, "xyz.openbmc_project.Control.Power.IdlePowerSaver",
2787                     "ExitDwellTime", timeMilliseconds);
2788             }
2789         });
2790 
2791     BMCWEB_LOG_DEBUG("EXIT: Set idle power saver parameters");
2792 }
2793 
handleComputerSystemCollectionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2794 inline void handleComputerSystemCollectionHead(
2795     crow::App& app, const crow::Request& req,
2796     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2797 {
2798     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2799     {
2800         return;
2801     }
2802     asyncResp->res.addHeader(
2803         boost::beast::http::field::link,
2804         "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby");
2805 }
2806 
handleComputerSystemCollectionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2807 inline void handleComputerSystemCollectionGet(
2808     crow::App& app, const crow::Request& req,
2809     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2810 {
2811     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2812     {
2813         return;
2814     }
2815 
2816     asyncResp->res.addHeader(
2817         boost::beast::http::field::link,
2818         "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby");
2819     asyncResp->res.jsonValue["@odata.type"] =
2820         "#ComputerSystemCollection.ComputerSystemCollection";
2821     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems";
2822     asyncResp->res.jsonValue["Name"] = "Computer System Collection";
2823 
2824     getSystemCollectionMembers(asyncResp);
2825 }
2826 
2827 /**
2828  * Function transceives data with dbus directly.
2829  */
doNMI(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)2830 inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2831 {
2832     constexpr const char* serviceName = "xyz.openbmc_project.Control.Host.NMI";
2833     constexpr const char* objectPath = "/xyz/openbmc_project/control/host0/nmi";
2834     constexpr const char* interfaceName =
2835         "xyz.openbmc_project.Control.Host.NMI";
2836     constexpr const char* method = "NMI";
2837 
2838     dbus::utility::async_method_call(
2839         asyncResp,
2840         [asyncResp](const boost::system::error_code& ec) {
2841             if (ec)
2842             {
2843                 BMCWEB_LOG_ERROR(" Bad D-Bus request error: {}", ec);
2844                 messages::internalError(asyncResp->res);
2845                 return;
2846             }
2847             messages::success(asyncResp->res);
2848         },
2849         serviceName, objectPath, interfaceName, method);
2850 }
2851 
handleComputerSystemResetActionPost(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)2852 inline void handleComputerSystemResetActionPost(
2853     crow::App& app, const crow::Request& req,
2854     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2855     const std::string& systemName)
2856 {
2857     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2858     {
2859         return;
2860     }
2861 
2862     if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
2863     {
2864         if (systemName == "hypervisor")
2865         {
2866             handleHypervisorSystemResetPost(req, asyncResp);
2867             return;
2868         }
2869     }
2870 
2871     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
2872     {
2873         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2874                                    systemName);
2875         return;
2876     }
2877     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
2878     {
2879         // Option currently returns no systems.  TBD
2880         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
2881                                    systemName);
2882         return;
2883     }
2884     std::string resetType;
2885     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType))
2886     {
2887         return;
2888     }
2889 
2890     // Get the command and host vs. chassis
2891     std::string command;
2892     bool hostCommand = true;
2893     if ((resetType == "On") || (resetType == "ForceOn"))
2894     {
2895         command = "xyz.openbmc_project.State.Host.Transition.On";
2896         hostCommand = true;
2897     }
2898     else if (resetType == "ForceOff")
2899     {
2900         command = "xyz.openbmc_project.State.Chassis.Transition.Off";
2901         hostCommand = false;
2902     }
2903     else if (resetType == "ForceRestart")
2904     {
2905         command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot";
2906         hostCommand = true;
2907     }
2908     else if (resetType == "GracefulShutdown")
2909     {
2910         command = "xyz.openbmc_project.State.Host.Transition.Off";
2911         hostCommand = true;
2912     }
2913     else if (resetType == "GracefulRestart")
2914     {
2915         command =
2916             "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot";
2917         hostCommand = true;
2918     }
2919     else if (resetType == "PowerCycle")
2920     {
2921         command = "xyz.openbmc_project.State.Host.Transition.Reboot";
2922         hostCommand = true;
2923     }
2924     else if (resetType == "Nmi")
2925     {
2926         doNMI(asyncResp);
2927         return;
2928     }
2929     else
2930     {
2931         messages::actionParameterUnknown(asyncResp->res, "Reset", resetType);
2932         return;
2933     }
2934     sdbusplus::message::object_path statePath("/xyz/openbmc_project/state");
2935 
2936     if (hostCommand)
2937     {
2938         setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Host",
2939                         statePath / "host0", "xyz.openbmc_project.State.Host",
2940                         "RequestedHostTransition", command);
2941     }
2942     else
2943     {
2944         setDbusProperty(asyncResp, "Reset", "xyz.openbmc_project.State.Chassis",
2945                         statePath / "chassis0",
2946                         "xyz.openbmc_project.State.Chassis",
2947                         "RequestedPowerTransition", command);
2948     }
2949 }
2950 
handleComputerSystemHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)2951 inline void handleComputerSystemHead(
2952     App& app, const crow::Request& req,
2953     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2954     const std::string& /*systemName*/)
2955 {
2956     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
2957     {
2958         return;
2959     }
2960 
2961     asyncResp->res.addHeader(
2962         boost::beast::http::field::link,
2963         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
2964 }
2965 
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)2966 inline void afterPortRequest(
2967     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2968     const boost::system::error_code& ec,
2969     const std::vector<std::tuple<std::string, std::string, bool>>& socketData)
2970 {
2971     if (ec)
2972     {
2973         BMCWEB_LOG_ERROR("DBUS response error {}", ec);
2974         messages::internalError(asyncResp->res);
2975         return;
2976     }
2977     for (const auto& data : socketData)
2978     {
2979         const std::string& socketPath = get<0>(data);
2980         const std::string& protocolName = get<1>(data);
2981         bool isProtocolEnabled = get<2>(data);
2982         nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"];
2983         dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled;
2984         // need to retrieve port number for
2985         // obmc-console-ssh service
2986         if (protocolName == "SSH")
2987         {
2988             getPortNumber(socketPath, [asyncResp, protocolName](
2989                                           const boost::system::error_code& ec1,
2990                                           int portNumber) {
2991                 if (ec1)
2992                 {
2993                     BMCWEB_LOG_ERROR("DBUS response error {}", ec1);
2994                     messages::internalError(asyncResp->res);
2995                     return;
2996                 }
2997                 nlohmann::json& dataJson1 =
2998                     asyncResp->res.jsonValue["SerialConsole"];
2999                 dataJson1[protocolName]["Port"] = portNumber;
3000             });
3001         }
3002     }
3003 }
3004 
handleComputerSystemGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3005 inline void handleComputerSystemGet(
3006     crow::App& app, const crow::Request& req,
3007     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3008     const std::string& systemName)
3009 {
3010     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3011     {
3012         return;
3013     }
3014 
3015     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3016     {
3017         // Option currently returns no systems.  TBD
3018         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3019                                    systemName);
3020         return;
3021     }
3022 
3023     if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
3024     {
3025         if (systemName == "hypervisor")
3026         {
3027             handleHypervisorSystemGet(asyncResp);
3028             return;
3029         }
3030     }
3031 
3032     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3033     {
3034         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3035                                    systemName);
3036         return;
3037     }
3038     asyncResp->res.addHeader(
3039         boost::beast::http::field::link,
3040         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3041     asyncResp->res.jsonValue["@odata.type"] =
3042         "#ComputerSystem.v1_22_0.ComputerSystem";
3043     asyncResp->res.jsonValue["Name"] = BMCWEB_REDFISH_SYSTEM_URI_NAME;
3044     asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_SYSTEM_URI_NAME;
3045     asyncResp->res.jsonValue["SystemType"] =
3046         computer_system::SystemType::Physical;
3047     asyncResp->res.jsonValue["Description"] = "Computer System";
3048     asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0;
3049     asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] =
3050         double(0);
3051     asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
3052         "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3053 
3054     asyncResp->res.jsonValue["Processors"]["@odata.id"] = boost::urls::format(
3055         "/redfish/v1/Systems/{}/Processors", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3056     asyncResp->res.jsonValue["Memory"]["@odata.id"] = boost::urls::format(
3057         "/redfish/v1/Systems/{}/Memory", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3058     asyncResp->res.jsonValue["Storage"]["@odata.id"] = boost::urls::format(
3059         "/redfish/v1/Systems/{}/Storage", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3060     asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] =
3061         boost::urls::format("/redfish/v1/Systems/{}/FabricAdapters",
3062                             BMCWEB_REDFISH_SYSTEM_URI_NAME);
3063 
3064     asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] =
3065         boost::urls::format(
3066             "/redfish/v1/Systems/{}/Actions/ComputerSystem.Reset",
3067             BMCWEB_REDFISH_SYSTEM_URI_NAME);
3068     asyncResp->res
3069         .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] =
3070         boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo",
3071                             BMCWEB_REDFISH_SYSTEM_URI_NAME);
3072 
3073     asyncResp->res.jsonValue["LogServices"]["@odata.id"] = boost::urls::format(
3074         "/redfish/v1/Systems/{}/LogServices", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3075     asyncResp->res.jsonValue["Bios"]["@odata.id"] = boost::urls::format(
3076         "/redfish/v1/Systems/{}/Bios", BMCWEB_REDFISH_SYSTEM_URI_NAME);
3077 
3078     nlohmann::json::array_t managedBy;
3079     nlohmann::json& manager = managedBy.emplace_back();
3080     manager["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}",
3081                                                BMCWEB_REDFISH_MANAGER_URI_NAME);
3082     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy);
3083     asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK;
3084     asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled;
3085 
3086     // Fill in SerialConsole info
3087     asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15;
3088     asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = true;
3089 
3090     asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = true;
3091     asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200;
3092     asyncResp->res.jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] =
3093         "Press ~. to exit console";
3094     getPortStatusAndPath(std::span{protocolToDBusForSystems},
3095                          std::bind_front(afterPortRequest, asyncResp));
3096 
3097     if constexpr (BMCWEB_KVM)
3098     {
3099         // Fill in GraphicalConsole info
3100         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true;
3101         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] =
3102             4;
3103         asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] =
3104             nlohmann::json::array_t({"KVMIP"});
3105     }
3106 
3107     getMainChassisId(
3108         asyncResp, [](const std::string& chassisId,
3109                       const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
3110             nlohmann::json::array_t chassisArray;
3111             nlohmann::json& chassis = chassisArray.emplace_back();
3112             chassis["@odata.id"] =
3113                 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
3114             aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray);
3115         });
3116 
3117     getSystemLocationIndicatorActive(asyncResp);
3118     // TODO (Gunnar): Remove IndicatorLED after enough time has passed
3119     getIndicatorLedState(asyncResp);
3120     getComputerSystem(asyncResp);
3121     getHostState(asyncResp);
3122     getBootProperties(asyncResp);
3123     getBootProgress(asyncResp);
3124     getBootProgressLastStateTime(asyncResp);
3125     pcie_util::getPCIeDeviceList(asyncResp,
3126                                  nlohmann::json::json_pointer("/PCIeDevices"));
3127     getHostWatchdogTimer(asyncResp);
3128     getPowerRestorePolicy(asyncResp);
3129     getStopBootOnFault(asyncResp);
3130     getAutomaticRetryPolicy(asyncResp);
3131     getLastResetTime(asyncResp);
3132     if constexpr (BMCWEB_REDFISH_PROVISIONING_FEATURE)
3133     {
3134         getProvisioningStatus(asyncResp);
3135     }
3136     getTrustedModuleRequiredToBoot(asyncResp);
3137     getPowerMode(asyncResp);
3138     getIdlePowerSaver(asyncResp);
3139 }
3140 
handleComputerSystemPatch(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3141 inline void handleComputerSystemPatch(
3142     crow::App& app, const crow::Request& req,
3143     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3144     const std::string& systemName)
3145 {
3146     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3147     {
3148         return;
3149     }
3150     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3151     {
3152         // Option currently returns no systems.  TBD
3153         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3154                                    systemName);
3155         return;
3156     }
3157     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3158     {
3159         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3160                                    systemName);
3161         return;
3162     }
3163 
3164     asyncResp->res.addHeader(
3165         boost::beast::http::field::link,
3166         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby");
3167 
3168     std::optional<bool> locationIndicatorActive;
3169     std::optional<std::string> indicatorLed;
3170     std::optional<std::string> assetTag;
3171     std::optional<std::string> powerRestorePolicy;
3172     std::optional<std::string> powerMode;
3173     std::optional<bool> wdtEnable;
3174     std::optional<std::string> wdtTimeOutAction;
3175     std::optional<std::string> bootSource;
3176     std::optional<std::string> bootType;
3177     std::optional<std::string> bootEnable;
3178     std::optional<std::string> bootAutomaticRetry;
3179     std::optional<uint32_t> bootAutomaticRetryAttempts;
3180     std::optional<bool> bootTrustedModuleRequired;
3181     std::optional<std::string> stopBootOnFault;
3182     std::optional<bool> ipsEnable;
3183     std::optional<uint8_t> ipsEnterUtil;
3184     std::optional<uint64_t> ipsEnterTime;
3185     std::optional<uint8_t> ipsExitUtil;
3186     std::optional<uint64_t> ipsExitTime;
3187 
3188     if (!json_util::readJsonPatch(                                         //
3189             req, asyncResp->res,                                           //
3190             "AssetTag", assetTag,                                          //
3191             "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts,     //
3192             "Boot/AutomaticRetryConfig", bootAutomaticRetry,               //
3193             "Boot/BootSourceOverrideEnabled", bootEnable,                  //
3194             "Boot/BootSourceOverrideMode", bootType,                       //
3195             "Boot/BootSourceOverrideTarget", bootSource,                   //
3196             "Boot/StopBootOnFault", stopBootOnFault,                       //
3197             "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired, //
3198             "HostWatchdogTimer/FunctionEnabled", wdtEnable,                //
3199             "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,           //
3200             "IdlePowerSaver/Enabled", ipsEnable,                           //
3201             "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,          //
3202             "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,        //
3203             "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime,            //
3204             "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,          //
3205             "IndicatorLED", indicatorLed,                                  //
3206             "LocationIndicatorActive", locationIndicatorActive,            //
3207             "PowerMode", powerMode,                                        //
3208             "PowerRestorePolicy", powerRestorePolicy                       //
3209             ))
3210     {
3211         return;
3212     }
3213 
3214     asyncResp->res.result(boost::beast::http::status::no_content);
3215 
3216     if (assetTag)
3217     {
3218         setAssetTag(asyncResp, *assetTag);
3219     }
3220 
3221     if (wdtEnable || wdtTimeOutAction)
3222     {
3223         setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3224     }
3225 
3226     if (bootSource || bootType || bootEnable)
3227     {
3228         setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3229     }
3230     if (bootAutomaticRetry)
3231     {
3232         setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3233     }
3234 
3235     if (bootAutomaticRetryAttempts)
3236     {
3237         setAutomaticRetryAttempts(asyncResp,
3238                                   bootAutomaticRetryAttempts.value());
3239     }
3240 
3241     if (bootTrustedModuleRequired)
3242     {
3243         setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired);
3244     }
3245 
3246     if (stopBootOnFault)
3247     {
3248         setStopBootOnFault(asyncResp, *stopBootOnFault);
3249     }
3250 
3251     if (locationIndicatorActive)
3252     {
3253         setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3254     }
3255 
3256     // TODO (Gunnar): Remove IndicatorLED after enough time has
3257     // passed
3258     if (indicatorLed)
3259     {
3260         setIndicatorLedState(asyncResp, *indicatorLed);
3261         asyncResp->res.addHeader(boost::beast::http::field::warning,
3262                                  "299 - \"IndicatorLED is deprecated. Use "
3263                                  "LocationIndicatorActive instead.\"");
3264     }
3265 
3266     if (powerRestorePolicy)
3267     {
3268         setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3269     }
3270 
3271     if (powerMode)
3272     {
3273         setPowerMode(asyncResp, *powerMode);
3274     }
3275 
3276     if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime)
3277     {
3278         setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3279                           ipsExitUtil, ipsExitTime);
3280     }
3281 }
3282 
handleSystemCollectionResetActionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)3283 inline void handleSystemCollectionResetActionHead(
3284     crow::App& app, const crow::Request& req,
3285     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3286     const std::string& /*systemName*/)
3287 {
3288     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3289     {
3290         return;
3291     }
3292     asyncResp->res.addHeader(
3293         boost::beast::http::field::link,
3294         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3295 }
3296 
3297 /**
3298  * @brief Translates allowed host transitions to redfish string
3299  *
3300  * @param[in]  dbusAllowedHostTran The allowed host transition on dbus
3301  * @param[out] allowableValues     The translated host transition(s)
3302  *
3303  * @return Emplaces corresponding Redfish translated value(s) in
3304  * allowableValues. If translation not possible, does nothing to
3305  * allowableValues.
3306  */
dbusToRfAllowedHostTransitions(const std::string & dbusAllowedHostTran,nlohmann::json::array_t & allowableValues)3307 inline void dbusToRfAllowedHostTransitions(
3308     const std::string& dbusAllowedHostTran,
3309     nlohmann::json::array_t& allowableValues)
3310 {
3311     if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On")
3312     {
3313         allowableValues.emplace_back(resource::ResetType::On);
3314         allowableValues.emplace_back(resource::ResetType::ForceOn);
3315     }
3316     else if (dbusAllowedHostTran ==
3317              "xyz.openbmc_project.State.Host.Transition.Off")
3318     {
3319         allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3320     }
3321     else if (dbusAllowedHostTran ==
3322              "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
3323     {
3324         allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3325     }
3326     else if (dbusAllowedHostTran ==
3327              "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3328     {
3329         allowableValues.emplace_back(resource::ResetType::ForceRestart);
3330     }
3331     else
3332     {
3333         BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran);
3334     }
3335 }
3336 
afterGetAllowedHostTransitions(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::vector<std::string> & allowedHostTransitions)3337 inline void afterGetAllowedHostTransitions(
3338     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3339     const boost::system::error_code& ec,
3340     const std::vector<std::string>& allowedHostTransitions)
3341 {
3342     nlohmann::json::array_t allowableValues;
3343 
3344     // Supported on all systems currently
3345     allowableValues.emplace_back(resource::ResetType::ForceOff);
3346     allowableValues.emplace_back(resource::ResetType::PowerCycle);
3347     allowableValues.emplace_back(resource::ResetType::Nmi);
3348 
3349     if (ec)
3350     {
3351         if ((ec.value() ==
3352              boost::system::linux_error::bad_request_descriptor) ||
3353             (ec.value() == boost::asio::error::basic_errors::host_unreachable))
3354         {
3355             // Property not implemented so just return defaults
3356             BMCWEB_LOG_DEBUG("Property not available {}", ec);
3357             allowableValues.emplace_back(resource::ResetType::On);
3358             allowableValues.emplace_back(resource::ResetType::ForceOn);
3359             allowableValues.emplace_back(resource::ResetType::ForceRestart);
3360             allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3361             allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3362         }
3363         else
3364         {
3365             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
3366             messages::internalError(asyncResp->res);
3367             return;
3368         }
3369     }
3370     else
3371     {
3372         for (const std::string& transition : allowedHostTransitions)
3373         {
3374             BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition);
3375             dbusToRfAllowedHostTransitions(transition, allowableValues);
3376         }
3377     }
3378 
3379     nlohmann::json::object_t parameter;
3380     parameter["Name"] = "ResetType";
3381     parameter["Required"] = true;
3382     parameter["DataType"] = action_info::ParameterTypes::String;
3383     parameter["AllowableValues"] = std::move(allowableValues);
3384     nlohmann::json::array_t parameters;
3385     parameters.emplace_back(std::move(parameter));
3386     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3387 }
3388 
handleSystemCollectionResetActionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3389 inline void handleSystemCollectionResetActionGet(
3390     crow::App& app, const crow::Request& req,
3391     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3392     const std::string& systemName)
3393 {
3394     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3395     {
3396         return;
3397     }
3398     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3399     {
3400         // Option currently returns no systems.  TBD
3401         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3402                                    systemName);
3403         return;
3404     }
3405 
3406     if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
3407     {
3408         if (systemName == "hypervisor")
3409         {
3410             handleHypervisorResetActionGet(asyncResp);
3411             return;
3412         }
3413     }
3414 
3415     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3416     {
3417         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3418                                    systemName);
3419         return;
3420     }
3421 
3422     asyncResp->res.addHeader(
3423         boost::beast::http::field::link,
3424         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3425 
3426     asyncResp->res.jsonValue["@odata.id"] =
3427         boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo",
3428                             BMCWEB_REDFISH_SYSTEM_URI_NAME);
3429     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
3430     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3431     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3432 
3433     // Look to see if system defines AllowedHostTransitions
3434     dbus::utility::getProperty<std::vector<std::string>>(
3435         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
3436         "xyz.openbmc_project.State.Host", "AllowedHostTransitions",
3437         [asyncResp](const boost::system::error_code& ec,
3438                     const std::vector<std::string>& allowedHostTransitions) {
3439             afterGetAllowedHostTransitions(asyncResp, ec,
3440                                            allowedHostTransitions);
3441         });
3442 }
3443 /**
3444  * SystemResetActionInfo derived class for delivering Computer Systems
3445  * ResetType AllowableValues using ResetInfo schema.
3446  */
requestRoutesSystems(App & app)3447 inline void requestRoutesSystems(App& app)
3448 {
3449     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3450         .privileges(redfish::privileges::headComputerSystemCollection)
3451         .methods(boost::beast::http::verb::head)(
3452             std::bind_front(handleComputerSystemCollectionHead, std::ref(app)));
3453 
3454     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3455         .privileges(redfish::privileges::getComputerSystemCollection)
3456         .methods(boost::beast::http::verb::get)(
3457             std::bind_front(handleComputerSystemCollectionGet, std::ref(app)));
3458 
3459     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3460         .privileges(redfish::privileges::headComputerSystem)
3461         .methods(boost::beast::http::verb::head)(
3462             std::bind_front(handleComputerSystemHead, std::ref(app)));
3463 
3464     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3465         .privileges(redfish::privileges::getComputerSystem)
3466         .methods(boost::beast::http::verb::get)(
3467             std::bind_front(handleComputerSystemGet, std::ref(app)));
3468 
3469     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3470         .privileges(redfish::privileges::patchComputerSystem)
3471         .methods(boost::beast::http::verb::patch)(
3472             std::bind_front(handleComputerSystemPatch, std::ref(app)));
3473 
3474     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/")
3475         .privileges(redfish::privileges::postComputerSystem)
3476         .methods(boost::beast::http::verb::post)(std::bind_front(
3477             handleComputerSystemResetActionPost, std::ref(app)));
3478 
3479     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3480         .privileges(redfish::privileges::headActionInfo)
3481         .methods(boost::beast::http::verb::head)(std::bind_front(
3482             handleSystemCollectionResetActionHead, std::ref(app)));
3483     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3484         .privileges(redfish::privileges::getActionInfo)
3485         .methods(boost::beast::http::verb::get)(std::bind_front(
3486             handleSystemCollectionResetActionGet, std::ref(app)));
3487 }
3488 } // namespace redfish
3489