xref: /openbmc/bmcweb/redfish-core/lib/systems.hpp (revision dd7090e6)
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     // clang-format off
3203     if (!json_util::readJsonPatch(
3204             req, asyncResp->res,
3205             "IndicatorLED", indicatorLed,
3206             "LocationIndicatorActive", locationIndicatorActive,
3207             "AssetTag", assetTag,
3208             "PowerRestorePolicy", powerRestorePolicy,
3209             "PowerMode", powerMode,
3210             "HostWatchdogTimer/FunctionEnabled", wdtEnable,
3211             "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction,
3212             "Boot/BootSourceOverrideTarget", bootSource,
3213             "Boot/BootSourceOverrideMode", bootType,
3214             "Boot/BootSourceOverrideEnabled", bootEnable,
3215             "Boot/AutomaticRetryConfig", bootAutomaticRetry,
3216             "Boot/AutomaticRetryAttempts", bootAutomaticRetryAttempts,
3217             "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired,
3218             "Boot/StopBootOnFault", stopBootOnFault,
3219             "IdlePowerSaver/Enabled", ipsEnable,
3220             "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil,
3221             "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime,
3222             "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil,
3223             "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime))
3224     {
3225         return;
3226     }
3227     // clang-format on
3228 
3229     asyncResp->res.result(boost::beast::http::status::no_content);
3230 
3231     if (assetTag)
3232     {
3233         setAssetTag(asyncResp, *assetTag);
3234     }
3235 
3236     if (wdtEnable || wdtTimeOutAction)
3237     {
3238         setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction);
3239     }
3240 
3241     if (bootSource || bootType || bootEnable)
3242     {
3243         setBootProperties(asyncResp, bootSource, bootType, bootEnable);
3244     }
3245     if (bootAutomaticRetry)
3246     {
3247         setAutomaticRetry(asyncResp, *bootAutomaticRetry);
3248     }
3249 
3250     if (bootAutomaticRetryAttempts)
3251     {
3252         setAutomaticRetryAttempts(asyncResp,
3253                                   bootAutomaticRetryAttempts.value());
3254     }
3255 
3256     if (bootTrustedModuleRequired)
3257     {
3258         setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired);
3259     }
3260 
3261     if (stopBootOnFault)
3262     {
3263         setStopBootOnFault(asyncResp, *stopBootOnFault);
3264     }
3265 
3266     if (locationIndicatorActive)
3267     {
3268         setSystemLocationIndicatorActive(asyncResp, *locationIndicatorActive);
3269     }
3270 
3271     // TODO (Gunnar): Remove IndicatorLED after enough time has
3272     // passed
3273     if (indicatorLed)
3274     {
3275         setIndicatorLedState(asyncResp, *indicatorLed);
3276         asyncResp->res.addHeader(boost::beast::http::field::warning,
3277                                  "299 - \"IndicatorLED is deprecated. Use "
3278                                  "LocationIndicatorActive instead.\"");
3279     }
3280 
3281     if (powerRestorePolicy)
3282     {
3283         setPowerRestorePolicy(asyncResp, *powerRestorePolicy);
3284     }
3285 
3286     if (powerMode)
3287     {
3288         setPowerMode(asyncResp, *powerMode);
3289     }
3290 
3291     if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime)
3292     {
3293         setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime,
3294                           ipsExitUtil, ipsExitTime);
3295     }
3296 }
3297 
handleSystemCollectionResetActionHead(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)3298 inline void handleSystemCollectionResetActionHead(
3299     crow::App& app, const crow::Request& req,
3300     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3301     const std::string& /*systemName*/)
3302 {
3303     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3304     {
3305         return;
3306     }
3307     asyncResp->res.addHeader(
3308         boost::beast::http::field::link,
3309         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3310 }
3311 
3312 /**
3313  * @brief Translates allowed host transitions to redfish string
3314  *
3315  * @param[in]  dbusAllowedHostTran The allowed host transition on dbus
3316  * @param[out] allowableValues     The translated host transition(s)
3317  *
3318  * @return Emplaces corresponding Redfish translated value(s) in
3319  * allowableValues. If translation not possible, does nothing to
3320  * allowableValues.
3321  */
3322 inline void
dbusToRfAllowedHostTransitions(const std::string & dbusAllowedHostTran,nlohmann::json::array_t & allowableValues)3323     dbusToRfAllowedHostTransitions(const std::string& dbusAllowedHostTran,
3324                                    nlohmann::json::array_t& allowableValues)
3325 {
3326     if (dbusAllowedHostTran == "xyz.openbmc_project.State.Host.Transition.On")
3327     {
3328         allowableValues.emplace_back(resource::ResetType::On);
3329         allowableValues.emplace_back(resource::ResetType::ForceOn);
3330     }
3331     else if (dbusAllowedHostTran ==
3332              "xyz.openbmc_project.State.Host.Transition.Off")
3333     {
3334         allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3335     }
3336     else if (dbusAllowedHostTran ==
3337              "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot")
3338     {
3339         allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3340     }
3341     else if (dbusAllowedHostTran ==
3342              "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot")
3343     {
3344         allowableValues.emplace_back(resource::ResetType::ForceRestart);
3345     }
3346     else
3347     {
3348         BMCWEB_LOG_WARNING("Unsupported host tran {}", dbusAllowedHostTran);
3349     }
3350 }
3351 
afterGetAllowedHostTransitions(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::system::error_code & ec,const std::vector<std::string> & allowedHostTransitions)3352 inline void afterGetAllowedHostTransitions(
3353     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3354     const boost::system::error_code& ec,
3355     const std::vector<std::string>& allowedHostTransitions)
3356 {
3357     nlohmann::json::array_t allowableValues;
3358 
3359     // Supported on all systems currently
3360     allowableValues.emplace_back(resource::ResetType::ForceOff);
3361     allowableValues.emplace_back(resource::ResetType::PowerCycle);
3362     allowableValues.emplace_back(resource::ResetType::Nmi);
3363 
3364     if (ec)
3365     {
3366         if ((ec.value() ==
3367              boost::system::linux_error::bad_request_descriptor) ||
3368             (ec.value() == boost::asio::error::basic_errors::host_unreachable))
3369         {
3370             // Property not implemented so just return defaults
3371             BMCWEB_LOG_DEBUG("Property not available {}", ec);
3372             allowableValues.emplace_back(resource::ResetType::On);
3373             allowableValues.emplace_back(resource::ResetType::ForceOn);
3374             allowableValues.emplace_back(resource::ResetType::ForceRestart);
3375             allowableValues.emplace_back(resource::ResetType::GracefulRestart);
3376             allowableValues.emplace_back(resource::ResetType::GracefulShutdown);
3377         }
3378         else
3379         {
3380             BMCWEB_LOG_ERROR("DBUS response error {}", ec);
3381             messages::internalError(asyncResp->res);
3382             return;
3383         }
3384     }
3385     else
3386     {
3387         for (const std::string& transition : allowedHostTransitions)
3388         {
3389             BMCWEB_LOG_DEBUG("Found allowed host tran {}", transition);
3390             dbusToRfAllowedHostTransitions(transition, allowableValues);
3391         }
3392     }
3393 
3394     nlohmann::json::object_t parameter;
3395     parameter["Name"] = "ResetType";
3396     parameter["Required"] = true;
3397     parameter["DataType"] = action_info::ParameterTypes::String;
3398     parameter["AllowableValues"] = std::move(allowableValues);
3399     nlohmann::json::array_t parameters;
3400     parameters.emplace_back(std::move(parameter));
3401     asyncResp->res.jsonValue["Parameters"] = std::move(parameters);
3402 }
3403 
handleSystemCollectionResetActionGet(crow::App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & systemName)3404 inline void handleSystemCollectionResetActionGet(
3405     crow::App& app, const crow::Request& req,
3406     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
3407     const std::string& systemName)
3408 {
3409     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
3410     {
3411         return;
3412     }
3413     if constexpr (BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM)
3414     {
3415         // Option currently returns no systems.  TBD
3416         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3417                                    systemName);
3418         return;
3419     }
3420 
3421     if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM)
3422     {
3423         if (systemName == "hypervisor")
3424         {
3425             handleHypervisorResetActionGet(asyncResp);
3426             return;
3427         }
3428     }
3429 
3430     if (systemName != BMCWEB_REDFISH_SYSTEM_URI_NAME)
3431     {
3432         messages::resourceNotFound(asyncResp->res, "ComputerSystem",
3433                                    systemName);
3434         return;
3435     }
3436 
3437     asyncResp->res.addHeader(
3438         boost::beast::http::field::link,
3439         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby");
3440 
3441     asyncResp->res.jsonValue["@odata.id"] =
3442         boost::urls::format("/redfish/v1/Systems/{}/ResetActionInfo",
3443                             BMCWEB_REDFISH_SYSTEM_URI_NAME);
3444     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo";
3445     asyncResp->res.jsonValue["Name"] = "Reset Action Info";
3446     asyncResp->res.jsonValue["Id"] = "ResetActionInfo";
3447 
3448     // Look to see if system defines AllowedHostTransitions
3449     sdbusplus::asio::getProperty<std::vector<std::string>>(
3450         *crow::connections::systemBus, "xyz.openbmc_project.State.Host",
3451         "/xyz/openbmc_project/state/host0", "xyz.openbmc_project.State.Host",
3452         "AllowedHostTransitions",
3453         [asyncResp](const boost::system::error_code& ec,
3454                     const std::vector<std::string>& allowedHostTransitions) {
3455             afterGetAllowedHostTransitions(asyncResp, ec,
3456                                            allowedHostTransitions);
3457         });
3458 }
3459 /**
3460  * SystemResetActionInfo derived class for delivering Computer Systems
3461  * ResetType AllowableValues using ResetInfo schema.
3462  */
requestRoutesSystems(App & app)3463 inline void requestRoutesSystems(App& app)
3464 {
3465     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3466         .privileges(redfish::privileges::headComputerSystemCollection)
3467         .methods(boost::beast::http::verb::head)(
3468             std::bind_front(handleComputerSystemCollectionHead, std::ref(app)));
3469 
3470     BMCWEB_ROUTE(app, "/redfish/v1/Systems/")
3471         .privileges(redfish::privileges::getComputerSystemCollection)
3472         .methods(boost::beast::http::verb::get)(
3473             std::bind_front(handleComputerSystemCollectionGet, std::ref(app)));
3474 
3475     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3476         .privileges(redfish::privileges::headComputerSystem)
3477         .methods(boost::beast::http::verb::head)(
3478             std::bind_front(handleComputerSystemHead, std::ref(app)));
3479 
3480     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3481         .privileges(redfish::privileges::getComputerSystem)
3482         .methods(boost::beast::http::verb::get)(
3483             std::bind_front(handleComputerSystemGet, std::ref(app)));
3484 
3485     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/")
3486         .privileges(redfish::privileges::patchComputerSystem)
3487         .methods(boost::beast::http::verb::patch)(
3488             std::bind_front(handleComputerSystemPatch, std::ref(app)));
3489 
3490     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/")
3491         .privileges(redfish::privileges::postComputerSystem)
3492         .methods(boost::beast::http::verb::post)(std::bind_front(
3493             handleComputerSystemResetActionPost, std::ref(app)));
3494 
3495     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3496         .privileges(redfish::privileges::headActionInfo)
3497         .methods(boost::beast::http::verb::head)(std::bind_front(
3498             handleSystemCollectionResetActionHead, std::ref(app)));
3499     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/")
3500         .privileges(redfish::privileges::getActionInfo)
3501         .methods(boost::beast::http::verb::get)(std::bind_front(
3502             handleSystemCollectionResetActionGet, std::ref(app)));
3503 }
3504 } // namespace redfish
3505