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