| /* | 
 | // Copyright (c) 2018 Intel Corporation | 
 | // | 
 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
 | // you may not use this file except in compliance with the License. | 
 | // You may obtain a copy of the License at | 
 | // | 
 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
 | // | 
 | // Unless required by applicable law or agreed to in writing, software | 
 | // distributed under the License is distributed on an "AS IS" BASIS, | 
 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | // See the License for the specific language governing permissions and | 
 | // limitations under the License. | 
 | */ | 
 | #pragma once | 
 |  | 
 | #include "bm_config.h" | 
 | #include "bmcweb_config.h" | 
 |  | 
 | #include "app.hpp" | 
 | #include "dbus_utility.hpp" | 
 | #include "health.hpp" | 
 | #include "hypervisor_system.hpp" | 
 | #include "led.hpp" | 
 | #include "managed_store.hpp" | 
 | #include "pcie.hpp" | 
 | #include "query.hpp" | 
 | #include "redfish_util.hpp" | 
 | #include "registries/privilege_registry.hpp" | 
 | #include "utils/boot_time_utils.hpp" | 
 | #include "utils/dbus_utils.hpp" | 
 | #include "utils/json_utils.hpp" | 
 | #include "utils/sw_utils.hpp" | 
 | #include "utils/time_utils.hpp" | 
 |  | 
 | #include <boost/container/flat_map.hpp> | 
 | #include <boost/system/error_code.hpp> | 
 | #include <sdbusplus/asio/property.hpp> | 
 | #include <sdbusplus/message/types.hpp> | 
 | #include <sdbusplus/unpack_properties.hpp> | 
 |  | 
 | #include <array> | 
 | #include <filesystem> | 
 | #include <iomanip> | 
 | #include <string_view> | 
 | #include <variant> | 
 |  | 
 | #ifdef UNIT_TEST_BUILD | 
 | #include "test/g3/mock_managed_store.hpp" // NOLINT | 
 | #endif | 
 |  | 
 | namespace redfish | 
 | { | 
 |  | 
 | const static std::array<std::pair<std::string_view, std::string_view>, 2> | 
 |     protocolToDBusForSystems{ | 
 |         {{"SSH", "obmc-console-ssh"}, {"IPMI", "phosphor-ipmi-net"}}}; | 
 |  | 
 | constexpr std::array<std::string_view, 1> systemInterfaces{ | 
 |     {"xyz.openbmc_project.Inventory.Item.System"}}; | 
 |  | 
 | constexpr std::array<std::string_view, 1> hostStateInterfaces{ | 
 |     {"xyz.openbmc_project.State.Host"}}; | 
 |  | 
 | /** | 
 |  * @brief Updates the Functional State of DIMMs | 
 |  * | 
 |  * @param[in] aResp Shared pointer for completing asynchronous calls | 
 |  * @param[in] dimmState Dimm's Functional state, true/false | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     updateDimmProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                          bool isDimmFunctional) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Dimm Functional: " << isDimmFunctional; | 
 |  | 
 |     // Set it as Enabled if at least one DIMM is functional | 
 |     // Update STATE only if previous State was DISABLED and current Dimm is | 
 |     // ENABLED. | 
 |     const nlohmann::json& prevMemSummary = | 
 |         aResp->res.jsonValue["MemorySummary"]["Status"]["State"]; | 
 |     if (prevMemSummary == "Disabled") | 
 |     { | 
 |         if (isDimmFunctional) | 
 |         { | 
 |             aResp->res.jsonValue["MemorySummary"]["Status"]["State"] = | 
 |                 "Enabled"; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * @brief Update "ProcessorSummary" "Count" based on Cpu PresenceState | 
 |  * | 
 |  * @param[in] aResp Shared pointer for completing asynchronous calls | 
 |  * @param[in] cpuPresenceState CPU present or not | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     modifyCpuPresenceState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                            bool isCpuPresent) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Cpu Present: " << isCpuPresent; | 
 |  | 
 |     if (isCpuPresent) | 
 |     { | 
 |         nlohmann::json& procCount = | 
 |             aResp->res.jsonValue["ProcessorSummary"]["Count"]; | 
 |         auto* procCountPtr = | 
 |             procCount.get_ptr<nlohmann::json::number_integer_t*>(); | 
 |         if (procCountPtr != nullptr) | 
 |         { | 
 |             // shouldn't be possible to be nullptr | 
 |             *procCountPtr += 1; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * @brief Update "ProcessorSummary" "Status" "State" based on | 
 |  *        CPU Functional State | 
 |  * | 
 |  * @param[in] aResp Shared pointer for completing asynchronous calls | 
 |  * @param[in] cpuFunctionalState is CPU functional true/false | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     modifyCpuFunctionalState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                              bool isCpuFunctional) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Cpu Functional: " << isCpuFunctional; | 
 |  | 
 |     const nlohmann::json& prevProcState = | 
 |         aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"]; | 
 |  | 
 |     // Set it as Enabled if at least one CPU is functional | 
 |     // Update STATE only if previous State was Non_Functional and current CPU is | 
 |     // Functional. | 
 |     if (prevProcState == "Disabled") | 
 |     { | 
 |         if (isCpuFunctional) | 
 |         { | 
 |             aResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = | 
 |                 "Enabled"; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | inline void getProcessorProperties( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |     const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>& | 
 |         properties) | 
 | { | 
 |  | 
 |     BMCWEB_LOG_DEBUG << "Got " << properties.size() << " Cpu properties."; | 
 |  | 
 |     // TODO: Get Model | 
 |  | 
 |     const uint16_t* coreCount = nullptr; | 
 |  | 
 |     const bool success = sdbusplus::unpackPropertiesNoThrow( | 
 |         dbus_utils::UnpackErrorPrinter(), properties, "CoreCount", coreCount); | 
 |  | 
 |     if (!success) | 
 |     { | 
 |         messages::internalError(aResp->res); | 
 |         return; | 
 |     } | 
 |  | 
 |     if (coreCount != nullptr) | 
 |     { | 
 |         nlohmann::json& coreCountJson = | 
 |             aResp->res.jsonValue["ProcessorSummary"]["CoreCount"]; | 
 |         uint64_t* coreCountJsonPtr = coreCountJson.get_ptr<uint64_t*>(); | 
 |  | 
 |         if (coreCountJsonPtr == nullptr) | 
 |         { | 
 |             coreCountJson = *coreCount; | 
 |         } | 
 |         else | 
 |         { | 
 |             *coreCountJsonPtr += *coreCount; | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | /* | 
 |  * @brief Get ProcessorSummary fields | 
 |  * | 
 |  * @param[in] aResp Shared pointer for completing asynchronous calls | 
 |  * @param[in] service dbus service for Cpu Information | 
 |  * @param[in] path dbus path for Cpu | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getProcessorSummary(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                                 const std::string& service, | 
 |                                 const std::string& path) | 
 | { | 
 |  | 
 |     auto getCpuPresenceState = [aResp](const boost::system::error_code& ec3, | 
 |                                        const bool cpuPresenceCheck) { | 
 |         if (ec3) | 
 |         { | 
 |             BMCWEB_LOG_ERROR << "DBUS response error " << ec3; | 
 |             return; | 
 |         } | 
 |         modifyCpuPresenceState(aResp, cpuPresenceCheck); | 
 |     }; | 
 |  | 
 |     auto getCpuFunctionalState = [aResp](const boost::system::error_code& ec3, | 
 |                                          const bool cpuFunctionalCheck) { | 
 |         if (ec3) | 
 |         { | 
 |             BMCWEB_LOG_ERROR << "DBUS response error " << ec3; | 
 |             return; | 
 |         } | 
 |         modifyCpuFunctionalState(aResp, cpuFunctionalCheck); | 
 |     }; | 
 |  | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |  | 
 |     // Get the Presence of CPU | 
 |     dbus_utils::getProperty<bool>( | 
 |         service, path, "xyz.openbmc_project.Inventory.Item", "Present", context, | 
 |         std::move(getCpuPresenceState)); | 
 |  | 
 |     // Get the Functional State | 
 |     dbus_utils::getProperty<bool>( | 
 |         service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus", | 
 |         "Functional", context, std::move(getCpuFunctionalState)); | 
 |  | 
 |     managedStore::GetManagedObjectStore()->getAllProperties( | 
 |         service, path, "xyz.openbmc_project.Inventory.Item.Cpu", context, | 
 |         [aResp, service, | 
 |          path](const boost::system::error_code& ec2, | 
 |                const dbus::utility::DBusPropertiesMap& properties) { | 
 |         if (ec2) | 
 |         { | 
 |             BMCWEB_LOG_ERROR << "DBUS response error " << ec2; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         getProcessorProperties(aResp, properties); | 
 |     }); | 
 | } | 
 |  | 
 | /* | 
 |  * @brief Retrieves computer system properties over dbus | 
 |  * | 
 |  * @param[in] aResp Shared pointer for completing asynchronous calls | 
 |  * @param[in] systemHealth  Shared HealthPopulate pointer | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     getComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                       const std::shared_ptr<HealthPopulate>& systemHealth) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get available system components."; | 
 |     constexpr std::array<std::string_view, 5> interfaces = { | 
 |         "xyz.openbmc_project.Inventory.Decorator.Asset", | 
 |         "xyz.openbmc_project.Inventory.Item.Cpu", | 
 |         "xyz.openbmc_project.Inventory.Item.Dimm", | 
 |         "xyz.openbmc_project.Inventory.Item.System", | 
 |         "xyz.openbmc_project.Common.UUID", | 
 |     }; | 
 |  | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/xyz/openbmc_project/inventory", 0, interfaces, context, | 
 |         [aResp, systemHealth, | 
 |          context](const boost::system::error_code& ec, | 
 |                   const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         // Iterate over all retrieved ObjectPaths. | 
 |         for (const std::pair< | 
 |                  std::string, | 
 |                  std::vector<std::pair<std::string, std::vector<std::string>>>>& | 
 |                  object : subtree) | 
 |         { | 
 |             const std::string& path = object.first; | 
 |             BMCWEB_LOG_DEBUG << "Got path: " << path; | 
 |             const std::vector<std::pair<std::string, std::vector<std::string>>>& | 
 |                 connectionNames = object.second; | 
 |             if (connectionNames.empty()) | 
 |             { | 
 |                 continue; | 
 |             } | 
 |  | 
 |             auto memoryHealth = std::make_shared<HealthPopulate>( | 
 |                 aResp, "/MemorySummary/Status"_json_pointer); | 
 |  | 
 |             auto cpuHealth = std::make_shared<HealthPopulate>( | 
 |                 aResp, "/ProcessorSummary/Status"_json_pointer); | 
 |  | 
 | #ifdef HEALTH_POPULATE | 
 |             systemHealth->children.emplace_back(memoryHealth); | 
 |             systemHealth->children.emplace_back(cpuHealth); | 
 | #endif | 
 |  | 
 |             // This is not system, so check if it's cpu, dimm, UUID or | 
 |             // BiosVer | 
 |             for (const auto& connection : connectionNames) | 
 |             { | 
 |                 for (const auto& interfaceName : connection.second) | 
 |                 { | 
 |                     if (interfaceName == | 
 |                         "xyz.openbmc_project.Inventory.Item.Dimm") | 
 |                     { | 
 |                         BMCWEB_LOG_DEBUG | 
 |                             << "Found Dimm, now get its properties."; | 
 |  | 
 |                         managedStore::GetManagedObjectStore()->getAllProperties( | 
 |                             connection.first, path, | 
 |                             "xyz.openbmc_project.Inventory.Item.Dimm", context, | 
 |                             [aResp, service{connection.first}, path, | 
 |                              context](const boost::system::error_code& ec2, | 
 |                                       const dbus::utility::DBusPropertiesMap& | 
 |                                           properties) { | 
 |                             if (ec2) | 
 |                             { | 
 |                                 BMCWEB_LOG_ERROR << "DBUS response error " | 
 |                                                  << ec2; | 
 |                                 messages::internalError(aResp->res); | 
 |                                 return; | 
 |                             } | 
 |                             BMCWEB_LOG_DEBUG << "Got " << properties.size() | 
 |                                              << " Dimm properties."; | 
 |  | 
 |                             if (properties.empty()) | 
 |                             { | 
 |                                 dbus_utils::getProperty<bool>( | 
 |                                     service, path, | 
 |                                     "xyz.openbmc_project.State." | 
 |                                     "Decorator.OperationalStatus", | 
 |                                     "Functional", context, | 
 |                                     [aResp]( | 
 |                                         const boost::system::error_code& ec3, | 
 |                                         bool dimmState) { | 
 |                                     if (ec3) | 
 |                                     { | 
 |                                         BMCWEB_LOG_ERROR | 
 |                                             << "DBUS response error " << ec3; | 
 |                                         return; | 
 |                                     } | 
 |                                     updateDimmProperties(aResp, dimmState); | 
 |                                 }); | 
 |                                 return; | 
 |                             } | 
 |  | 
 |                             const size_t* memorySizeInKB = nullptr; | 
 |  | 
 |                             const bool success = | 
 |                                 sdbusplus::unpackPropertiesNoThrow( | 
 |                                     dbus_utils::UnpackErrorPrinter(), | 
 |                                     properties, "MemorySizeInKB", | 
 |                                     memorySizeInKB); | 
 |  | 
 |                             if (!success) | 
 |                             { | 
 |                                 messages::internalError(aResp->res); | 
 |                                 return; | 
 |                             } | 
 |  | 
 |                             if (memorySizeInKB != nullptr) | 
 |                             { | 
 |                                 nlohmann::json& totalMemory = | 
 |                                     aResp->res | 
 |                                         .jsonValue["MemorySummary"] | 
 |                                                   ["TotalSystemMemoryGiB"]; | 
 |                                 const uint64_t* preValue = | 
 |                                     totalMemory.get_ptr<const uint64_t*>(); | 
 |                                 if (preValue == nullptr) | 
 |                                 { | 
 |                                     aResp->res | 
 |                                         .jsonValue["MemorySummary"] | 
 |                                                   ["TotalSystemMemoryGiB"] = | 
 |                                         *memorySizeInKB / | 
 |                                         static_cast<size_t>(1024 * 1024); | 
 |                                 } | 
 |                                 else | 
 |                                 { | 
 |                                     aResp->res | 
 |                                         .jsonValue["MemorySummary"] | 
 |                                                   ["TotalSystemMemoryGiB"] = | 
 |                                         *memorySizeInKB / | 
 |                                             static_cast<size_t>(1024 * 1024) + | 
 |                                         *preValue; | 
 |                                 } | 
 |                                 aResp->res.jsonValue["MemorySummary"]["Status"] | 
 |                                                     ["State"] = "Enabled"; | 
 |                             } | 
 |                         }); | 
 |  | 
 |                         memoryHealth->inventory.emplace_back(path); | 
 |                     } | 
 |                     else if (interfaceName == | 
 |                              "xyz.openbmc_project.Inventory.Item.Cpu") | 
 |                     { | 
 |                         BMCWEB_LOG_DEBUG | 
 |                             << "Found Cpu, now get its properties."; | 
 |  | 
 |                         getProcessorSummary(aResp, connection.first, path); | 
 |  | 
 |                         cpuHealth->inventory.emplace_back(path); | 
 |                     } | 
 |                     else if (interfaceName == "xyz.openbmc_project.Common.UUID") | 
 |                     { | 
 |                         BMCWEB_LOG_DEBUG | 
 |                             << "Found UUID, now get its properties."; | 
 |  | 
 |                         managedStore::GetManagedObjectStore()->getAllProperties( | 
 |                             connection.first, path, | 
 |                             "xyz.openbmc_project.Common.UUID", context, | 
 |                             [aResp](const boost::system::error_code& ec3, | 
 |                                     const dbus::utility::DBusPropertiesMap& | 
 |                                         properties) { | 
 |                             if (ec3) | 
 |                             { | 
 |                                 BMCWEB_LOG_DEBUG << "DBUS response error " | 
 |                                                  << ec3; | 
 |                                 messages::internalError(aResp->res); | 
 |                                 return; | 
 |                             } | 
 |                             BMCWEB_LOG_DEBUG << "Got " << properties.size() | 
 |                                              << " UUID properties."; | 
 |  | 
 |                             const std::string* uUID = nullptr; | 
 |  | 
 |                             const bool success = | 
 |                                 sdbusplus::unpackPropertiesNoThrow( | 
 |                                     dbus_utils::UnpackErrorPrinter(), | 
 |                                     properties, "UUID", uUID); | 
 |  | 
 |                             if (!success) | 
 |                             { | 
 |                                 messages::internalError(aResp->res); | 
 |                                 return; | 
 |                             } | 
 |  | 
 |                             if (uUID != nullptr) | 
 |                             { | 
 |                                 std::string valueStr = *uUID; | 
 |                                 if (valueStr.size() == 32) | 
 |                                 { | 
 |                                     valueStr.insert(8, 1, '-'); | 
 |                                     valueStr.insert(13, 1, '-'); | 
 |                                     valueStr.insert(18, 1, '-'); | 
 |                                     valueStr.insert(23, 1, '-'); | 
 |                                 } | 
 |                                 BMCWEB_LOG_DEBUG << "UUID = " << valueStr; | 
 |                                 aResp->res.jsonValue["UUID"] = valueStr; | 
 |                             } | 
 |                         }); | 
 |                     } | 
 |                     else if (interfaceName == | 
 |                              "xyz.openbmc_project.Inventory.Item.System") | 
 |                     { | 
 |                         managedStore::GetManagedObjectStore()->getAllProperties( | 
 |                             connection.first, path, | 
 |                             "xyz.openbmc_project.Inventory.Decorator.Asset", | 
 |                             context, | 
 |                             [aResp, | 
 |                              context](const boost::system::error_code& ec2, | 
 |                                       const dbus::utility::DBusPropertiesMap& | 
 |                                           propertiesList) { | 
 |                             if (ec2) | 
 |                             { | 
 |                                 // doesn't have to include this | 
 |                                 // interface | 
 |                                 return; | 
 |                             } | 
 |                             BMCWEB_LOG_DEBUG << "Got " << propertiesList.size() | 
 |                                              << " properties for system"; | 
 |  | 
 |                             const std::string* partNumber = nullptr; | 
 |                             const std::string* serialNumber = nullptr; | 
 |                             const std::string* manufacturer = nullptr; | 
 |                             const std::string* model = nullptr; | 
 |                             const std::string* subModel = nullptr; | 
 |  | 
 |                             const bool success = | 
 |                                 sdbusplus::unpackPropertiesNoThrow( | 
 |                                     dbus_utils::UnpackErrorPrinter(), | 
 |                                     propertiesList, "PartNumber", partNumber, | 
 |                                     "SerialNumber", serialNumber, | 
 |                                     "Manufacturer", manufacturer, "Model", | 
 |                                     model, "SubModel", subModel); | 
 |  | 
 |                             if (!success) | 
 |                             { | 
 |                                 messages::internalError(aResp->res); | 
 |                                 return; | 
 |                             } | 
 |  | 
 |                             if (partNumber != nullptr) | 
 |                             { | 
 |                                 aResp->res.jsonValue["PartNumber"] = | 
 |                                     *partNumber; | 
 |                             } | 
 |  | 
 |                             if (serialNumber != nullptr) | 
 |                             { | 
 |                                 aResp->res.jsonValue["SerialNumber"] = | 
 |                                     *serialNumber; | 
 |                             } | 
 |  | 
 |                             if (manufacturer != nullptr) | 
 |                             { | 
 |                                 aResp->res.jsonValue["Manufacturer"] = | 
 |                                     *manufacturer; | 
 |                             } | 
 |  | 
 |                             if (model != nullptr) | 
 |                             { | 
 |                                 aResp->res.jsonValue["Model"] = *model; | 
 |                             } | 
 |  | 
 |                             if (subModel != nullptr) | 
 |                             { | 
 |                                 aResp->res.jsonValue["SubModel"] = *subModel; | 
 |                             } | 
 |  | 
 |                             // Grab the bios version | 
 |                             sw_util::populateSoftwareInformation( | 
 |                                 aResp, sw_util::biosPurpose, "BiosVersion", | 
 |                                 false); | 
 |                         }); | 
 |  | 
 |                         dbus_utils::getProperty<std::string>( | 
 |                             connection.first, path, | 
 |                             "xyz.openbmc_project.Inventory.Decorator." | 
 |                             "AssetTag", | 
 |                             "AssetTag", context, | 
 |                             [aResp](const boost::system::error_code& ec2, | 
 |                                     const std::string& value) { | 
 |                             if (ec2) | 
 |                             { | 
 |                                 // doesn't have to include this | 
 |                                 // interface | 
 |                                 return; | 
 |                             } | 
 |  | 
 |                             aResp->res.jsonValue["AssetTag"] = value; | 
 |                         }); | 
 |                     } | 
 |                 } | 
 |                 break; | 
 |             } | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | inline void populateHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                               const std::string& service, | 
 |                               const std::string& path) | 
 | { | 
 |  | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         service, path, "xyz.openbmc_project.State.Host", "CurrentHostState", | 
 |         context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& hostState) { | 
 |         if (ec) | 
 |         { | 
 |             if (ec == boost::system::errc::host_unreachable) | 
 |             { | 
 |                 // Service not available, no error, just don't return | 
 |                 // host state info | 
 |                 BMCWEB_LOG_DEBUG << "Service not available " << ec; | 
 |                 return; | 
 |             } | 
 |             BMCWEB_LOG_ERROR << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Host state: " << hostState; | 
 |         // Verify Host State | 
 |         if (hostState == "xyz.openbmc_project.State.Host.HostState.Running") | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "On"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "Enabled"; | 
 |         } | 
 |         else if (hostState == | 
 |                  "xyz.openbmc_project.State.Host.HostState.Quiesced") | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "On"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "Quiesced"; | 
 |         } | 
 |         else if (hostState == | 
 |                  "xyz.openbmc_project.State.Host.HostState.DiagnosticMode") | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "On"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "InTest"; | 
 |         } | 
 |         else if ( | 
 |             hostState == | 
 |             "xyz.openbmc_project.State.Host.HostState.TransitioningToRunning") | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "PoweringOn"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "Starting"; | 
 |         } | 
 |         else if (hostState == | 
 |                  "xyz.openbmc_project.State.Host.HostState.TransitioningToOff") | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "PoweringOff"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "Disabled"; | 
 |         } | 
 |         else | 
 |         { | 
 |             aResp->res.jsonValue["PowerState"] = "Off"; | 
 |             aResp->res.jsonValue["Status"]["State"] = "Disabled"; | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves host state properties over dbus | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getHostState(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                          const std::string& systemPath, | 
 |                          const dbus::utility::MapperGetSubTreeResponse& objects) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get host information."; | 
 |  | 
 |     // For single host systems, the path is hardcoded to be | 
 |     // /xyz/openbmc_project/state/host0 and the service is | 
 |     // xyz.openbmc_project.State.Host | 
 |     if (systemPath.empty()) | 
 |     { | 
 |         populateHostState(aResp, "xyz.openbmc_project.State.Host", | 
 |                           "/xyz/openbmc_project/state/host0"); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Objects should never be empty in a multi-host system | 
 |     if (objects.empty()) | 
 |     { | 
 |         BMCWEB_LOG_ERROR << "Host has no Power Control Objects"; | 
 |         messages::internalError(aResp->res); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Map1: [key, val] -> [objectPath, Map2] | 
 |     // Map2: [key, val] -> [serviceName, list of interfaces] | 
 |     const std::string powerControlPath = objects[0].first; | 
 |  | 
 |     // This object path can have multiple services, we need the one that | 
 |     // contains "State.Host" | 
 |     for (const auto& serviceMapping : objects[0].second) | 
 |     { | 
 |         if (absl::StrContains(serviceMapping.first, "State.Host")) | 
 |         { | 
 |             populateHostState(aResp, serviceMapping.first, powerControlPath); | 
 |             return; | 
 |         } | 
 |     } | 
 |  | 
 |     BMCWEB_LOG_ERROR << "Could not find correct host Power Control Object"; | 
 |     messages::internalError(aResp->res); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates boot source DBUS property value to redfish. | 
 |  * | 
 |  * @param[in] dbusSource    The boot source in DBUS speak. | 
 |  * | 
 |  * @return Returns as a string, the boot source in Redfish terms. If translation | 
 |  * cannot be done, returns an empty string. | 
 |  */ | 
 | inline std::string dbusToRfBootSource(const std::string& dbusSource) | 
 | { | 
 |     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Default") | 
 |     { | 
 |         return "None"; | 
 |     } | 
 |     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Disk") | 
 |     { | 
 |         return "Hdd"; | 
 |     } | 
 |     if (dbusSource == | 
 |         "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia") | 
 |     { | 
 |         return "Cd"; | 
 |     } | 
 |     if (dbusSource == "xyz.openbmc_project.Control.Boot.Source.Sources.Network") | 
 |     { | 
 |         return "Pxe"; | 
 |     } | 
 |     if (dbusSource == | 
 |         "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia") | 
 |     { | 
 |         return "Usb"; | 
 |     } | 
 |     return ""; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates boot type DBUS property value to redfish. | 
 |  * | 
 |  * @param[in] dbusType    The boot type in DBUS speak. | 
 |  * | 
 |  * @return Returns as a string, the boot type in Redfish terms. If translation | 
 |  * cannot be done, returns an empty string. | 
 |  */ | 
 | inline std::string dbusToRfBootType(const std::string& dbusType) | 
 | { | 
 |     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.Legacy") | 
 |     { | 
 |         return "Legacy"; | 
 |     } | 
 |     if (dbusType == "xyz.openbmc_project.Control.Boot.Type.Types.EFI") | 
 |     { | 
 |         return "UEFI"; | 
 |     } | 
 |     return ""; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates boot mode DBUS property value to redfish. | 
 |  * | 
 |  * @param[in] dbusMode    The boot mode in DBUS speak. | 
 |  * | 
 |  * @return Returns as a string, the boot mode in Redfish terms. If translation | 
 |  * cannot be done, returns an empty string. | 
 |  */ | 
 | inline std::string dbusToRfBootMode(const std::string& dbusMode) | 
 | { | 
 |     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") | 
 |     { | 
 |         return "None"; | 
 |     } | 
 |     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe") | 
 |     { | 
 |         return "Diags"; | 
 |     } | 
 |     if (dbusMode == "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup") | 
 |     { | 
 |         return "BiosSetup"; | 
 |     } | 
 |     return ""; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates boot progress DBUS property value to redfish. | 
 |  * | 
 |  * @param[in] dbusBootProgress    The boot progress in DBUS speak. | 
 |  * | 
 |  * @return Returns as a string, the boot progress in Redfish terms. If | 
 |  *         translation cannot be done, returns "None". | 
 |  */ | 
 | inline std::string dbusToRfBootProgress(const std::string& dbusBootProgress) | 
 | { | 
 |     // Now convert the D-Bus BootProgress to the appropriate Redfish | 
 |     // enum | 
 |     std::string rfBpLastState = "None"; | 
 |     if (dbusBootProgress == "xyz.openbmc_project.State.Boot.Progress." | 
 |                             "ProgressStages.Unspecified") | 
 |     { | 
 |         rfBpLastState = "None"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "PrimaryProcInit") | 
 |     { | 
 |         rfBpLastState = "PrimaryProcessorInitializationStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "BusInit") | 
 |     { | 
 |         rfBpLastState = "BusInitializationStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "MemoryInit") | 
 |     { | 
 |         rfBpLastState = "MemoryInitializationStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "SecondaryProcInit") | 
 |     { | 
 |         rfBpLastState = "SecondaryProcessorInitializationStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "PCIInit") | 
 |     { | 
 |         rfBpLastState = "PCIResourceConfigStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "SystemSetup") | 
 |     { | 
 |         rfBpLastState = "SetupEntered"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "SystemInitComplete") | 
 |     { | 
 |         rfBpLastState = "SystemHardwareInitializationComplete"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "OSStart") | 
 |     { | 
 |         rfBpLastState = "OSBootStarted"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "OSRunning") | 
 |     { | 
 |         rfBpLastState = "OSRunning"; | 
 |     } | 
 |     else if (dbusBootProgress == | 
 |              "xyz.openbmc_project.State.Boot.Progress.ProgressStages." | 
 |              "OEM") | 
 |     { | 
 |         rfBpLastState = "OEM"; | 
 |     } | 
 |     else | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Unsupported D-Bus BootProgress " | 
 |                          << dbusBootProgress; | 
 |         // Just return the default | 
 |     } | 
 |     return rfBpLastState; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates boot source from Redfish to the DBus boot paths. | 
 |  * | 
 |  * @param[in] rfSource    The boot source in Redfish. | 
 |  * @param[out] bootSource The DBus source | 
 |  * @param[out] bootMode   the DBus boot mode | 
 |  * | 
 |  * @return Integer error code. | 
 |  */ | 
 | inline int assignBootParameters(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                                 const std::string& rfSource, | 
 |                                 std::string& bootSource, std::string& bootMode) | 
 | { | 
 |     bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Default"; | 
 |     bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; | 
 |  | 
 |     if (rfSource == "None") | 
 |     { | 
 |         return 0; | 
 |     } | 
 |     if (rfSource == "Pxe") | 
 |     { | 
 |         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Network"; | 
 |     } | 
 |     else if (rfSource == "Hdd") | 
 |     { | 
 |         bootSource = "xyz.openbmc_project.Control.Boot.Source.Sources.Disk"; | 
 |     } | 
 |     else if (rfSource == "Diags") | 
 |     { | 
 |         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Safe"; | 
 |     } | 
 |     else if (rfSource == "Cd") | 
 |     { | 
 |         bootSource = | 
 |             "xyz.openbmc_project.Control.Boot.Source.Sources.ExternalMedia"; | 
 |     } | 
 |     else if (rfSource == "BiosSetup") | 
 |     { | 
 |         bootMode = "xyz.openbmc_project.Control.Boot.Mode.Modes.Setup"; | 
 |     } | 
 |     else if (rfSource == "Usb") | 
 |     { | 
 |         bootSource = | 
 |             "xyz.openbmc_project.Control.Boot.Source.Sources.RemovableMedia"; | 
 |     } | 
 |     else | 
 |     { | 
 |         BMCWEB_LOG_DEBUG | 
 |             << "Invalid property value for BootSourceOverrideTarget: " | 
 |             << bootSource; | 
 |         messages::propertyValueNotInList(aResp->res, rfSource, | 
 |                                          "BootSourceTargetOverride"); | 
 |         return -1; | 
 |     } | 
 |     return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot progress of the system | 
 |  * | 
 |  * @param[in] aResp  Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getBootProgress(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", | 
 |         "xyz.openbmc_project.State.Boot.Progress", "BootProgress", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& bootProgressStr) { | 
 |         if (ec) | 
 |         { | 
 |             // BootProgress is an optional object so just do nothing if | 
 |             // not found | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Boot Progress: " << bootProgressStr; | 
 |  | 
 |         aResp->res.jsonValue["BootProgress"]["LastState"] = | 
 |             dbusToRfBootProgress(bootProgressStr); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot progress Last Update of the system | 
 |  * | 
 |  * @param[in] aResp  Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getBootProgressLastStateTime( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<uint64_t>( | 
 |         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", | 
 |         "xyz.openbmc_project.State.Boot.Progress", "BootProgressLastUpdate", | 
 |         context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const uint64_t lastStateTime) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; | 
 |             return; | 
 |         } | 
 |  | 
 |         // BootProgressLastUpdate is the last time the BootProgress property | 
 |         // was updated. The time is the Epoch time, number of microseconds | 
 |         // since 1 Jan 1970 00::00::00 UTC." | 
 |         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/master/ | 
 |         // yaml/xyz/openbmc_project/State/Boot/Progress.interface.yaml#L11 | 
 |  | 
 |         // Convert to ISO 8601 standard | 
 |         aResp->res.jsonValue["BootProgress"]["LastStateTime"] = | 
 |             redfish::time_utils::getDateTimeUintUs(lastStateTime); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot progress OemLastState of the system | 
 |  * | 
 |  * @param[in] aResp  Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     getBootProgressOemLastState(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     /* Check the boot progress LastState */ | 
 |     managedStore::ManagedObjectStoreContext requestContext(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0", | 
 |         "xyz.openbmc_project.State.Boot.Progress", "BootProgress", | 
 |         requestContext, | 
 |         [aResp, requestContext](const boost::system::error_code ec, | 
 |                 const std::string& bootProgressStr) { | 
 |         if (ec) | 
 |         { | 
 |             // BootProgress is an optional object so just do nothing if | 
 |             // not found | 
 |             return; | 
 |         } | 
 |         /* The OemLastState only present if LastState is "OEM" */ | 
 |         if (dbusToRfBootProgress(bootProgressStr) == "OEM") | 
 |         { | 
 |             // TODO: Move to dbus_utils::getProperty once tuple support is added | 
 |             // b/293925308 | 
 |             dbus_utils::getProperty< | 
 |                 std::tuple<uint64_t, std::vector<uint8_t>>>( | 
 |                 "xyz.openbmc_project.State.Boot.Raw", | 
 |                 "/xyz/openbmc_project/state/boot/raw0", | 
 |                 "xyz.openbmc_project.State.Boot.Raw", "Value", | 
 |                 requestContext, | 
 |                 [aResp](const boost::system::error_code ec2, | 
 |                         const std::tuple<uint64_t, std::vector<uint8_t>>& | 
 |                             bootProgressOemLastState) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     return; | 
 |                 } | 
 |  | 
 |                 std::string bootProgressOemLastStateStr = "0x"; | 
 |                 std::stringstream tmp; | 
 |                 uint64_t bootProgress1st = 0; | 
 |                 std::vector<uint8_t> bootProgress2nd; | 
 |  | 
 |                 /* The OemLastState updated to the PostCodes Boot.Raw: | 
 |                  * https://github.com/openbmc/phosphor-dbus-interfaces/blob/ | 
 |                  * master/yaml/xyz/openbmc_project/State/Boot/Raw.interface.yaml#L6 | 
 |                  * The type of the Boot.Raw value is struct[uint64,array[byte]] | 
 |                  */ | 
 |                 bootProgress1st = std::get<0>(bootProgressOemLastState); | 
 |                 bootProgress2nd = std::get<1>(bootProgressOemLastState); | 
 |                 /* Formatting boot progress code */ | 
 |                 tmp << std::hex << std::setfill('0'); | 
 |  | 
 |                 /* Set "OemLastState": to "" if there is no bootprogress code */ | 
 |                 if (bootProgress1st == 0) | 
 |                 { | 
 |                     bootProgressOemLastStateStr = ""; | 
 |                 } | 
 |                 else | 
 |                 { | 
 |                     /* Get first bytes of the boot progress code */ | 
 |                     tmp << std::setw(2) | 
 |                         << static_cast<uint64_t>(bootProgress1st); | 
 |  | 
 |                     if (!bootProgress2nd.empty()) | 
 |                     { | 
 |                         /* Get the last byte of the boot progress code */ | 
 |                         for (uint8_t i : bootProgress2nd) | 
 |                         { | 
 |                             tmp << std::setw(2) << static_cast<uint16_t>(i); | 
 |                         } | 
 |                     } | 
 |                     /* Padding, Ex: 0x1020304 to 0x01020304 */ | 
 |                     if ((tmp.str().size() % 2) != 0) | 
 |                     { | 
 |                         bootProgressOemLastStateStr = "0x0"; | 
 |                     } | 
 |                     bootProgressOemLastStateStr += tmp.str(); | 
 |                 } | 
 |  | 
 |                 aResp->res.jsonValue["BootProgress"]["OemLastState"] = | 
 |                     bootProgressOemLastStateStr; | 
 |             }); | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot override type over DBUS and fills out the response | 
 |  * | 
 |  * @param[in] aResp         Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 |  | 
 | inline void getBootOverrideType(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "xyz.openbmc_project.Control.Boot.Type", "BootType", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& bootType) { | 
 |         if (ec) | 
 |         { | 
 |             // not an error, don't have to have the interface | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Boot type: " << bootType; | 
 |  | 
 |         aResp->res.jsonValue["Boot"] | 
 |                             ["BootSourceOverrideMode@Redfish.AllowableValues"] = | 
 |             nlohmann::json::array_t({"Legacy", "UEFI"}); | 
 |  | 
 |         auto rfType = dbusToRfBootType(bootType); | 
 |         if (rfType.empty()) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         aResp->res.jsonValue["Boot"]["BootSourceOverrideMode"] = rfType; | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot override mode over DBUS and fills out the response | 
 |  * | 
 |  * @param[in] aResp         Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 |  | 
 | inline void getBootOverrideMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "xyz.openbmc_project.Control.Boot.Mode", "BootMode", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& bootModeStr) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Boot mode: " << bootModeStr; | 
 |  | 
 |         aResp->res | 
 |             .jsonValue["Boot"] | 
 |                       ["BootSourceOverrideTarget@Redfish.AllowableValues"] = { | 
 |             "None", "Pxe", "Hdd", "Cd", "Diags", "BiosSetup", "Usb"}; | 
 |  | 
 |         if (bootModeStr != | 
 |             "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular") | 
 |         { | 
 |             auto rfMode = dbusToRfBootMode(bootModeStr); | 
 |             if (!rfMode.empty()) | 
 |             { | 
 |                 aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = | 
 |                     rfMode; | 
 |             } | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot override source over DBUS | 
 |  * | 
 |  * @param[in] aResp         Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 |  | 
 | inline void | 
 |     getBootOverrideSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "xyz.openbmc_project.Control.Boot.Source", "BootSource", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& bootSourceStr) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             if (ec.value() == boost::asio::error::host_unreachable) | 
 |             { | 
 |                 return; | 
 |             } | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Boot source: " << bootSourceStr; | 
 |  | 
 |         auto rfSource = dbusToRfBootSource(bootSourceStr); | 
 |         if (!rfSource.empty()) | 
 |         { | 
 |             aResp->res.jsonValue["Boot"]["BootSourceOverrideTarget"] = rfSource; | 
 |         } | 
 |  | 
 |         // Get BootMode as BootSourceOverrideTarget is constructed | 
 |         // from both BootSource and BootMode | 
 |         getBootOverrideMode(aResp); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief This functions abstracts all the logic behind getting a | 
 |  * "BootSourceOverrideEnabled" property from an overall boot override enable | 
 |  * state | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 |  | 
 | inline void | 
 |     processBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                               const bool bootOverrideEnableSetting) | 
 | { | 
 |     if (!bootOverrideEnableSetting) | 
 |     { | 
 |         aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Disabled"; | 
 |         return; | 
 |     } | 
 |  | 
 |     // If boot source override is enabled, we need to check 'one_time' | 
 |     // property to set a correct value for the "BootSourceOverrideEnabled" | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<bool>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot/one_time", | 
 |         "xyz.openbmc_project.Object.Enable", "Enabled", context, | 
 |         [aResp](const boost::system::error_code& ec, bool oneTimeSetting) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         if (oneTimeSetting) | 
 |         { | 
 |             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = "Once"; | 
 |         } | 
 |         else | 
 |         { | 
 |             aResp->res.jsonValue["Boot"]["BootSourceOverrideEnabled"] = | 
 |                 "Continuous"; | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot override enable over DBUS | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 |  | 
 | inline void | 
 |     getBootOverrideEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<bool>("xyz.openbmc_project.Settings", | 
 |                                   "/xyz/openbmc_project/control/host0/boot", | 
 |                                   "xyz.openbmc_project.Object.Enable", | 
 |                                   "Enabled", context, | 
 |                                   [aResp](const boost::system::error_code& ec, | 
 |                                           const bool bootOverrideEnable) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             if (ec.value() == boost::asio::error::host_unreachable) | 
 |             { | 
 |                 return; | 
 |             } | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         processBootOverrideEnable(aResp, bootOverrideEnable); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves boot source override properties | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get boot information."; | 
 |  | 
 |     getBootOverrideSource(aResp); | 
 |     getBootOverrideType(aResp); | 
 |     getBootOverrideEnable(aResp); | 
 | } | 
 |  | 
 | inline void | 
 |     populateLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                           const std::string& service, const std::string& path) | 
 | { | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<uint64_t>( | 
 |         service, path, "xyz.openbmc_project.State.Chassis", | 
 |         "LastStateChangeTime", context, | 
 |         [aResp](const boost::system::error_code& ec, uint64_t lastResetTime) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; | 
 |             return; | 
 |         } | 
 |  | 
 |         // LastStateChangeTime is epoch time, in milliseconds | 
 |         // https://github.com/openbmc/phosphor-dbus-interfaces/blob/33e8e1dd64da53a66e888d33dc82001305cd0bf9/xyz/openbmc_project/State/Chassis.interface.yaml#L19 | 
 |         uint64_t lastResetTimeStamp = lastResetTime / 1000; | 
 |  | 
 |         // Convert to ISO 8601 standard | 
 |         aResp->res.jsonValue["LastResetTime"] = | 
 |             redfish::time_utils::getDateTimeUint(lastResetTimeStamp); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves the Last Reset Time | 
 |  * | 
 |  * "Reset" is an overloaded term in Redfish, "Reset" includes power on | 
 |  * and power off. Even though this is the "system" Redfish object look at the | 
 |  * chassis D-Bus interface for the LastStateChangeTime since this has the | 
 |  * last power operation time. | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     getLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                      const std::string& systemPath, | 
 |                      const dbus::utility::MapperGetSubTreeResponse& objects) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Getting System Last Reset Time"; | 
 |  | 
 |     // Single system hardcodes chassis power control object | 
 |     if (systemPath.empty()) | 
 |     { | 
 |         populateLastResetTime(aResp, "xyz.openbmc_project.State.Chassis", | 
 |                               "/xyz/openbmc_project/state/chassis0"); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Objects should never be empty in a multi-host system | 
 |     if (objects.empty()) | 
 |     { | 
 |         BMCWEB_LOG_ERROR << "Host has no Power Control Objects"; | 
 |         messages::internalError(aResp->res); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Map1: [key, val] -> [objectPath, Map2] | 
 |     // Map2: [key, val] -> [serviceName, list of interfaces] | 
 |     const std::string powerControlPath = objects[0].first; | 
 |  | 
 |     // This object path can have multiple services, we need the one that | 
 |     // contains "State.Host" | 
 |     for (const auto& serviceMapping : objects[0].second) | 
 |     { | 
 |         if (absl::StrContains(serviceMapping.first, "State.Chassis")) | 
 |         { | 
 |             populateLastResetTime(aResp, serviceMapping.first, | 
 |                                   powerControlPath); | 
 |             return; | 
 |         } | 
 |     } | 
 |  | 
 |     BMCWEB_LOG_ERROR << "Could not find correct chassis Power Control Object"; | 
 |     messages::internalError(aResp->res); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves Automatic Retry properties. Known on D-Bus as AutoReboot. | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get Automatic Retry policy"; | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<bool>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/auto_reboot", | 
 |         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", context, | 
 |         [aResp, context](const boost::system::error_code& ec, | 
 |                          bool autoRebootEnabled) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Auto Reboot: " << autoRebootEnabled; | 
 |         if (autoRebootEnabled) | 
 |         { | 
 |             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = | 
 |                 "RetryAttempts"; | 
 |             // If AutomaticRetry (AutoReboot) is enabled see how many | 
 |             // attempts are left | 
 |             dbus_utils::getProperty<uint32_t>( | 
 |                 "xyz.openbmc_project.State.Host", | 
 |                 "/xyz/openbmc_project/state/host0", | 
 |                 "xyz.openbmc_project.Control.Boot.RebootAttempts", | 
 |                 "AttemptsLeft", context, | 
 |                 [aResp](const boost::system::error_code& ec2, | 
 |                         const uint32_t autoRebootAttemptsLeft) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "D-BUS response error " << ec2; | 
 |                     return; | 
 |                 } | 
 |  | 
 |                 BMCWEB_LOG_DEBUG << "Auto Reboot Attempts Left: " | 
 |                                  << autoRebootAttemptsLeft; | 
 |  | 
 |                 aResp->res | 
 |                     .jsonValue["Boot"]["RemainingAutomaticRetryAttempts"] = | 
 |                     autoRebootAttemptsLeft; | 
 |             }); | 
 |         } | 
 |         else | 
 |         { | 
 |             aResp->res.jsonValue["Boot"]["AutomaticRetryConfig"] = "Disabled"; | 
 |         } | 
 |  | 
 |         // Not on D-Bus. Hardcoded here: | 
 |         // https://github.com/openbmc/phosphor-state-manager/blob/1dbbef42675e94fb1f78edb87d6b11380260535a/meson_options.txt#L71 | 
 |         aResp->res.jsonValue["Boot"]["AutomaticRetryAttempts"] = 3; | 
 |  | 
 |         // "AutomaticRetryConfig" can be 3 values, Disabled, RetryAlways, | 
 |         // and RetryAttempts. OpenBMC only supports Disabled and | 
 |         // RetryAttempts. | 
 |         aResp->res.jsonValue["Boot"] | 
 |                             ["AutomaticRetryConfig@Redfish.AllowableValues"] = { | 
 |             "Disabled", "RetryAttempts"}; | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves power restore policy over DBUS. | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     getPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get power restore policy"; | 
 |  | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/power_restore_policy", | 
 |         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", | 
 |         context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const std::string& policy) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             return; | 
 |         } | 
 |  | 
 |         const boost::container::flat_map<std::string, std::string> policyMaps = { | 
 |             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn", | 
 |              "AlwaysOn"}, | 
 |             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff", | 
 |              "AlwaysOff"}, | 
 |             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore", | 
 |              "LastState"}, | 
 |             // Return `AlwaysOff` when power restore policy set to "None" | 
 |             {"xyz.openbmc_project.Control.Power.RestorePolicy.Policy.None", | 
 |              "AlwaysOff"}}; | 
 |  | 
 |         auto policyMapsIt = policyMaps.find(policy); | 
 |         if (policyMapsIt == policyMaps.end()) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         aResp->res.jsonValue["PowerRestorePolicy"] = policyMapsIt->second; | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Get TrustedModuleRequiredToBoot property. Determines whether or not | 
 |  * TPM is required for booting the host. | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getTrustedModuleRequiredToBoot( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get TPM required to boot."; | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.TPM.Policy"}; | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, context, | 
 |         [aResp, | 
 |          context](const boost::system::error_code& ec, | 
 |                   const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree" | 
 |                              << ec; | 
 |             // This is an optional D-Bus object so just return if | 
 |             // error occurs | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             // As noted above, this is an optional interface so just return | 
 |             // if there is no instance found | 
 |             return; | 
 |         } | 
 |  | 
 |         /* When there is more than one TPMEnable object... */ | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "DBUS response has more than 1 TPM Enable object:" | 
 |                 << subtree.size(); | 
 |             // Throw an internal Error and return | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // Make sure the Dbus response map has a service and objectPath | 
 |         // field | 
 |         if (subtree[0].first.empty() || subtree[0].second.size() != 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& serv = subtree[0].second.begin()->first; | 
 |  | 
 |         // Valid TPM Enable object found, now reading the current value | 
 |         dbus_utils::getProperty<bool>( | 
 |             serv, path, "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", | 
 |             context, | 
 |             [aResp](const boost::system::error_code& ec2, bool tpmRequired) { | 
 |             if (ec2) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG << "D-BUS response error on TPM.Policy Get" | 
 |                                  << ec2; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             if (tpmRequired) | 
 |             { | 
 |                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = | 
 |                     "Required"; | 
 |             } | 
 |             else | 
 |             { | 
 |                 aResp->res.jsonValue["Boot"]["TrustedModuleRequiredToBoot"] = | 
 |                     "Disabled"; | 
 |             } | 
 |         }); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Set TrustedModuleRequiredToBoot property. Determines whether or not | 
 |  * TPM is required for booting the host. | 
 |  * | 
 |  * @param[in] aResp         Shared pointer for generating response message. | 
 |  * @param[in] tpmRequired   Value to set TPM Required To Boot property to. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setTrustedModuleRequiredToBoot( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& aResp, const bool tpmRequired) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot."; | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.TPM.Policy"}; | 
 |     managedStore::ManagedObjectStoreContext requestContext(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, requestContext, | 
 |         [aResp, | 
 |          tpmRequired](const boost::system::error_code& ec, | 
 |                       const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error on TPM.Policy GetSubTree" | 
 |                              << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             messages::propertyValueNotInList(aResp->res, "ComputerSystem", | 
 |                                              "TrustedModuleRequiredToBoot"); | 
 |             return; | 
 |         } | 
 |  | 
 |         /* When there is more than one TPMEnable object... */ | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "DBUS response has more than 1 TPM Enable object:" | 
 |                 << subtree.size(); | 
 |             // Throw an internal Error and return | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // Make sure the Dbus response map has a service and objectPath | 
 |         // field | 
 |         if (subtree[0].first.empty() || subtree[0].second.size() != 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "TPM.Policy mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& serv = subtree[0].second.begin()->first; | 
 |  | 
 |         if (serv.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "TPM.Policy service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // Valid TPM Enable object found, now setting the value | 
 |         managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |             aResp->strand_, | 
 |             [aResp](const boost::system::error_code& ec2) { | 
 |             if (ec2) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG | 
 |                     << "DBUS response error: Set TrustedModuleRequiredToBoot" | 
 |                     << ec2; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |             BMCWEB_LOG_DEBUG << "Set TrustedModuleRequiredToBoot done."; | 
 |         }, | 
 |             serv, path, "org.freedesktop.DBus.Properties", "Set", | 
 |             "xyz.openbmc_project.Control.TPM.Policy", "TPMEnable", | 
 |             dbus::utility::DbusVariantType(tpmRequired)); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets boot properties into DBUS object(s). | 
 |  * | 
 |  * @param[in] aResp           Shared pointer for generating response message. | 
 |  * @param[in] bootType        The boot type to set. | 
 |  * @return Integer error code. | 
 |  */ | 
 | inline void setBootType(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                         const std::optional<std::string>& bootType) | 
 | { | 
 |     std::string bootTypeStr; | 
 |  | 
 |     if (!bootType) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     // Source target specified | 
 |     BMCWEB_LOG_DEBUG << "Boot type: " << *bootType; | 
 |     // Figure out which DBUS interface and property to use | 
 |     if (*bootType == "Legacy") | 
 |     { | 
 |         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.Legacy"; | 
 |     } | 
 |     else if (*bootType == "UEFI") | 
 |     { | 
 |         bootTypeStr = "xyz.openbmc_project.Control.Boot.Type.Types.EFI"; | 
 |     } | 
 |     else | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Invalid property value for " | 
 |                             "BootSourceOverrideMode: " | 
 |                          << *bootType; | 
 |         messages::propertyValueNotInList(aResp->res, *bootType, | 
 |                                          "BootSourceOverrideMode"); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Act on validated parameters | 
 |     BMCWEB_LOG_DEBUG << "DBUS boot type: " << bootTypeStr; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             if (ec.value() == boost::asio::error::host_unreachable) | 
 |             { | 
 |                 messages::resourceNotFound(aResp->res, "Set", "BootType"); | 
 |                 return; | 
 |             } | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         BMCWEB_LOG_DEBUG << "Boot type update done."; | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Control.Boot.Type", "BootType", | 
 |         dbus::utility::DbusVariantType(bootTypeStr)); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets boot properties into DBUS object(s). | 
 |  * | 
 |  * @param[in] aResp           Shared pointer for generating response message. | 
 |  * @param[in] bootType        The boot type to set. | 
 |  * @return Integer error code. | 
 |  */ | 
 | inline void setBootEnable(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                           const std::optional<std::string>& bootEnable) | 
 | { | 
 |     if (!bootEnable) | 
 |     { | 
 |         return; | 
 |     } | 
 |     // Source target specified | 
 |     BMCWEB_LOG_DEBUG << "Boot enable: " << *bootEnable; | 
 |  | 
 |     bool bootOverrideEnable = false; | 
 |     bool bootOverridePersistent = false; | 
 |     // Figure out which DBUS interface and property to use | 
 |     if (*bootEnable == "Disabled") | 
 |     { | 
 |         bootOverrideEnable = false; | 
 |     } | 
 |     else if (*bootEnable == "Once") | 
 |     { | 
 |         bootOverrideEnable = true; | 
 |         bootOverridePersistent = false; | 
 |     } | 
 |     else if (*bootEnable == "Continuous") | 
 |     { | 
 |         bootOverrideEnable = true; | 
 |         bootOverridePersistent = true; | 
 |     } | 
 |     else | 
 |     { | 
 |         BMCWEB_LOG_DEBUG | 
 |             << "Invalid property value for BootSourceOverrideEnabled: " | 
 |             << *bootEnable; | 
 |         messages::propertyValueNotInList(aResp->res, *bootEnable, | 
 |                                          "BootSourceOverrideEnabled"); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Act on validated parameters | 
 |     BMCWEB_LOG_DEBUG << "DBUS boot override enable: " << bootOverrideEnable; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec2) { | 
 |         if (ec2) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         BMCWEB_LOG_DEBUG << "Boot override enable update done."; | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Object.Enable", "Enabled", | 
 |         dbus::utility::DbusVariantType(bootOverrideEnable)); | 
 |  | 
 |     if (!bootOverrideEnable) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     // In case boot override is enabled we need to set correct value for the | 
 |     // 'one_time' enable DBus interface | 
 |     BMCWEB_LOG_DEBUG << "DBUS boot override persistent: " | 
 |                      << bootOverridePersistent; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         BMCWEB_LOG_DEBUG << "Boot one_time update done."; | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot/one_time", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Object.Enable", "Enabled", | 
 |         dbus::utility::DbusVariantType(!bootOverridePersistent)); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets boot properties into DBUS object(s). | 
 |  * | 
 |  * @param[in] aResp           Shared pointer for generating response message. | 
 |  * @param[in] bootSource      The boot source to set. | 
 |  * | 
 |  * @return Integer error code. | 
 |  */ | 
 | inline void setBootModeOrSource(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                                 const std::optional<std::string>& bootSource) | 
 | { | 
 |     std::string bootSourceStr; | 
 |     std::string bootModeStr; | 
 |  | 
 |     if (!bootSource) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     // Source target specified | 
 |     BMCWEB_LOG_DEBUG << "Boot source: " << *bootSource; | 
 |     // Figure out which DBUS interface and property to use | 
 |     if (assignBootParameters(aResp, *bootSource, bootSourceStr, bootModeStr) != | 
 |         0) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG | 
 |             << "Invalid property value for BootSourceOverrideTarget: " | 
 |             << *bootSource; | 
 |         messages::propertyValueNotInList(aResp->res, *bootSource, | 
 |                                          "BootSourceTargetOverride"); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Act on validated parameters | 
 |     BMCWEB_LOG_DEBUG << "DBUS boot source: " << bootSourceStr; | 
 |     BMCWEB_LOG_DEBUG << "DBUS boot mode: " << bootModeStr; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         BMCWEB_LOG_DEBUG << "Boot source update done."; | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Control.Boot.Source", "BootSource", | 
 |         dbus::utility::DbusVariantType(bootSourceStr)); | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         BMCWEB_LOG_DEBUG << "Boot mode update done."; | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/boot", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Control.Boot.Mode", "BootMode", | 
 |         dbus::utility::DbusVariantType(bootModeStr)); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets Boot source override properties. | 
 |  * | 
 |  * @param[in] aResp      Shared pointer for generating response message. | 
 |  * @param[in] bootSource The boot source from incoming RF request. | 
 |  * @param[in] bootType   The boot type from incoming RF request. | 
 |  * @param[in] bootEnable The boot override enable from incoming RF request. | 
 |  * | 
 |  * @return Integer error code. | 
 |  */ | 
 |  | 
 | inline void setBootProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                               const std::optional<std::string>& bootSource, | 
 |                               const std::optional<std::string>& bootType, | 
 |                               const std::optional<std::string>& bootEnable) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set boot information."; | 
 |  | 
 |     setBootModeOrSource(aResp, bootSource); | 
 |     setBootType(aResp, bootType); | 
 |     setBootEnable(aResp, bootEnable); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets AssetTag | 
 |  * | 
 |  * @param[in] aResp   Shared pointer for generating response message. | 
 |  * @param[in] assetTag  "AssetTag" from request. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setAssetTag(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                         const std::string& assetTag) | 
 | { | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Inventory.Item.System"}; | 
 |     managedStore::ManagedObjectStoreContext requestContext(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/xyz/openbmc_project/inventory", 0, interfaces, requestContext, | 
 |         [aResp, | 
 |          assetTag](const boost::system::error_code& ec, | 
 |                    const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "D-Bus response error on GetSubTree " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Can't find system D-Bus object!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         // Assume only 1 system D-Bus object | 
 |         // Throw an error if there is more than 1 | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus object!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree[0].first.empty() || subtree[0].second.size() != 1) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Asset Tag Set mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& service = subtree[0].second.begin()->first; | 
 |  | 
 |         if (service.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Asset Tag Set service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |             aResp->strand_, | 
 |             [aResp](const boost::system::error_code& ec2) { | 
 |             if (ec2) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG << "D-Bus response error on AssetTag Set " | 
 |                                  << ec2; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |         }, | 
 |             service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |             "xyz.openbmc_project.Inventory.Decorator.AssetTag", "AssetTag", | 
 |             dbus::utility::DbusVariantType(assetTag)); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets automaticRetry (Auto Reboot) | 
 |  * | 
 |  * @param[in] aResp   Shared pointer for generating response message. | 
 |  * @param[in] automaticRetryConfig  "AutomaticRetryConfig" from request. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setAutomaticRetry(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                               const std::string& automaticRetryConfig) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set Automatic Retry."; | 
 |  | 
 |     // OpenBMC only supports "Disabled" and "RetryAttempts". | 
 |     bool autoRebootEnabled = false; | 
 |  | 
 |     if (automaticRetryConfig == "Disabled") | 
 |     { | 
 |         autoRebootEnabled = false; | 
 |     } | 
 |     else if (automaticRetryConfig == "RetryAttempts") | 
 |     { | 
 |         autoRebootEnabled = true; | 
 |     } | 
 |     else | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Invalid property value for AutomaticRetryConfig: " | 
 |                          << automaticRetryConfig; | 
 |         messages::propertyValueNotInList(aResp->res, automaticRetryConfig, | 
 |                                          "AutomaticRetryConfig"); | 
 |         return; | 
 |     } | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/auto_reboot", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Control.Boot.RebootPolicy", "AutoReboot", | 
 |         dbus::utility::DbusVariantType(autoRebootEnabled)); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets power restore policy properties. | 
 |  * | 
 |  * @param[in] aResp   Shared pointer for generating response message. | 
 |  * @param[in] policy  power restore policy properties from request. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     setPowerRestorePolicy(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                           const std::string& policy) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set power restore policy."; | 
 |  | 
 |     const boost::container::flat_map<std::string, std::string> policyMaps = { | 
 |         {"AlwaysOn", | 
 |          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOn"}, | 
 |         {"AlwaysOff", | 
 |          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.AlwaysOff"}, | 
 |         {"LastState", | 
 |          "xyz.openbmc_project.Control.Power.RestorePolicy.Policy.Restore"}}; | 
 |  | 
 |     std::string powerRestorPolicy; | 
 |  | 
 |     auto policyMapsIt = policyMaps.find(policy); | 
 |     if (policyMapsIt == policyMaps.end()) | 
 |     { | 
 |         messages::propertyValueNotInList(aResp->res, policy, | 
 |                                          "PowerRestorePolicy"); | 
 |         return; | 
 |     } | 
 |  | 
 |     powerRestorPolicy = policyMapsIt->second; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         aResp->strand_, | 
 |         [aResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     }, | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/control/host0/power_restore_policy", | 
 |         "org.freedesktop.DBus.Properties", "Set", | 
 |         "xyz.openbmc_project.Control.Power.RestorePolicy", "PowerRestorePolicy", | 
 |         dbus::utility::DbusVariantType(powerRestorPolicy)); | 
 | } | 
 |  | 
 | #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE | 
 | /** | 
 |  * @brief Retrieves provisioning status | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get OEM information."; | 
 |     managedStore::ManagedObjectStoreContext context(asyncResp); | 
 |     managedStore::GetManagedObjectStore()->getAllProperties( | 
 |         "xyz.openbmc_project.PFR.Manager", "/xyz/openbmc_project/pfr", | 
 |         "xyz.openbmc_project.PFR.Attributes", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const dbus::utility::DBusPropertiesMap& propertiesList) { | 
 |         nlohmann::json& oemPFR = | 
 |             aResp->res.jsonValue["Oem"]["OpenBmc"]["FirmwareProvisioning"]; | 
 |         aResp->res.jsonValue["Oem"]["OpenBmc"]["@odata.type"] = | 
 |             "#OemComputerSystem.OpenBmc"; | 
 |         oemPFR["@odata.type"] = "#OemComputerSystem.FirmwareProvisioning"; | 
 |  | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             // not an error, don't have to have the interface | 
 |             oemPFR["ProvisioningStatus"] = "NotProvisioned"; | 
 |             return; | 
 |         } | 
 |  | 
 |         const bool* provState = nullptr; | 
 |         const bool* lockState = nullptr; | 
 |  | 
 |         const bool success = sdbusplus::unpackPropertiesNoThrow( | 
 |             dbus_utils::UnpackErrorPrinter(), propertiesList, "UfmProvisioned", | 
 |             provState, "UfmLocked", lockState); | 
 |  | 
 |         if (!success) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         if ((provState == nullptr) || (lockState == nullptr)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Unable to get PFR attributes."; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         if (*provState == true) | 
 |         { | 
 |             if (*lockState == true) | 
 |             { | 
 |                 oemPFR["ProvisioningStatus"] = "ProvisionedAndLocked"; | 
 |             } | 
 |             else | 
 |             { | 
 |                 oemPFR["ProvisioningStatus"] = "ProvisionedButNotLocked"; | 
 |             } | 
 |         } | 
 |         else | 
 |         { | 
 |             oemPFR["ProvisioningStatus"] = "NotProvisioned"; | 
 |         } | 
 |     }); | 
 | } | 
 | #endif | 
 |  | 
 | /** | 
 |  * @brief Translate the PowerMode to a response message. | 
 |  * | 
 |  * @param[in] aResp  Shared pointer for generating response message. | 
 |  * @param[in] modeValue  PowerMode value to be translated | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                                const std::string& modeValue) | 
 | { | 
 |     if (modeValue == "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static") | 
 |     { | 
 |         aResp->res.jsonValue["PowerMode"] = "Static"; | 
 |     } | 
 |     else if ( | 
 |         modeValue == | 
 |         "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance") | 
 |     { | 
 |         aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; | 
 |     } | 
 |     else if (modeValue == | 
 |              "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving") | 
 |     { | 
 |         aResp->res.jsonValue["PowerMode"] = "PowerSaving"; | 
 |     } | 
 |     else if (modeValue == | 
 |              "xyz.openbmc_project.Control.Power.Mode.PowerMode.OEM") | 
 |     { | 
 |         aResp->res.jsonValue["PowerMode"] = "OEM"; | 
 |     } | 
 |     else | 
 |     { | 
 |         // Any other values would be invalid | 
 |         BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; | 
 |         messages::internalError(aResp->res); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves system power mode | 
 |  * | 
 |  * @param[in] aResp  Shared pointer for generating response message. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get power mode."; | 
 |  | 
 |     // Get Power Mode object path: | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.Power.Mode"}; | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, context, | 
 |         [aResp, | 
 |          context](const boost::system::error_code& ec, | 
 |                   const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree " | 
 |                              << ec; | 
 |             // This is an optional D-Bus object so just return if | 
 |             // error occurs | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             // As noted above, this is an optional interface so just return | 
 |             // if there is no instance found | 
 |             return; | 
 |         } | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             // More then one PowerMode object is not supported and is an | 
 |             // error | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "Found more than 1 system D-Bus Power.Mode objects: " | 
 |                 << subtree.size(); | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& service = subtree[0].second.begin()->first; | 
 |         if (service.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         // Valid Power Mode object found, now read the current value | 
 |         dbus_utils::getProperty<std::string>( | 
 |             service, path, "xyz.openbmc_project.Control.Power.Mode", | 
 |             "PowerMode", context, | 
 |             [aResp](const boost::system::error_code& ec2, | 
 |                     const std::string& pmode) { | 
 |             if (ec2) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG << "DBUS response error on PowerMode Get: " | 
 |                                  << ec2; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = { | 
 |                 "Static", "MaximumPerformance", "PowerSaving"}; | 
 |  | 
 |             BMCWEB_LOG_DEBUG << "Current power mode: " << pmode; | 
 |             translatePowerMode(aResp, pmode); | 
 |         }); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Validate the specified mode is valid and return the PowerMode | 
 |  * name associated with that string | 
 |  * | 
 |  * @param[in] aResp   Shared pointer for generating response message. | 
 |  * @param[in] modeString  String representing the desired PowerMode | 
 |  * | 
 |  * @return PowerMode value or empty string if mode is not valid | 
 |  */ | 
 | inline std::string | 
 |     validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                       const std::string& modeString) | 
 | { | 
 |     std::string mode; | 
 |  | 
 |     if (modeString == "Static") | 
 |     { | 
 |         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; | 
 |     } | 
 |     else if (modeString == "MaximumPerformance") | 
 |     { | 
 |         mode = | 
 |             "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"; | 
 |     } | 
 |     else if (modeString == "PowerSaving") | 
 |     { | 
 |         mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; | 
 |     } | 
 |     else | 
 |     { | 
 |         messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); | 
 |     } | 
 |     return mode; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets system power mode. | 
 |  * | 
 |  * @param[in] aResp   Shared pointer for generating response message. | 
 |  * @param[in] pmode   System power mode from request. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                          const std::string& pmode) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set power mode."; | 
 |  | 
 |     std::string powerMode = validatePowerMode(aResp, pmode); | 
 |     if (powerMode.empty()) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     // Get Power Mode object path: | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.Power.Mode"}; | 
 |     managedStore::ManagedObjectStoreContext requestContext(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, requestContext, | 
 |         [aResp, | 
 |          powerMode](const boost::system::error_code& ec, | 
 |                     const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error on Power.Mode GetSubTree " | 
 |                              << ec; | 
 |             // This is an optional D-Bus object, but user attempted to patch | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             // This is an optional D-Bus object, but user attempted to patch | 
 |             messages::resourceNotFound(aResp->res, "ComputerSystem", | 
 |                                        "PowerMode"); | 
 |             return; | 
 |         } | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             // More then one PowerMode object is not supported and is an | 
 |             // error | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "Found more than 1 system D-Bus Power.Mode objects: " | 
 |                 << subtree.size(); | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& service = subtree[0].second.begin()->first; | 
 |         if (service.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " | 
 |                          << path; | 
 |  | 
 |         // Set the Power Mode property | 
 |         managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |             aResp->strand_, | 
 |             [aResp](const boost::system::error_code& ec2) { | 
 |             if (ec2) | 
 |             { | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |         }, | 
 |             service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |             "xyz.openbmc_project.Control.Power.Mode", "PowerMode", | 
 |             dbus::utility::DbusVariantType(powerMode)); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Translates watchdog timeout action DBUS property value to redfish. | 
 |  * | 
 |  * @param[in] dbusAction    The watchdog timeout action in D-BUS. | 
 |  * | 
 |  * @return Returns as a string, the timeout action in Redfish terms. If | 
 |  * translation cannot be done, returns an empty string. | 
 |  */ | 
 | inline std::string dbusToRfWatchdogAction(const std::string& dbusAction) | 
 | { | 
 |     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.None") | 
 |     { | 
 |         return "None"; | 
 |     } | 
 |     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.HardReset") | 
 |     { | 
 |         return "ResetSystem"; | 
 |     } | 
 |     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerOff") | 
 |     { | 
 |         return "PowerDown"; | 
 |     } | 
 |     if (dbusAction == "xyz.openbmc_project.State.Watchdog.Action.PowerCycle") | 
 |     { | 
 |         return "PowerCycle"; | 
 |     } | 
 |  | 
 |     return ""; | 
 | } | 
 |  | 
 | /** | 
 |  *@brief Translates timeout action from Redfish to DBUS property value. | 
 |  * | 
 |  *@param[in] rfAction The timeout action in Redfish. | 
 |  * | 
 |  *@return Returns as a string, the time_out action as expected by DBUS. | 
 |  *If translation cannot be done, returns an empty string. | 
 |  */ | 
 |  | 
 | inline std::string rfToDbusWDTTimeOutAct(const std::string& rfAction) | 
 | { | 
 |     if (rfAction == "None") | 
 |     { | 
 |         return "xyz.openbmc_project.State.Watchdog.Action.None"; | 
 |     } | 
 |     if (rfAction == "PowerCycle") | 
 |     { | 
 |         return "xyz.openbmc_project.State.Watchdog.Action.PowerCycle"; | 
 |     } | 
 |     if (rfAction == "PowerDown") | 
 |     { | 
 |         return "xyz.openbmc_project.State.Watchdog.Action.PowerOff"; | 
 |     } | 
 |     if (rfAction == "ResetSystem") | 
 |     { | 
 |         return "xyz.openbmc_project.State.Watchdog.Action.HardReset"; | 
 |     } | 
 |  | 
 |     return ""; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves host watchdog timer properties over DBUS | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void | 
 |     getHostWatchdogTimer(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get host watchodg"; | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     managedStore::GetManagedObjectStore()->getAllProperties( | 
 |         "xyz.openbmc_project.Watchdog", "/xyz/openbmc_project/watchdog/host0", | 
 |         "xyz.openbmc_project.State.Watchdog", context, | 
 |         [aResp](const boost::system::error_code& ec, | 
 |                 const dbus::utility::DBusPropertiesMap& properties) { | 
 |         if (ec) | 
 |         { | 
 |             // watchdog service is stopped | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |             return; | 
 |         } | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Got " << properties.size() << " wdt prop."; | 
 |  | 
 |         nlohmann::json& hostWatchdogTimer = | 
 |             aResp->res.jsonValue["HostWatchdogTimer"]; | 
 |  | 
 |         // watchdog service is running/enabled | 
 |         hostWatchdogTimer["Status"]["State"] = "Enabled"; | 
 |  | 
 |         const bool* enabled = nullptr; | 
 |         const std::string* expireAction = nullptr; | 
 |  | 
 |         const bool success = sdbusplus::unpackPropertiesNoThrow( | 
 |             dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, | 
 |             "ExpireAction", expireAction); | 
 |  | 
 |         if (!success) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         if (enabled != nullptr) | 
 |         { | 
 |             hostWatchdogTimer["FunctionEnabled"] = *enabled; | 
 |         } | 
 |  | 
 |         if (expireAction != nullptr) | 
 |         { | 
 |             std::string action = dbusToRfWatchdogAction(*expireAction); | 
 |             if (action.empty()) | 
 |             { | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |             hostWatchdogTimer["TimeoutAction"] = action; | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets Host WatchDog Timer properties. | 
 |  * | 
 |  * @param[in] aResp      Shared pointer for generating response message. | 
 |  * @param[in] wdtEnable  The WDTimer Enable value (true/false) from incoming | 
 |  *                       RF request. | 
 |  * @param[in] wdtTimeOutAction The WDT Timeout action, from incoming RF request. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setWDTProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                              const std::optional<bool> wdtEnable, | 
 |                              const std::optional<std::string>& wdtTimeOutAction) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set host watchdog"; | 
 |  | 
 |     if (wdtTimeOutAction) | 
 |     { | 
 |         std::string wdtTimeOutActStr = rfToDbusWDTTimeOutAct(*wdtTimeOutAction); | 
 |         // check if TimeOut Action is Valid | 
 |         if (wdtTimeOutActStr.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Unsupported value for TimeoutAction: " | 
 |                              << *wdtTimeOutAction; | 
 |             messages::propertyValueNotInList(aResp->res, *wdtTimeOutAction, | 
 |                                              "TimeoutAction"); | 
 |             return; | 
 |         } | 
 |  | 
 |         managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |             aResp->strand_, | 
 |             [aResp](const boost::system::error_code& ec) { | 
 |             if (ec) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |         }, | 
 |             "xyz.openbmc_project.Watchdog", | 
 |             "/xyz/openbmc_project/watchdog/host0", | 
 |             "org.freedesktop.DBus.Properties", "Set", | 
 |             "xyz.openbmc_project.State.Watchdog", "ExpireAction", | 
 |             dbus::utility::DbusVariantType(wdtTimeOutActStr)); | 
 |     } | 
 |  | 
 |     if (wdtEnable) | 
 |     { | 
 |         managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |             aResp->strand_, | 
 |             [aResp](const boost::system::error_code& ec) { | 
 |             if (ec) | 
 |             { | 
 |                 BMCWEB_LOG_DEBUG << "DBUS response error " << ec; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |         }, | 
 |             "xyz.openbmc_project.Watchdog", | 
 |             "/xyz/openbmc_project/watchdog/host0", | 
 |             "org.freedesktop.DBus.Properties", "Set", | 
 |             "xyz.openbmc_project.State.Watchdog", "Enabled", | 
 |             dbus::utility::DbusVariantType(*wdtEnable)); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Parse the Idle Power Saver properties into json | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * @param[in] properties  IPS property data from DBus. | 
 |  * | 
 |  * @return true if successful | 
 |  */ | 
 | inline bool | 
 |     parseIpsProperties(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                        const dbus::utility::DBusPropertiesMap& properties) | 
 | { | 
 |     const bool* enabled = nullptr; | 
 |     const uint8_t* enterUtilizationPercent = nullptr; | 
 |     const uint64_t* enterDwellTime = nullptr; | 
 |     const uint8_t* exitUtilizationPercent = nullptr; | 
 |     const uint64_t* exitDwellTime = nullptr; | 
 |  | 
 |     const bool success = sdbusplus::unpackPropertiesNoThrow( | 
 |         dbus_utils::UnpackErrorPrinter(), properties, "Enabled", enabled, | 
 |         "EnterUtilizationPercent", enterUtilizationPercent, "EnterDwellTime", | 
 |         enterDwellTime, "ExitUtilizationPercent", exitUtilizationPercent, | 
 |         "ExitDwellTime", exitDwellTime); | 
 |  | 
 |     if (!success) | 
 |     { | 
 |         return false; | 
 |     } | 
 |  | 
 |     if (enabled != nullptr) | 
 |     { | 
 |         aResp->res.jsonValue["IdlePowerSaver"]["Enabled"] = *enabled; | 
 |     } | 
 |  | 
 |     if (enterUtilizationPercent != nullptr) | 
 |     { | 
 |         aResp->res.jsonValue["IdlePowerSaver"]["EnterUtilizationPercent"] = | 
 |             *enterUtilizationPercent; | 
 |     } | 
 |  | 
 |     if (enterDwellTime != nullptr) | 
 |     { | 
 |         const std::chrono::duration<uint64_t, std::milli> ms(*enterDwellTime); | 
 |         aResp->res.jsonValue["IdlePowerSaver"]["EnterDwellTimeSeconds"] = | 
 |             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) | 
 |                 .count(); | 
 |     } | 
 |  | 
 |     if (exitUtilizationPercent != nullptr) | 
 |     { | 
 |         aResp->res.jsonValue["IdlePowerSaver"]["ExitUtilizationPercent"] = | 
 |             *exitUtilizationPercent; | 
 |     } | 
 |  | 
 |     if (exitDwellTime != nullptr) | 
 |     { | 
 |         const std::chrono::duration<uint64_t, std::milli> ms(*exitDwellTime); | 
 |         aResp->res.jsonValue["IdlePowerSaver"]["ExitDwellTimeSeconds"] = | 
 |             std::chrono::duration_cast<std::chrono::duration<uint64_t>>(ms) | 
 |                 .count(); | 
 |     } | 
 |  | 
 |     return true; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves host watchdog timer properties over DBUS | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get idle power saver parameters"; | 
 |  | 
 |     // Get IdlePowerSaver object path: | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; | 
 |     managedStore::ManagedObjectStoreContext context(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, context, | 
 |         [aResp, | 
 |          context](const boost::system::error_code& ec, | 
 |                   const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "DBUS response error on Power.IdlePowerSaver GetSubTree " | 
 |                 << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             // This is an optional interface so just return | 
 |             // if there is no instance found | 
 |             BMCWEB_LOG_DEBUG << "No instances found"; | 
 |             return; | 
 |         } | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             // More then one PowerIdlePowerSaver object is not supported and | 
 |             // is an error | 
 |             BMCWEB_LOG_DEBUG << "Found more than 1 system D-Bus " | 
 |                                 "Power.IdlePowerSaver objects: " | 
 |                              << subtree.size(); | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& service = subtree[0].second.begin()->first; | 
 |         if (service.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // Valid IdlePowerSaver object found, now read the current values | 
 |         managedStore::GetManagedObjectStore()->getAllProperties( | 
 |             service, path, "xyz.openbmc_project.Control.Power.IdlePowerSaver", | 
 |             context, | 
 |             [aResp](const boost::system::error_code& ec2, | 
 |                     const dbus::utility::DBusPropertiesMap& properties) { | 
 |             if (ec2) | 
 |             { | 
 |                 BMCWEB_LOG_ERROR | 
 |                     << "DBUS response error on IdlePowerSaver GetAll: " << ec2; | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             if (!parseIpsProperties(aResp, properties)) | 
 |             { | 
 |                 messages::internalError(aResp->res); | 
 |                 return; | 
 |             } | 
 |         }); | 
 |     }); | 
 |  | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Get idle power saver parameters"; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieve the systemName suffix | 
 |  * | 
 |  * @param[in] systemName     String of systemName, assume it's "systemX" | 
 |  * | 
 |  * @return string of the suffix, empty string if it's invalid or empty | 
 |  */ | 
 | inline std::string getSystemSuffix(const std::string& systemName) | 
 | { | 
 |     constexpr std::string_view systemPrefix = "system"; | 
 |  | 
 |     if (systemName.rfind(systemPrefix, 0) != 0) | 
 |     { | 
 |         // The systemName did not start with the prefix - return empty | 
 |         return ""; | 
 |     } | 
 |     // Extract the part after "system" - empty string if there is no suffix | 
 |     return systemName.substr(systemPrefix.size()); | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves BM readiness signal from the file system | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * @param[in] systemName     String of systemName | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getBMReady(const std::shared_ptr<bmcweb::AsyncResp>& aResp) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get BMReady signal"; | 
 |     nlohmann::json& googleBM = | 
 |         aResp->res.jsonValue["Oem"]["Google"]["BareMetalStatus"]; | 
 |  | 
 |     googleBM["BareMetal"] = "Disabled"; | 
 |     if (std::filesystem::exists(BM_SIGNAL_PATH)) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "BMReady flag found"; | 
 |         googleBM["BareMetal"] = "BareMetalReady"; | 
 |     } | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Get BMReady signal"; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves NERF status from the file system | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * @param[in] systemName     String of systemName | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getNERFStatus(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                           const std::string& systemName) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get NERF status signal"; | 
 |  | 
 |     nlohmann::json& googleNERF = | 
 |         aResp->res.jsonValue["Oem"]["Google"]["NERFStatus"]; | 
 |  | 
 |     googleNERF["NERF"] = "NonBMMode"; | 
 |  | 
 |     const std::string systemSuffix = getSystemSuffix(systemName); | 
 |     const std::string bmDriveCleaningFlagPath = | 
 |         "/run/bm-drive-cleaning.flag" + systemSuffix; | 
 |     const std::string bmDriveCleaningDoneAckFlagPath = | 
 |         "/run/bm-drive-cleaning-done-ack.flag" + systemSuffix; | 
 |     if (std::filesystem::exists(bmDriveCleaningDoneAckFlagPath)) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Cleaning was finished and acked by NERF"; | 
 |         googleNERF["NERF"] = "UEFIboot"; | 
 |     } | 
 |     else if (std::filesystem::exists(bmDriveCleaningFlagPath)) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Cleaning flag found, NERF must be in rendevouz"; | 
 |         googleNERF["NERF"] = "SteadyState"; | 
 |     } | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Get NERF Status signal"; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Retrieves BM Instance properties from the file system | 
 |  * | 
 |  * @param[in] aResp     Shared pointer for completing asynchronous calls. | 
 |  * @param[in] systemName     String of systemName | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void getBMInstance(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                           const std::string& systemName) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Get BM Instance property"; | 
 |     aResp->res.jsonValue["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Oem/Google/BareMetalInstance"; | 
 |     aResp->res.jsonValue["@odata.type"] = | 
 |         "#GoogleBareMetalInstance.v1_0_0.GoogleBareMetalInstance"; | 
 |  | 
 |     const auto systemSuffix = getSystemSuffix(systemName); | 
 |     const std::array<std::pair<std::string_view, std::string>, 7> | 
 |         bmPropertyToPath = { | 
 |             {{"AssetTag", "/run/bm-instance/asset-tag" + systemSuffix}, | 
 |              {"BoardSerialNumber", | 
 |               "/run/bm-instance/board-serial-number" + systemSuffix}, | 
 |              {"Family", "/run/bm-instance/family" + systemSuffix}, | 
 |              {"ProductName", "/run/bm-instance/product-name" + systemSuffix}, | 
 |              {"SKU", "/run/bm-instance/sku" + systemSuffix}, | 
 |              {"SystemSerialNumber", | 
 |               "/run/bm-instance/system-serial-number" + systemSuffix}, | 
 |              {"UUID", "/run/bm-instance/uuid" + systemSuffix}}}; | 
 |  | 
 |     for (const auto& [propertyName, filePath] : bmPropertyToPath) | 
 |     { | 
 |         // If the path doesn't exist, set it to an empty string | 
 |         if (!std::filesystem::exists(filePath)) | 
 |         { | 
 |             aResp->res.jsonValue[propertyName] = ""; | 
 |             continue; | 
 |         } | 
 |  | 
 |         std::ifstream ifs; | 
 |         ifs.exceptions(std::ifstream::failbit); | 
 |         std::string property; | 
 |         try | 
 |         { | 
 |             ifs.open(filePath); | 
 |             std::getline(ifs, property); | 
 |         } | 
 |         catch (std::ios_base::failure& fail) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Faield to read - setting to default value: " | 
 |                              << filePath; | 
 |             aResp->res.jsonValue[propertyName] = ""; | 
 |             continue; | 
 |         } | 
 |         aResp->res.jsonValue[propertyName] = property; | 
 |     } | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Get BM Instance property"; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets Idle Power Saver properties. | 
 |  * | 
 |  * @param[in] aResp      Shared pointer for generating response message. | 
 |  * @param[in] ipsEnable  The IPS Enable value (true/false) from incoming | 
 |  *                       RF request. | 
 |  * @param[in] ipsEnterUtil The utilization limit to enter idle state. | 
 |  * @param[in] ipsEnterTime The time the utilization must be below ipsEnterUtil | 
 |  * before entering idle state. | 
 |  * @param[in] ipsExitUtil The utilization limit when exiting idle state. | 
 |  * @param[in] ipsExitTime The time the utilization must be above ipsExutUtil | 
 |  * before exiting idle state | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setIdlePowerSaver(const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |                               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) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set idle power saver properties"; | 
 |  | 
 |     // Get IdlePowerSaver object path: | 
 |     constexpr std::array<std::string_view, 1> interfaces = { | 
 |         "xyz.openbmc_project.Control.Power.IdlePowerSaver"}; | 
 |     managedStore::ManagedObjectStoreContext requestContext(aResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTree( | 
 |         "/", 0, interfaces, requestContext, | 
 |         [aResp, ipsEnable, ipsEnterUtil, ipsEnterTime, ipsExitUtil, | 
 |          ipsExitTime](const boost::system::error_code& ec, | 
 |                       const dbus::utility::MapperGetSubTreeResponse& subtree) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "DBUS response error on Power.IdlePowerSaver GetSubTree " | 
 |                 << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if (subtree.empty()) | 
 |         { | 
 |             // This is an optional D-Bus object, but user attempted to patch | 
 |             messages::resourceNotFound(aResp->res, "ComputerSystem", | 
 |                                        "IdlePowerSaver"); | 
 |             return; | 
 |         } | 
 |         if (subtree.size() > 1) | 
 |         { | 
 |             // More then one PowerIdlePowerSaver object is not supported and | 
 |             // is an error | 
 |             BMCWEB_LOG_DEBUG | 
 |                 << "Found more than 1 system D-Bus Power.IdlePowerSaver objects: " | 
 |                 << subtree.size(); | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |         const std::string& path = subtree[0].first; | 
 |         const std::string& service = subtree[0].second.begin()->first; | 
 |         if (service.empty()) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Power.IdlePowerSaver service mapper error!"; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // Valid Power IdlePowerSaver object found, now set any values that | 
 |         // need to be updated | 
 |  | 
 |         if (ipsEnable) | 
 |         { | 
 |             managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |                 aResp->strand_, | 
 |                 [aResp](const boost::system::error_code& ec2) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |                     messages::internalError(aResp->res); | 
 |                     return; | 
 |                 } | 
 |             }, | 
 |                 service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", "Enabled", | 
 |                 dbus::utility::DbusVariantType(*ipsEnable)); | 
 |         } | 
 |         if (ipsEnterUtil) | 
 |         { | 
 |             managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |                 aResp->strand_, | 
 |                 [aResp](const boost::system::error_code& ec2) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |                     messages::internalError(aResp->res); | 
 |                     return; | 
 |                 } | 
 |             }, | 
 |                 service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", | 
 |                 "EnterUtilizationPercent", | 
 |                 dbus::utility::DbusVariantType(*ipsEnterUtil)); | 
 |         } | 
 |         if (ipsEnterTime) | 
 |         { | 
 |             // Convert from seconds into milliseconds for DBus | 
 |             const uint64_t timeMilliseconds = *ipsEnterTime * 1000; | 
 |             managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |                 aResp->strand_, | 
 |                 [aResp](const boost::system::error_code& ec2) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |                     messages::internalError(aResp->res); | 
 |                     return; | 
 |                 } | 
 |             }, | 
 |                 service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", | 
 |                 "EnterDwellTime", | 
 |                 dbus::utility::DbusVariantType(timeMilliseconds)); | 
 |         } | 
 |         if (ipsExitUtil) | 
 |         { | 
 |             managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |                 aResp->strand_, | 
 |                 [aResp](const boost::system::error_code& ec2) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |                     messages::internalError(aResp->res); | 
 |                     return; | 
 |                 } | 
 |             }, | 
 |                 service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", | 
 |                 "ExitUtilizationPercent", | 
 |                 dbus::utility::DbusVariantType(*ipsExitUtil)); | 
 |         } | 
 |         if (ipsExitTime) | 
 |         { | 
 |             // Convert from seconds into milliseconds for DBus | 
 |             const uint64_t timeMilliseconds = *ipsExitTime * 1000; | 
 |             managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |                 aResp->strand_, | 
 |                 [aResp](const boost::system::error_code& ec2) { | 
 |                 if (ec2) | 
 |                 { | 
 |                     BMCWEB_LOG_DEBUG << "DBUS response error " << ec2; | 
 |                     messages::internalError(aResp->res); | 
 |                     return; | 
 |                 } | 
 |             }, | 
 |                 service, path, "org.freedesktop.DBus.Properties", "Set", | 
 |                 "xyz.openbmc_project.Control.Power.IdlePowerSaver", | 
 |                 "ExitDwellTime", | 
 |                 dbus::utility::DbusVariantType(timeMilliseconds)); | 
 |         } | 
 |     }); | 
 |  | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Set idle power saver parameters"; | 
 | } | 
 |  | 
 | /** | 
 |  * @brief Sets BMInstnace  properties. | 
 |  * | 
 |  * @param[in] aResp             Shared pointer for generating response message. | 
 |  * @param[in] systemName        String of systemName | 
 |  * @param[in] bmiAssetTag       BM instance asset tag to be set | 
 |  * @param[in] bmiBoardSerialNumber   BM instance board serial number to be set | 
 |  * @param[in] bmiFamily         BM instance family to be set | 
 |  * @param[in] bmiProductName    BM instance product name to be set | 
 |  * @param[in] bmiSKU            BM instance SKU to be set | 
 |  * @param[in] bmiSystemSerialNumber   BM instance syste serial number to be set | 
 |  * @param[in] bmiUUID           BM instance UUID to be set | 
 |  * | 
 |  * @return None. | 
 |  */ | 
 | inline void setBMInstance( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& aResp, | 
 |     const std::string& systemName, const std::string& bmiAssetTag, | 
 |     const std::string& bmiBoardSerialNumber, const std::string& bmiFamily, | 
 |     const std::string& bmiProductName, const std::string& bmiSKU, | 
 |     const std::string& bmiSystemSerialNumber, const std::string& bmiUUID) | 
 | { | 
 |     BMCWEB_LOG_DEBUG << "Set BM Instance properties"; | 
 |  | 
 |     std::filesystem::path bmInstanceDirPath = "/run/bm-instance"; | 
 |  | 
 |     // Create parent directories if they don't exist | 
 |     std::error_code ec; | 
 |     if (!std::filesystem::exists(bmInstanceDirPath, ec)) | 
 |     { | 
 |         std::filesystem::create_directories(bmInstanceDirPath, ec); | 
 |     } | 
 |     if (ec) | 
 |     { | 
 |         if (!std::filesystem::exists(bmInstanceDirPath, ec)) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Failed to create base directory(" | 
 |                              << bmInstanceDirPath << "): " << ec; | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |  | 
 |     const std::string systemSuffix = getSystemSuffix(systemName); | 
 |     // Helper function to output the value to the file path | 
 |     auto processFile = [&systemSuffix](const std::filesystem::path& path, | 
 |                                        std::string_view val) -> bool { | 
 |         std::filesystem::path appendedPath = path; | 
 |         appendedPath.concat(systemSuffix); | 
 |         std::ofstream file(appendedPath); | 
 |         if (!file) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Failed to create: " << appendedPath.string(); | 
 |             return false; | 
 |         } | 
 |         file << val << '\n'; | 
 |         file.close(); | 
 |         return true; | 
 |     }; | 
 |  | 
 |     if (!bmiAssetTag.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "asset-tag", bmiAssetTag)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiBoardSerialNumber.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "board-serial-number", | 
 |                          bmiBoardSerialNumber)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiFamily.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "family", bmiFamily)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiProductName.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "product-name", bmiProductName)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiSKU.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "sku", bmiSKU)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiSystemSerialNumber.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "system-serial-number", | 
 |                          bmiSystemSerialNumber)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |     if (!bmiUUID.empty()) | 
 |     { | 
 |         if (!processFile(bmInstanceDirPath / "uuid", bmiUUID)) | 
 |         { | 
 |             messages::internalError(aResp->res); | 
 |             return; | 
 |         } | 
 |     } | 
 |  | 
 |     messages::success(aResp->res); | 
 |     BMCWEB_LOG_DEBUG << "EXIT: Set BM Instance properties"; | 
 | } | 
 |  | 
 | inline void handleComputerSystemHead( | 
 |     crow::App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ComputerSystemCollection/ComputerSystemCollection.json>; rel=describedby"); | 
 | } | 
 |  | 
 | inline void handleGetSystemsCollection( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ComputerSystemCollection.json>; rel=describedby"); | 
 |     asyncResp->res.jsonValue["@odata.type"] = | 
 |         "#ComputerSystemCollection.ComputerSystemCollection"; | 
 |     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems"; | 
 |     asyncResp->res.jsonValue["Name"] = "Computer System Collection"; | 
 |  | 
 |     managedStore::ManagedObjectStoreContext context(asyncResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTreePaths( | 
 |         "/", 0, systemInterfaces, context, | 
 |         [asyncResp, context](const boost::system::error_code& ec, | 
 |                              const std::vector<std::string>& objects) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |         // If there are less than 2 Item.Systems assume singlehost | 
 |         if (objects.size() < 2) | 
 |         { | 
 |             nlohmann::json::object_t system; | 
 |             system["@odata.id"] = "/redfish/v1/Systems/system"; | 
 |             asyncResp->res.jsonValue["Members"].emplace_back(system); | 
 |             asyncResp->res.jsonValue["Members@odata.count"] = | 
 |                 asyncResp->res.jsonValue["Members"].size(); | 
 |             return; | 
 |         } | 
 |         // Otherwise list all systems | 
 |         for (const auto& object : objects) | 
 |         { | 
 |             std::string systemName = object.substr(object.rfind('/')); | 
 |             nlohmann::json::object_t system; | 
 |             system["@odata.id"] = "/redfish/v1/Systems" + systemName; | 
 |             asyncResp->res.jsonValue["Members"].emplace_back(system); | 
 |         } | 
 |         asyncResp->res.jsonValue["Members@odata.count"] = | 
 |             asyncResp->res.jsonValue["Members"].size(); | 
 |     }); | 
 |  | 
 |     dbus_utils::getProperty<std::string>( | 
 |         "xyz.openbmc_project.Settings", | 
 |         "/xyz/openbmc_project/network/hypervisor", | 
 |         "xyz.openbmc_project.Network.SystemConfiguration", "HostName", context, | 
 |         [asyncResp](const boost::system::error_code& ec2, | 
 |                     const std::string& /*hostName*/) { | 
 |         if (!ec2) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "Hypervisor is available"; | 
 |             nlohmann::json::object_t hypervisor; | 
 |             hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor"; | 
 |             asyncResp->res.jsonValue["Members"].push_back( | 
 |                 std::move(hypervisor)); | 
 |             asyncResp->res.jsonValue["Members@odata.count"] = | 
 |                 asyncResp->res.jsonValue["Members"].size(); | 
 |         } | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * SystemsCollection derived class for delivering ComputerSystems Collection | 
 |  * Schema | 
 |  */ | 
 | inline void requestRoutesSystemsCollection(App& app) | 
 | { | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/") | 
 |         .privileges(redfish::privileges::headComputerSystemCollection) | 
 |         .methods(boost::beast::http::verb::head)( | 
 |             std::bind_front(handleComputerSystemHead, std::ref(app))); | 
 |  | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/") | 
 |         .privileges(redfish::privileges::getComputerSystemCollection) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleGetSystemsCollection, std::ref(app))); | 
 | } | 
 |  | 
 | /** | 
 |  * Function transceives data with dbus directly. | 
 |  */ | 
 | inline void doNMI(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
 | { | 
 |     constexpr char const* serviceName = "xyz.openbmc_project.Control.Host.NMI"; | 
 |     constexpr char const* objectPath = "/xyz/openbmc_project/control/host0/nmi"; | 
 |     constexpr char const* interfaceName = | 
 |         "xyz.openbmc_project.Control.Host.NMI"; | 
 |     constexpr char const* method = "NMI"; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         asyncResp->strand_, | 
 |         [asyncResp](const boost::system::error_code& ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_ERROR << " Bad D-Bus request error: " << ec; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |         messages::success(asyncResp->res); | 
 |     }, | 
 |         serviceName, objectPath, interfaceName, method); | 
 | } | 
 |  | 
 | inline void sendPowerSystemCommand( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& command, const std::string& resetType, | 
 |     const std::string& service, const std::string& path, | 
 |     const std::string& interface, const std::string& property) | 
 | { | 
 |     managedStore::GetManagedObjectStore()->PostDbusCallToIoContextThreadSafe( | 
 |         asyncResp->strand_, | 
 |         [asyncResp, resetType](const boost::system::error_code ec) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_ERROR << "D-Bus responses error: " << ec; | 
 |             if (ec.value() == boost::asio::error::invalid_argument) | 
 |             { | 
 |                 messages::actionParameterNotSupported(asyncResp->res, resetType, | 
 |                                                       "Reset"); | 
 |             } | 
 |             else | 
 |             { | 
 |                 messages::internalError(asyncResp->res); | 
 |             } | 
 |             return; | 
 |         } | 
 |         messages::success(asyncResp->res); | 
 |     }, | 
 |         service, path, "org.freedesktop.DBus.Properties", "Set", interface, | 
 |         property, dbus::utility::DbusVariantType{command}); | 
 | } | 
 |  | 
 | struct SystemResetCommand { | 
 |     std::string command = ""; // NOLINT | 
 |     bool hostCommand = true; | 
 |     bool validCommand = true; | 
 | }; | 
 |  | 
 | inline SystemResetCommand GetSystemResetCommandFromInput(const std::string& resetType){ | 
 |     if ((resetType == "On") || (resetType == "ForceOn")) | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Host.Transition.On", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     if (resetType == "ForceOff") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Chassis.Transition.Off", | 
 |             .hostCommand = false | 
 |         }; | 
 |     } | 
 |     if (resetType == "ForceRestart") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Host.Transition.ForceWarmReboot", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     if (resetType == "GracefulShutdown") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Host.Transition.Off", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     if (resetType == "GracefulRestart") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = | 
 |             "xyz.openbmc_project.State.Host.Transition.GracefulWarmReboot", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     if (resetType == "PowerCycle") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Host.Transition.Reboot", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     //TODO(b/294130541) (b/335339881) | 
 |     // On the gsz platform (GracefulShutdown) does forced shutdown in x86-power-control | 
 |     // This second call path was needed for the bm use case | 
 |     // This is ONLY supported on "gsz" | 
 |     if (resetType == "ReallyGracefulShutDownTechDebt") | 
 |     { | 
 |         return SystemResetCommand { | 
 |             .command = "xyz.openbmc_project.State.Host.Transition.ReallyGracefulShutDown", | 
 |             .hostCommand = true | 
 |         }; | 
 |     } | 
 |     return SystemResetCommand {.validCommand = false}; | 
 | } | 
 |  | 
 | /* Have systemd run a curl command in a set amount of time | 
 |  *  resetURI: Chassis or Systems based on where you want to reset | 
 |  *  resetTimeSec: The amount of seconds to delay reset | 
 |  *  resetOp: same as resetType variable here | 
 |  *  asyncResp update the response | 
 | */ | 
 |  | 
 | void delayResetSystem(std::string_view systemName, int delayTimeSecs, | 
 |                       std::string_view resetType, | 
 |                       const std::shared_ptr<bmcweb::AsyncResp>&  asyncResp); | 
 |  | 
 | /* | 
 |  * Handles System reset by creating the DBus call associated with the requested | 
 |  * reset. | 
 |  * | 
 |  * systemPath is object path of the related Item.System object to call the | 
 |  * ComputerSystem.Reset call on. This is needed to find its associated power | 
 |  * control objects. | 
 |  * | 
 |  * If systemPath is /xyz/openbmc_project/state/host1 (sample Item.System object) | 
 |  * Then host power state objects are associated with forward association | 
 |  * system_power and chassis power state objects are associated with forward | 
 |  * asociation chassis_power | 
 |  */ | 
 | inline void sendSystemResetAction(const crow::Request& req, | 
 |                            const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |                            const std::string& systemPath, | 
 |                            const std::string& systemName) | 
 | { | 
 |     std::string resetType; | 
 |     std::optional<int> delayTimeSec; | 
 |     if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", resetType, | 
 |                                    "Delay", delayTimeSec)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     if (resetType == "Nmi") | 
 |     { | 
 |         doNMI(asyncResp); | 
 |         return; | 
 |     } | 
 |  | 
 |     SystemResetCommand systemResetCommand = GetSystemResetCommandFromInput(resetType); | 
 |  | 
 |     if (!systemResetCommand.validCommand) | 
 |     { | 
 |         messages::actionParameterUnknown(asyncResp->res, "Reset", resetType); | 
 |         return; | 
 |     } | 
 |  | 
 |     // Get the command and host vs. chassis | 
 |     std::string command = systemResetCommand.command; | 
 |     bool hostCommand = systemResetCommand.hostCommand; | 
 |     if (delayTimeSec.has_value() && delayTimeSec.value() > 900) // 15 minutes | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "reset delay timer too large, >900"; | 
 |         messages::propertyValueOutOfRange(asyncResp->res, "900", "Delay"); | 
 |         return; | 
 |     } | 
 |     if (delayTimeSec.has_value() && delayTimeSec.value() <= 900 && | 
 |         (resetType == "On" || resetType == "ForceOn" || | 
 |          resetType == "ForceOff" || resetType == "ForceRestart" || | 
 |          resetType == "GracefulShutdown" || resetType == "PowerCycle")) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG << "Seting delayed " << resetType; | 
 |         delayResetSystem(systemName, delayTimeSec.value(), resetType, asyncResp); | 
 |         return; | 
 |     } | 
 |     if (hostCommand) | 
 |     { | 
 |  | 
 |         // For single system servers, the power state object is hardcoded | 
 |         if (systemPath.empty()) | 
 |         { | 
 |             sendPowerSystemCommand( | 
 |                 asyncResp, command, resetType, "xyz.openbmc_project.State.Host", | 
 |                 "/xyz/openbmc_project/state/host0", | 
 |                 "xyz.openbmc_project.State.Host", "RequestedHostTransition"); | 
 |             return; | 
 |         } | 
 |  | 
 |         managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |         managedStore::GetManagedObjectStore()->getAssociatedSubTree( | 
 |             sdbusplus::message::object_path(systemPath + "/host_power"), | 
 |             sdbusplus::message::object_path("/xyz/openbmc_project/state"), 0, | 
 |             std::array<std::string_view, 1>{"xyz.openbmc_project.State.Host"}, | 
 |             requestContext, | 
 |             [asyncResp, command, | 
 |              resetType](const boost::system::error_code ec, | 
 |                         const dbus::utility::MapperGetSubTreeResponse& objects) { | 
 |             if (ec || objects.empty()) | 
 |             { | 
 |                 BMCWEB_LOG_ERROR | 
 |                     << "Host power control not associated with system object"; | 
 |                 messages::internalError(asyncResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             // There should only be one host power control object associated | 
 |             // with this system | 
 |             if (objects.size() > 1) | 
 |             { | 
 |                 BMCWEB_LOG_ERROR | 
 |                     << "Too many host power control objects associated with the system"; | 
 |                 messages::internalError(asyncResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             // Map1: [key, val] -> [objectPath, Map2] | 
 |             // Map2: [key, val] -> [serviceName, list of interfaces] | 
 |             const std::string powerControlPath = objects[0].first; | 
 |  | 
 |             // This object path can have multiple services, we need the one that | 
 |             // contains "State.Host" | 
 |             for (const auto& serviceMapping : objects[0].second) | 
 |             { | 
 |                 // Host 1 object is implemented by | 
 |                 // xyz.openbmc_project.State.Host1 Cannot directly find | 
 |                 // interface as the different host's have different services | 
 |                 if (absl::StrContains(serviceMapping.first, "xyz.openbmc_project.State.Host")) | 
 |                 { | 
 |                     sendPowerSystemCommand( | 
 |                         asyncResp, command, resetType, serviceMapping.first, | 
 |                         powerControlPath, "xyz.openbmc_project.State.Host", | 
 |                         "RequestedHostTransition"); | 
 |                     return; | 
 |                 } | 
 |             } | 
 |  | 
 |             BMCWEB_LOG_ERROR | 
 |                 << "Could not find correct host Power Control Object"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         }); | 
 |     } | 
 |     else | 
 |     { | 
 |         // For single system servers, the power state object is hardcoded | 
 |         if (systemPath.empty()) | 
 |         { | 
 |             sendPowerSystemCommand(asyncResp, command, resetType, | 
 |                                    "xyz.openbmc_project.State.Chassis", | 
 |                                    "/xyz/openbmc_project/state/chassis0", | 
 |                                    "xyz.openbmc_project.State.Chassis", | 
 |                                    "RequestedPowerTransition"); | 
 |             return; | 
 |         } | 
 |  | 
 |         managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |         managedStore::GetManagedObjectStore()->getAssociatedSubTree( | 
 |             sdbusplus::message::object_path(systemPath + "/chassis_power"), | 
 |             sdbusplus::message::object_path("/xyz/openbmc_project/state"), 0, | 
 |             std::array<std::string_view, 1>{ | 
 |                 "xyz.openbmc_project.State.Chassis"}, | 
 |             requestContext, | 
 |             [asyncResp, command, | 
 |              resetType](const boost::system::error_code ec, | 
 |                         const dbus::utility::MapperGetSubTreeResponse& objects) { | 
 |             if (ec || objects.empty()) | 
 |             { | 
 |                 BMCWEB_LOG_ERROR | 
 |                     << "Chassis power control not associated with system object"; | 
 |                 messages::internalError(asyncResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             // There should only be one chassis power control object associated | 
 |             // with this system | 
 |             if (objects.size() > 1) | 
 |             { | 
 |                 BMCWEB_LOG_ERROR | 
 |                     << "Too many chassis power control objects associated with the system"; | 
 |                 messages::internalError(asyncResp->res); | 
 |                 return; | 
 |             } | 
 |  | 
 |             // Map1: [key, val] -> [objectPath, Map2] | 
 |             // Map2: [key, val] -> [serviceName, list of interfaces] | 
 |             const std::string powerControlPath = objects[0].first; | 
 |  | 
 |             // This object path can have multiple services, we need the one that | 
 |             // contains "State.Host" | 
 |             for (const auto& serviceMapping : objects[0].second) | 
 |             { | 
 |                 if (absl::StrContains(serviceMapping.first, "xyz.openbmc_project.State.Chassis")) | 
 |                 { | 
 |                     sendPowerSystemCommand( | 
 |                         asyncResp, command, resetType, serviceMapping.first, | 
 |                         powerControlPath, "xyz.openbmc_project.State.Chassis", | 
 |                         "RequestedPowerTransition"); | 
 |                     return; | 
 |                 } | 
 |             } | 
 |  | 
 |             BMCWEB_LOG_ERROR | 
 |                 << "Could not find correct chassis Power Control Object"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         }); | 
 |     } | 
 | } | 
 |  | 
 | inline void handlePostComputerSystemReset(App& app, const crow::Request& req, | 
 |                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |                    const std::string& systemName) { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTreePaths( | 
 |         "/", 0, systemInterfaces, requestContext, | 
 |         [req, asyncResp, | 
 |             systemName](const boost::system::error_code& ec, | 
 |                         const std::vector<std::string>& objects) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |         // If there are less than 2 Item.Systems assume singlehost | 
 |         if (objects.size() < 2) | 
 |         { | 
 |             if (systemName != "system") | 
 |             { | 
 |                 messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                             systemName); | 
 |                 return; | 
 |             } | 
 |             sendSystemResetAction(req, asyncResp, "", systemName); | 
 |             return; | 
 |         } | 
 |         // Otherwise list all systems | 
 |         for (const auto& object : objects) | 
 |         { | 
 |             std::string objectName = object.substr(object.rfind('/') + 1); | 
 |             // Found system object | 
 |             if (systemName == objectName) | 
 |             { | 
 |                 sendSystemResetAction(req, asyncResp, object, systemName); | 
 |                 return; | 
 |             } | 
 |         } | 
 |  | 
 |         // Could not find system object | 
 |         messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                     systemName); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * SystemActionsReset class supports handle POST method for Reset action. | 
 |  * The class retrieves and sends data directly to D-Bus. | 
 |  */ | 
 | inline void requestRoutesSystemActionsReset(App& app) | 
 | { | 
 |     /** | 
 |      * Function handles POST method request. | 
 |      * Analyzes POST body message before sends Reset request data to D-Bus. | 
 |      */ | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Actions/ComputerSystem.Reset/") | 
 |         .privileges(redfish::privileges::postComputerSystem) | 
 |         .methods(boost::beast::http::verb::post)( | 
 |             std::bind_front(handlePostComputerSystemReset, std::ref(app)));; | 
 | } | 
 |  | 
 | inline void handlePostSystemBootGuestOS( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     const std::string systemSuffix = getSystemSuffix(systemName); | 
 |     const std::string bmDriveCleaningDoneFlagPath = | 
 |         "/run/bm-drive-cleaning-done.flag" + systemSuffix; | 
 |     const std::string bmDriveCleaningDoneAckFlagPath = | 
 |         "/run/bm-drive-cleaning-done-ack.flag" + systemSuffix; | 
 |  | 
 |     std ::error_code ec; | 
 |     if (std::filesystem::exists(bmDriveCleaningDoneFlagPath, ec) || | 
 |         std::filesystem::exists(bmDriveCleaningDoneAckFlagPath, ec)) | 
 |     { | 
 |         BMCWEB_LOG_DEBUG | 
 |             << "NERF was successfully notified to go into UEFI boot already"; | 
 |         messages::success(asyncResp->res); | 
 |         return; | 
 |     } | 
 |     if (!std::filesystem::exists(bmDriveCleaningDoneFlagPath, ec)) | 
 |     { | 
 |         std::ofstream ofs; | 
 |         ofs.open(bmDriveCleaningDoneFlagPath, std::ofstream::out); | 
 |         ofs.close(); | 
 |  | 
 |         BMCWEB_LOG_DEBUG << "Successfully created flag file: " | 
 |                          << bmDriveCleaningDoneFlagPath; | 
 |  | 
 |         messages::success(asyncResp->res); | 
 |         return; | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Notify BMC to let NERF boot to Guest OS | 
 |  */ | 
 | inline void requestRoutesSystemBootGuestOS(App& app) | 
 | { | 
 |     /** | 
 |      * Function handles POST method request. | 
 |      */ | 
 |     BMCWEB_ROUTE( | 
 |         app, | 
 |         "/redfish/v1/Systems/<str>/Actions/Oem/GoogleComputerSystem.BootGuestOS/") | 
 |         .privileges(redfish::privileges::postComputerSystem) | 
 |         .methods(boost::beast::http::verb::post)( | 
 |             std::bind_front(handlePostSystemBootGuestOS, std::ref(app))); | 
 | } | 
 |  | 
 | inline void handleGetSystemBootGuestOSInfo( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; | 
 |     asyncResp->res.jsonValue["@odata.id"] = | 
 |         "/redfish/v1/System/" + systemName + "/Oem/Google/BootGuestOSActionInfo"; | 
 |     asyncResp->res.jsonValue["Name"] = "Boot Guest OS"; | 
 |     asyncResp->res.jsonValue["Id"] = "BootGuestOS"; | 
 | } | 
 |  | 
 | /** | 
 |  * Action Info for notifying BMC to let NERF boot to Guest OS | 
 |  */ | 
 | inline void requestRoutesSystemBootGuestOSInfo(App& app) | 
 | { | 
 |     /** | 
 |      * Function handles POST method request. | 
 |      */ | 
 |     BMCWEB_ROUTE(app, | 
 |                  "/redfish/v1/Systems/<str>/Oem/Google/BootGuestOSActionInfo/") | 
 |         .privileges(redfish::privileges::getActionInfo) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleGetSystemBootGuestOSInfo, std::ref(app))); | 
 | } | 
 |  | 
 | inline void handleComputerSystemCollectionHead( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); | 
 | } | 
 |  | 
 | inline void 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) | 
 | { | 
 |     if (ec) | 
 |     { | 
 |         messages::internalError(asyncResp->res); | 
 |         return; | 
 |     } | 
 |     for (const auto& data : socketData) | 
 |     { | 
 |         const std::string& socketPath = get<0>(data); | 
 |         const std::string& protocolName = get<1>(data); | 
 |         bool isProtocolEnabled = get<2>(data); | 
 |         nlohmann::json& dataJson = asyncResp->res.jsonValue["SerialConsole"]; | 
 |         dataJson[protocolName]["ServiceEnabled"] = isProtocolEnabled; | 
 |         // need to retrieve port number for | 
 |         // obmc-console-ssh service | 
 |         if (protocolName == "SSH") | 
 |         { | 
 |             managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |             getPortNumber( | 
 |                 socketPath, requestContext, | 
 |                 [asyncResp, protocolName](const boost::system::error_code ec1, | 
 |                                           int portNumber) { | 
 |                 if (ec1) | 
 |                 { | 
 |                     messages::internalError(asyncResp->res); | 
 |                     return; | 
 |                 } | 
 |                 nlohmann::json& dataJson1 = | 
 |                     asyncResp->res.jsonValue["SerialConsole"]; | 
 |                 dataJson1[protocolName]["Port"] = portNumber; | 
 |             }); | 
 |         } | 
 |     } | 
 | } | 
 |  | 
 | inline void | 
 |     handleComputerSystem(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |                          const std::string& systemObjectPath, | 
 |                          const std::string& systemName, bool multiHost) | 
 | { | 
 |     // Handling both single-system and multi-system cases | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); | 
 |     asyncResp->res.jsonValue["@odata.type"] = | 
 |         "#ComputerSystem.v1_16_0.ComputerSystem"; | 
 |     asyncResp->res.jsonValue["Name"] = systemName; | 
 |     asyncResp->res.jsonValue["Id"] = systemName; | 
 |     asyncResp->res.jsonValue["SystemType"] = "Physical"; | 
 |     asyncResp->res.jsonValue["Description"] = "Computer System"; | 
 |     asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + systemName; | 
 |     asyncResp->res.jsonValue["Actions"]["#ComputerSystem.Reset"]["target"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Actions/ComputerSystem.Reset"; | 
 |     asyncResp->res | 
 |         .jsonValue["Actions"]["#ComputerSystem.Reset"]["@Redfish.ActionInfo"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/ResetActionInfo"; | 
 |     asyncResp->res.jsonValue["Processors"]["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Processors"; | 
 |     asyncResp->res.jsonValue["Storage"]["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Storage"; | 
 |     getBMReady(asyncResp); | 
 |     if constexpr (enableGoogleBaremetal) | 
 |     { | 
 |         asyncResp->res | 
 |             .jsonValue["Actions"]["Oem"]["Google"] | 
 |                       ["#GoogleComputerSystem.BootGuestOS"]["target"] = | 
 |             "/redfish/v1/Systems/" + systemName + | 
 |             "/Actions/Oem/GoogleComputerSystem.BootGuestOS"; | 
 |         asyncResp->res.jsonValue["Actions"]["Oem"]["Google"] | 
 |                                 ["#GoogleComputerSystem.BootGuestOS"] | 
 |                                 ["@Redfish.ActionInfo"] = | 
 |             "/redfish/v1/Systems/" + systemName + | 
 |             "/Oem/Google/BootGuestOSActionInfo"; | 
 |         asyncResp->res | 
 |             .jsonValue["Oem"]["Google"]["BareMetalInstance"]["@odata.id"] = | 
 |             "/redfish/v1/Systems/" + systemName + | 
 |             "/Oem/Google/BareMetalInstance"; | 
 |         getNERFStatus(asyncResp, systemName); | 
 |     } | 
 |     asyncResp->res.jsonValue["LogServices"]["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/LogServices"; | 
 |     asyncResp->res.jsonValue["Memory"]["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Memory"; | 
 |  | 
 |     nlohmann::json::array_t managedBy; | 
 |     nlohmann::json& manager = managedBy.emplace_back(); | 
 |     manager["@odata.id"] = "/redfish/v1/Managers/bmc"; | 
 |     asyncResp->res.jsonValue["Links"]["ManagedBy"] = std::move(managedBy); | 
 |  | 
 |     getMainChassisId(asyncResp, | 
 |                      [](const std::string& chassisId, | 
 |                         const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { | 
 |         nlohmann::json::array_t chassisArray; | 
 |         nlohmann::json& chassis = chassisArray.emplace_back(); | 
 |         chassis["@odata.id"] = | 
 |             crow::utility::urlFromPieces("redfish", "v1", "Chassis", chassisId); | 
 |         aRsp->res.jsonValue["Links"]["Chassis"] = std::move(chassisArray); | 
 |     }); | 
 |  | 
 |     managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |     asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; | 
 |  | 
 |     managedStore::GetManagedObjectStore()->getAssociatedSubTree( | 
 |         sdbusplus::message::object_path(systemObjectPath + "/host_power"), | 
 |         sdbusplus::message::object_path("/xyz/openbmc_project/state"), 0, | 
 |         hostStateInterfaces, requestContext, | 
 |         [asyncResp, systemObjectPath]( | 
 |             const boost::system::error_code& ec, | 
 |             const dbus::utility::MapperGetSubTreeResponse& objects) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_ERROR | 
 |                 << "Chassis power control not associated with system object"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // There should only be one chassis power control object associated with | 
 |         // this system | 
 |         if (objects.size() > 1) | 
 |         { | 
 |             BMCWEB_LOG_ERROR | 
 |                 << "Too many chassis power control objects associated with the system"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         getHostState(asyncResp, systemObjectPath, objects); | 
 |         getLastResetTime(asyncResp, systemObjectPath, objects); | 
 |     }); | 
 |  | 
 |     // Handling multi-system and single-system separately. In the future, the | 
 |     // goal is to not have to separate these two. However, until code is | 
 |     // refactored, there will be diffs. | 
 |  | 
 |     // Handle single-system code | 
 |     if (!multiHost) | 
 |     { | 
 |         asyncResp->res.jsonValue["ProcessorSummary"]["Count"] = 0; | 
 |         asyncResp->res.jsonValue["ProcessorSummary"]["Status"]["State"] = | 
 |             "Disabled"; | 
 |         asyncResp->res.jsonValue["MemorySummary"]["TotalSystemMemoryGiB"] = | 
 |             uint64_t(0); | 
 |         asyncResp->res.jsonValue["MemorySummary"]["Status"]["State"] = | 
 |             "Disabled"; | 
 |         asyncResp->res.jsonValue["FabricAdapters"]["@odata.id"] = | 
 |             "/redfish/v1/Systems/system/FabricAdapters"; | 
 |  | 
 |         asyncResp->res.jsonValue["Bios"]["@odata.id"] = | 
 |             "/redfish/v1/Systems/system/Bios"; | 
 |  | 
 |         asyncResp->res.jsonValue["Status"]["Health"] = "OK"; | 
 |  | 
 |         // Fill in SerialConsole info | 
 |         asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; | 
 |         asyncResp->res.jsonValue["SerialConsole"]["IPMI"]["ServiceEnabled"] = | 
 |             true; | 
 |  | 
 |         // TODO (Gunnar): Should look for obmc-console-ssh@2200.service | 
 |         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["ServiceEnabled"] = | 
 |             true; | 
 |         asyncResp->res.jsonValue["SerialConsole"]["SSH"]["Port"] = 2200; | 
 |         asyncResp->res | 
 |             .jsonValue["SerialConsole"]["SSH"]["HotKeySequenceDisplay"] = | 
 |             "Press ~. to exit console"; | 
 |         getPortStatusAndPath(std::span{protocolToDBusForSystems}, | 
 |                              requestContext, | 
 |                              std::bind_front(afterPortRequest, asyncResp)); | 
 |  | 
 | #ifdef BMCWEB_ENABLE_KVM | 
 |         // Fill in GraphicalConsole info | 
 |         asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; | 
 |         asyncResp->res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = | 
 |             4; | 
 |         asyncResp->res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = | 
 |             nlohmann::json::array_t({"KVMIP"}); | 
 |  | 
 | #endif // BMCWEB_ENABLE_KVM | 
 |  | 
 |         auto health = std::make_shared<HealthPopulate>(asyncResp); | 
 | #ifdef HEALTH_POPULATE | 
 |         constexpr std::array<std::string_view, 4> inventoryForSystems{ | 
 |             "xyz.openbmc_project.Inventory.Item.Dimm", | 
 |             "xyz.openbmc_project.Inventory.Item.Cpu", | 
 |             "xyz.openbmc_project.Inventory.Item.Drive", | 
 |             "xyz.openbmc_project.Inventory.Item.StorageController"}; | 
 |  | 
 |         managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |         managedStore::GetManagedObjectStore()->getSubTreePaths( | 
 |             "/", 0, inventoryForSystems, requestContext, | 
 |             [health](const boost::system::error_code& ec, | 
 |                      const std::vector<std::string>& resp) { | 
 |             if (ec) | 
 |             { | 
 |                 // no inventory | 
 |                 return; | 
 |             } | 
 |  | 
 |             health->inventory = resp; | 
 |         }); | 
 |         health->populate(); | 
 | #endif | 
 |  | 
 |         getLocationIndicatorActive(asyncResp); | 
 |         // TODO (Gunnar): Remove IndicatorLED after enough time has | 
 |         // passed | 
 |         getIndicatorLedState(asyncResp); | 
 |         getComputerSystem(asyncResp, health); | 
 |         getBootProperties(asyncResp); | 
 |         getBootProgress(asyncResp); | 
 |         getBootProgressLastStateTime(asyncResp); | 
 |         getBootProgressOemLastState(asyncResp); | 
 |         getPCIeDeviceList(asyncResp, "PCIeDevices"); | 
 |         getHostWatchdogTimer(asyncResp); | 
 |         getPowerRestorePolicy(asyncResp); | 
 |         getAutomaticRetry(asyncResp); | 
 | #ifdef BMCWEB_ENABLE_REDFISH_PROVISIONING_FEATURE | 
 |         getProvisioningStatus(asyncResp); | 
 | #endif | 
 |         getTrustedModuleRequiredToBoot(asyncResp); | 
 |         getPowerMode(asyncResp); | 
 |         getIdlePowerSaver(asyncResp); | 
 |         // Enabled boot time only for single host | 
 | #ifdef BMCWEB_ENABLE_REDFISH_BOOT_TIME | 
 |         asyncResp->res.jsonValue["Oem"]["Google"]["BootTime"]["@odata.id"] = | 
 |             "/redfish/v1/Systems/system/Oem/Google/BootTime"; | 
 | #endif | 
 |     } | 
 | } | 
 |  | 
 | inline void handleGetComputerSystemCollection( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     if (systemName == "hypervisor") | 
 |     { | 
 |         handleHypervisorSystemGet(asyncResp); | 
 |         return; | 
 |     } | 
 |  | 
 |     managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTreePaths( | 
 |         "/", 0, systemInterfaces, requestContext, | 
 |         [asyncResp, systemName](const boost::system::error_code& ec, | 
 |                                 const std::vector<std::string>& objects) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |  | 
 |         // If there are less than 2 Item.Systems assume singlehost | 
 |         if (objects.size() < 2) | 
 |         { | 
 |             if (systemName != "system") | 
 |             { | 
 |                 messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                            systemName); | 
 |                 return; | 
 |             } | 
 |             handleComputerSystem(asyncResp, "", systemName, false); | 
 |             return; | 
 |         } | 
 |         // Otherwise find system | 
 |         for (const auto& object : objects) | 
 |         { | 
 |             std::string objectName = object.substr(object.rfind('/') + 1); | 
 |             // Found system object | 
 |             if (systemName == objectName) | 
 |             { | 
 |                 handleComputerSystem(asyncResp, object, systemName, true); | 
 |                 return; | 
 |             } | 
 |         } | 
 |  | 
 |         // Could not find system object | 
 |         messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                    systemName); | 
 |     }); | 
 | } | 
 |  | 
 | inline void handlePatchComputerSystemCollection( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     if (systemName != "system") | 
 |     { | 
 |         messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                    systemName); | 
 |         return; | 
 |     } | 
 |  | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ComputerSystem/ComputerSystem.json>; rel=describedby"); | 
 |  | 
 |     std::optional<bool> locationIndicatorActive; | 
 |     std::optional<std::string> indicatorLed; | 
 |     std::optional<std::string> assetTag; | 
 |     std::optional<std::string> powerRestorePolicy; | 
 |     std::optional<std::string> powerMode; | 
 |     std::optional<bool> wdtEnable; | 
 |     std::optional<std::string> wdtTimeOutAction; | 
 |     std::optional<std::string> bootSource; | 
 |     std::optional<std::string> bootType; | 
 |     std::optional<std::string> bootEnable; | 
 |     std::optional<std::string> bootAutomaticRetry; | 
 |     std::optional<bool> bootTrustedModuleRequired; | 
 |     std::optional<bool> ipsEnable; | 
 |     std::optional<uint8_t> ipsEnterUtil; | 
 |     std::optional<uint64_t> ipsEnterTime; | 
 |     std::optional<uint8_t> ipsExitUtil; | 
 |     std::optional<uint64_t> ipsExitTime; | 
 |  | 
 |     // clang-format off | 
 |             if (!json_util::readJsonPatch( | 
 |                     req, asyncResp->res, | 
 |                     "IndicatorLED", indicatorLed, | 
 |                     "LocationIndicatorActive", locationIndicatorActive, | 
 |                     "AssetTag", assetTag, | 
 |                     "PowerRestorePolicy", powerRestorePolicy, | 
 |                     "PowerMode", powerMode, | 
 |                     "HostWatchdogTimer/FunctionEnabled", wdtEnable, | 
 |                     "HostWatchdogTimer/TimeoutAction", wdtTimeOutAction, | 
 |                     "Boot/BootSourceOverrideTarget", bootSource, | 
 |                     "Boot/BootSourceOverrideMode", bootType, | 
 |                     "Boot/BootSourceOverrideEnabled", bootEnable, | 
 |                     "Boot/AutomaticRetryConfig", bootAutomaticRetry, | 
 |                     "Boot/TrustedModuleRequiredToBoot", bootTrustedModuleRequired, | 
 |                     "IdlePowerSaver/Enabled", ipsEnable, | 
 |                     "IdlePowerSaver/EnterUtilizationPercent", ipsEnterUtil, | 
 |                     "IdlePowerSaver/EnterDwellTimeSeconds", ipsEnterTime, | 
 |                     "IdlePowerSaver/ExitUtilizationPercent", ipsExitUtil, | 
 |                     "IdlePowerSaver/ExitDwellTimeSeconds", ipsExitTime)) | 
 |             { | 
 |                 return; | 
 |             } | 
 |     // clang-format on | 
 |  | 
 |     asyncResp->res.result(boost::beast::http::status::no_content); | 
 |  | 
 |     if (assetTag) | 
 |     { | 
 |         setAssetTag(asyncResp, *assetTag); | 
 |     } | 
 |  | 
 |     if (wdtEnable || wdtTimeOutAction) | 
 |     { | 
 |         setWDTProperties(asyncResp, wdtEnable, wdtTimeOutAction); | 
 |     } | 
 |  | 
 |     if (bootSource || bootType || bootEnable) | 
 |     { | 
 |         setBootProperties(asyncResp, bootSource, bootType, bootEnable); | 
 |     } | 
 |     if (bootAutomaticRetry) | 
 |     { | 
 |         setAutomaticRetry(asyncResp, *bootAutomaticRetry); | 
 |     } | 
 |  | 
 |     if (bootTrustedModuleRequired) | 
 |     { | 
 |         setTrustedModuleRequiredToBoot(asyncResp, *bootTrustedModuleRequired); | 
 |     } | 
 |  | 
 |     if (locationIndicatorActive) | 
 |     { | 
 |         setLocationIndicatorActive(asyncResp, *locationIndicatorActive); | 
 |     } | 
 |  | 
 |     // TODO (Gunnar): Remove IndicatorLED after enough time has | 
 |     // passed | 
 |     if (indicatorLed) | 
 |     { | 
 |         setIndicatorLedState(asyncResp, *indicatorLed); | 
 |         asyncResp->res.addHeader(boost::beast::http::field::warning, | 
 |                                  "299 - \"IndicatorLED is deprecated. Use " | 
 |                                  "LocationIndicatorActive instead.\""); | 
 |     } | 
 |  | 
 |     if (powerRestorePolicy) | 
 |     { | 
 |         setPowerRestorePolicy(asyncResp, *powerRestorePolicy); | 
 |     } | 
 |  | 
 |     if (powerMode) | 
 |     { | 
 |         setPowerMode(asyncResp, *powerMode); | 
 |     } | 
 |  | 
 |     if (ipsEnable || ipsEnterUtil || ipsEnterTime || ipsExitUtil || ipsExitTime) | 
 |     { | 
 |         setIdlePowerSaver(asyncResp, ipsEnable, ipsEnterUtil, ipsEnterTime, | 
 |                           ipsExitUtil, ipsExitTime); | 
 |     } | 
 | } | 
 |  | 
 | inline void handleGetBareMetalInstance( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/GoogleBareMetalInstance/GoogleBareMetalInstance.json>; rel=describedby"); | 
 |  | 
 |     getBMInstance(asyncResp, systemName); | 
 | } | 
 |  | 
 | inline void handlePatchBareMetalInstance( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/GoogleBareMetalInstance/GoogleBareMetalInstance.json>; rel=describedby"); | 
 |     std::optional<std::string> bmiAssetTag; | 
 |     std::optional<std::string> bmiBoardSerialNumber; | 
 |     std::optional<std::string> bmiFamily; | 
 |     std::optional<std::string> bmiProductName; | 
 |     std::optional<std::string> bmiSKU; | 
 |     std::optional<std::string> bmiSystemSerialNumber; | 
 |     std::optional<std::string> bmiUUID; | 
 |  | 
 |     // clang-format off | 
 |     if (!json_util::readJsonPatch( | 
 |         req, asyncResp->res, | 
 |         "AssetTag", bmiAssetTag, | 
 |         "BoardSerialNumber", bmiBoardSerialNumber, | 
 |         "Family", bmiFamily, | 
 |         "ProductName", bmiProductName, | 
 |         "SKU", bmiSKU, | 
 |         "SystemSerialNumber", bmiSystemSerialNumber, | 
 |         "UUID", bmiUUID)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     // clang-format on | 
 |     asyncResp->res.result(boost::beast::http::status::no_content); | 
 |     if (bmiAssetTag || bmiBoardSerialNumber || bmiFamily || bmiProductName || | 
 |         bmiSKU || bmiSystemSerialNumber || bmiUUID) | 
 |     { | 
 |         setBMInstance(asyncResp, systemName, bmiAssetTag.value_or(""), | 
 |                       bmiBoardSerialNumber.value_or(""), bmiFamily.value_or(""), | 
 |                       bmiProductName.value_or(""), bmiSKU.value_or(""), | 
 |                       bmiSystemSerialNumber.value_or(""), bmiUUID.value_or("")); | 
 |     } | 
 | } | 
 |  | 
 | /** | 
 |  * Systems derived class for delivering Computer Systems Schema. | 
 |  */ | 
 | inline void requestRoutesSystems(App& app) | 
 | { | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") | 
 |         .privileges(redfish::privileges::headComputerSystem) | 
 |         .methods(boost::beast::http::verb::head)( | 
 |             std::bind_front(handleComputerSystemCollectionHead, std::ref(app))); | 
 |     /** | 
 |      * Functions triggers appropriate requests on DBus | 
 |      */ | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") | 
 |         .privileges(redfish::privileges::getComputerSystem) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleGetComputerSystemCollection, std::ref(app))); | 
 |  | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/") | 
 |         .privileges(redfish::privileges::patchComputerSystem) | 
 |         .methods(boost::beast::http::verb::patch)(std::bind_front( | 
 |             handlePatchComputerSystemCollection, std::ref(app))); | 
 |  | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Oem/Google/BareMetalInstance/") | 
 |         .privileges(redfish::privileges::getComputerSystem) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleGetBareMetalInstance, std::ref(app))); | 
 |  | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Oem/Google/BareMetalInstance/") | 
 |         .privileges(redfish::privileges::patchComputerSystem) | 
 |         .methods(boost::beast::http::verb::patch)( | 
 |             std::bind_front(handlePatchBareMetalInstance, std::ref(app))); | 
 | } | 
 |  | 
 | inline void handleSystemCollectionResetActionHead( | 
 |     crow::App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); | 
 | } | 
 |  | 
 | inline void createResetActionInfoResponse( | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     asyncResp->res.addHeader( | 
 |         boost::beast::http::field::link, | 
 |         "</redfish/v1/JsonSchemas/ActionInfo/ActionInfo.json>; rel=describedby"); | 
 |  | 
 |     asyncResp->res.jsonValue["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/ResetActionInfo"; | 
 |     asyncResp->res.jsonValue["@odata.type"] = "#ActionInfo.v1_1_2.ActionInfo"; | 
 |     asyncResp->res.jsonValue["Name"] = "Reset Action Info"; | 
 |     asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; | 
 |  | 
 |     nlohmann::json::array_t parameters; | 
 |     nlohmann::json::object_t parameter; | 
 |  | 
 |     parameter["Name"] = "ResetType"; | 
 |     parameter["Required"] = true; | 
 |     parameter["DataType"] = "String"; | 
 |     parameter["Delay"] = "Number"; | 
 |     nlohmann::json::array_t allowableValues; | 
 |     allowableValues.emplace_back("On"); | 
 |     allowableValues.emplace_back("ForceOff"); | 
 |     allowableValues.emplace_back("ForceOn"); | 
 |     allowableValues.emplace_back("ForceRestart"); | 
 |     allowableValues.emplace_back("GracefulRestart"); | 
 |     allowableValues.emplace_back("GracefulShutdown"); | 
 |     allowableValues.emplace_back("PowerCycle"); | 
 |     allowableValues.emplace_back("Nmi"); | 
 |     allowableValues.emplace_back("ReallyGracefulShutDownTechDebt"); | 
 |     parameter["AllowableValues"] = std::move(allowableValues); | 
 |     parameters.emplace_back(std::move(parameter)); | 
 |  | 
 |     nlohmann::json::object_t delayParameter; | 
 |     delayParameter["Name"] = "Delay"; | 
 |     delayParameter["Required"] = false; | 
 |     delayParameter["DataType"] = "Number"; | 
 |     parameters.emplace_back(std::move(delayParameter)); | 
 |     asyncResp->res.jsonValue["Parameters"] = std::move(parameters); | 
 | } | 
 |  | 
 | inline void handleGetSystemResetActionInfo( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     if (systemName == "hypervisor") | 
 |     { | 
 |         handleHypervisorResetActionGet(asyncResp); | 
 |         return; | 
 |     } | 
 |  | 
 |     managedStore::ManagedObjectStoreContext requestContext(asyncResp); | 
 |     managedStore::GetManagedObjectStore()->getSubTreePaths( | 
 |         "/", 0, systemInterfaces, requestContext, | 
 |         [asyncResp, systemName](const boost::system::error_code& ec, | 
 |                                 const std::vector<std::string>& objects) { | 
 |         if (ec) | 
 |         { | 
 |             BMCWEB_LOG_DEBUG << "DBUS response error"; | 
 |             messages::internalError(asyncResp->res); | 
 |             return; | 
 |         } | 
 |         // If there are less than 2 Item.Systems assume singlehost | 
 |         if (objects.size() < 2) | 
 |         { | 
 |             if (systemName != "system") | 
 |             { | 
 |                 messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                            systemName); | 
 |                 return; | 
 |             } | 
 |             createResetActionInfoResponse(asyncResp, systemName); | 
 |             return; | 
 |         } | 
 |         // Otherwise list all systems | 
 |         for (const auto& object : objects) | 
 |         { | 
 |             std::string objectName = object.substr(object.rfind('/') + 1); | 
 |             // Found system object | 
 |             if (systemName == objectName) | 
 |             { | 
 |                 createResetActionInfoResponse(asyncResp, systemName); | 
 |                 return; | 
 |             } | 
 |         } | 
 |  | 
 |         // Could not find system object | 
 |         messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                    systemName); | 
 |     }); | 
 | } | 
 |  | 
 | /** | 
 |  * SystemResetActionInfo derived class for delivering Computer Systems | 
 |  * ResetType AllowableValues using ResetInfo schema. | 
 |  */ | 
 | inline void requestRoutesSystemResetActionInfo(App& app) | 
 | { | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/ResetActionInfo/") | 
 |         .privileges(redfish::privileges::headActionInfo) | 
 |         .methods(boost::beast::http::verb::head)(std::bind_front( | 
 |             handleSystemCollectionResetActionHead, std::ref(app))); | 
 |     /** | 
 |      * Functions triggers appropriate requests on DBus | 
 |      */ | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/ResetActionInfo/") | 
 |         .privileges(redfish::privileges::getActionInfo) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleGetSystemResetActionInfo, std::ref(app))); | 
 | } | 
 |  | 
 | inline void handleHostBootTimeDataGet( | 
 |     App& app, const crow::Request& req, | 
 |     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, | 
 |     const std::string& systemName) | 
 | { | 
 |     if (!redfish::setUpRedfishRoute(app, req, asyncResp)) | 
 |     { | 
 |         return; | 
 |     } | 
 |  | 
 |     // only for single host | 
 |     if (systemName != "system") | 
 |     { | 
 |         messages::resourceNotFound(asyncResp->res, "ComputerSystem", | 
 |                                    systemName); | 
 |         return; | 
 |     } | 
 |  | 
 |     boot_time_utils::PopulateDefaultBootTimeProperties(asyncResp); | 
 |     asyncResp->res.jsonValue["@odata.id"] = | 
 |         "/redfish/v1/Systems/" + systemName + "/Oem/Google/BootTime"; | 
 |  | 
 |     std::shared_ptr<std::vector<boot_time_utils::Checkpoint>> hostCheckpoints = | 
 |         std::make_shared<std::vector<boot_time_utils::Checkpoint>>(); | 
 |     std::shared_ptr<std::vector<boot_time_utils::Duration>> hostDurations = | 
 |         std::make_shared<std::vector<boot_time_utils::Duration>>(); | 
 |     std::shared_ptr<std::vector<boot_time_utils::Checkpoint>> bmcCheckpoints = | 
 |         std::make_shared<std::vector<boot_time_utils::Checkpoint>>(); | 
 |     std::shared_ptr<bool> hostIsRebooting = std::make_shared<bool>(false); | 
 |  | 
 |     std::shared_ptr<int> waitingForLoadingData = std::make_shared<int>(4); | 
 |     std::shared_ptr<bool> errorOccurred = std::make_shared<bool>(false); | 
 |  | 
 |     std::function<void()> dbusSuccessCallback = | 
 |         [asyncResp, hostCheckpoints, hostDurations, bmcCheckpoints, | 
 |          hostIsRebooting, waitingForLoadingData, errorOccurred]() { | 
 |         --(*waitingForLoadingData); | 
 |         if (*waitingForLoadingData == 0 && !*errorOccurred) | 
 |         { | 
 |             boot_time_utils::GetHostBreakdownStages( | 
 |                 asyncResp, hostCheckpoints, bmcCheckpoints, hostDurations); | 
 |             boot_time_utils::PopulateDurationInResponse(asyncResp, | 
 |                                                         hostDurations); | 
 |             boot_time_utils::GetHostRebootFlow(asyncResp, hostCheckpoints, | 
 |                                                bmcCheckpoints); | 
 |             boot_time_utils::PopulateTotalTimeInResponse( | 
 |                 asyncResp, hostCheckpoints, hostDurations); | 
 |             boot_time_utils::PopulateStatPowerSourceInResponse(asyncResp, | 
 |                                                                hostCheckpoints); | 
 |             boot_time_utils::PopulateStatIsRebootingInResponse(asyncResp, | 
 |                                                                hostIsRebooting); | 
 |         } | 
 |     }; | 
 |     std::function<void()> dbusErrCallback = [errorOccurred, | 
 |                                              waitingForLoadingData]() { | 
 |         --(*waitingForLoadingData); | 
 |         *errorOccurred = true; | 
 |     }; | 
 |  | 
 |     boot_time_utils::GetBootTimeCheckpoints(asyncResp, "host0", hostCheckpoints, | 
 |                                             dbusSuccessCallback, | 
 |                                             dbusErrCallback); | 
 |     boot_time_utils::GetBootTimeDurations(asyncResp, "host0", hostDurations, | 
 |                                           dbusSuccessCallback, dbusErrCallback); | 
 |     boot_time_utils::GetBootTimeCheckpoints( | 
 |         asyncResp, "bmc", bmcCheckpoints, dbusSuccessCallback, dbusErrCallback); | 
 |     boot_time_utils::GetIsRebooting(asyncResp, "host0", hostIsRebooting, | 
 |                                     dbusSuccessCallback, dbusErrCallback); | 
 | } | 
 |  | 
 | inline void requestRoutesHostBootTime(App& app) | 
 | { | 
 |     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Oem/Google/BootTime/") | 
 |         .privileges(redfish::privileges::getComputerSystemCollection) | 
 |         .methods(boost::beast::http::verb::get)( | 
 |             std::bind_front(handleHostBootTimeDataGet, std::ref(app))); | 
 | } | 
 | } // namespace redfish |