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