Migration of OpenBMC Manager OEM schema

With the support of OEM route infrastructure each OEM implementation
can be separated into an OEM route handler. The MR migrates OEM resource
of manager resource into new files and route handlers

Tested
- All unit tests are passing
- GET request on /redfish/v1/Managers/<bmcid> has OpenBMC OEM properties

Change-Id: I935524dcdad6a6cc38a5532b6e7e7ffa1cb0369f
Signed-off-by: rohitpai <rohitpai77@gmail.com>
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index cbe3081..e5a89f0 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -15,6 +15,7 @@
 #include "generated/enums/resource.hpp"
 #include "http_request.hpp"
 #include "logging.hpp"
+#include "openbmc/openbmc_managers.hpp"
 #include "persistent_data.hpp"
 #include "query.hpp"
 #include "redfish_util.hpp"
@@ -27,11 +28,8 @@
 
 #include <systemd/sd-bus.h>
 
-#include <boost/asio/post.hpp>
 #include <boost/beast/http/status.hpp>
 #include <boost/beast/http/verb.hpp>
-#include <boost/container/flat_map.hpp>
-#include <boost/container/flat_set.hpp>
 #include <boost/system/error_code.hpp>
 #include <boost/url/format.hpp>
 #include <boost/url/url.hpp>
@@ -41,7 +39,6 @@
 #include <sdbusplus/message/native_types.hpp>
 #include <sdbusplus/unpack_properties.hpp>
 
-#include <algorithm>
 #include <array>
 #include <cstddef>
 #include <cstdint>
@@ -54,7 +51,6 @@
 #include <string>
 #include <string_view>
 #include <utility>
-#include <variant>
 #include <vector>
 
 namespace redfish
@@ -340,1439 +336,6 @@
             });
 }
 
-static constexpr const char* objectManagerIface =
-    "org.freedesktop.DBus.ObjectManager";
-static constexpr const char* pidConfigurationIface =
-    "xyz.openbmc_project.Configuration.Pid";
-static constexpr const char* pidZoneConfigurationIface =
-    "xyz.openbmc_project.Configuration.Pid.Zone";
-static constexpr const char* stepwiseConfigurationIface =
-    "xyz.openbmc_project.Configuration.Stepwise";
-static constexpr const char* thermalModeIface =
-    "xyz.openbmc_project.Control.ThermalMode";
-
-inline void asyncPopulatePid(
-    const std::string& connection, const std::string& path,
-    const std::string& currentProfile,
-    const std::vector<std::string>& supportedProfiles,
-    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
-{
-    sdbusplus::message::object_path objPath(path);
-    dbus::utility::getManagedObjects(
-        connection, objPath,
-        [asyncResp, currentProfile, supportedProfiles](
-            const boost::system::error_code& ec,
-            const dbus::utility::ManagedObjectType& managedObj) {
-            if (ec)
-            {
-                BMCWEB_LOG_ERROR("{}", ec);
-                messages::internalError(asyncResp->res);
-                return;
-            }
-            nlohmann::json& configRoot =
-                asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"];
-            nlohmann::json& fans = configRoot["FanControllers"];
-            fans["@odata.type"] =
-                "#OpenBMCManager.v1_0_0.Manager.FanControllers";
-            fans["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers",
-                BMCWEB_REDFISH_MANAGER_URI_NAME);
-
-            nlohmann::json& pids = configRoot["PidControllers"];
-            pids["@odata.type"] =
-                "#OpenBMCManager.v1_0_0.Manager.PidControllers";
-            pids["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers",
-                BMCWEB_REDFISH_MANAGER_URI_NAME);
-
-            nlohmann::json& stepwise = configRoot["StepwiseControllers"];
-            stepwise["@odata.type"] =
-                "#OpenBMCManager.v1_0_0.Manager.StepwiseControllers";
-            stepwise["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers",
-                BMCWEB_REDFISH_MANAGER_URI_NAME);
-
-            nlohmann::json& zones = configRoot["FanZones"];
-            zones["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones",
-                BMCWEB_REDFISH_MANAGER_URI_NAME);
-            zones["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.FanZones";
-            configRoot["@odata.id"] =
-                boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan",
-                                    BMCWEB_REDFISH_MANAGER_URI_NAME);
-            configRoot["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager.Fan";
-            configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
-
-            if (!currentProfile.empty())
-            {
-                configRoot["Profile"] = currentProfile;
-            }
-            BMCWEB_LOG_DEBUG("profile = {} !", currentProfile);
-
-            for (const auto& pathPair : managedObj)
-            {
-                for (const auto& intfPair : pathPair.second)
-                {
-                    if (intfPair.first != pidConfigurationIface &&
-                        intfPair.first != pidZoneConfigurationIface &&
-                        intfPair.first != stepwiseConfigurationIface)
-                    {
-                        continue;
-                    }
-
-                    std::string name;
-
-                    for (const std::pair<std::string,
-                                         dbus::utility::DbusVariantType>&
-                             propPair : intfPair.second)
-                    {
-                        if (propPair.first == "Name")
-                        {
-                            const std::string* namePtr =
-                                std::get_if<std::string>(&propPair.second);
-                            if (namePtr == nullptr)
-                            {
-                                BMCWEB_LOG_ERROR("Pid Name Field illegal");
-                                messages::internalError(asyncResp->res);
-                                return;
-                            }
-                            name = *namePtr;
-                            dbus::utility::escapePathForDbus(name);
-                        }
-                        else if (propPair.first == "Profiles")
-                        {
-                            const std::vector<std::string>* profiles =
-                                std::get_if<std::vector<std::string>>(
-                                    &propPair.second);
-                            if (profiles == nullptr)
-                            {
-                                BMCWEB_LOG_ERROR("Pid Profiles Field illegal");
-                                messages::internalError(asyncResp->res);
-                                return;
-                            }
-                            if (std::find(profiles->begin(), profiles->end(),
-                                          currentProfile) == profiles->end())
-                            {
-                                BMCWEB_LOG_INFO(
-                                    "{} not supported in current profile",
-                                    name);
-                                continue;
-                            }
-                        }
-                    }
-                    nlohmann::json* config = nullptr;
-                    const std::string* classPtr = nullptr;
-
-                    for (const std::pair<std::string,
-                                         dbus::utility::DbusVariantType>&
-                             propPair : intfPair.second)
-                    {
-                        if (propPair.first == "Class")
-                        {
-                            classPtr =
-                                std::get_if<std::string>(&propPair.second);
-                        }
-                    }
-
-                    boost::urls::url url(
-                        boost::urls::format("/redfish/v1/Managers/{}",
-                                            BMCWEB_REDFISH_MANAGER_URI_NAME));
-                    if (intfPair.first == pidZoneConfigurationIface)
-                    {
-                        std::string chassis;
-                        if (!dbus::utility::getNthStringFromPath(
-                                pathPair.first.str, 5, chassis))
-                        {
-                            chassis = "#IllegalValue";
-                        }
-                        nlohmann::json& zone = zones[name];
-                        zone["Chassis"]["@odata.id"] = boost::urls::format(
-                            "/redfish/v1/Chassis/{}", chassis);
-                        url.set_fragment(
-                            ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name)
-                                .to_string());
-                        zone["@odata.id"] = std::move(url);
-                        zone["@odata.type"] =
-                            "#OpenBMCManager.v1_0_0.Manager.FanZone";
-                        config = &zone;
-                    }
-
-                    else if (intfPair.first == stepwiseConfigurationIface)
-                    {
-                        if (classPtr == nullptr)
-                        {
-                            BMCWEB_LOG_ERROR("Pid Class Field illegal");
-                            messages::internalError(asyncResp->res);
-                            return;
-                        }
-
-                        nlohmann::json& controller = stepwise[name];
-                        config = &controller;
-                        url.set_fragment(
-                            ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer /
-                             name)
-                                .to_string());
-                        controller["@odata.id"] = std::move(url);
-                        controller["@odata.type"] =
-                            "#OpenBMCManager.v1_0_0.Manager.StepwiseController";
-
-                        controller["Direction"] = *classPtr;
-                    }
-
-                    // pid and fans are off the same configuration
-                    else if (intfPair.first == pidConfigurationIface)
-                    {
-                        if (classPtr == nullptr)
-                        {
-                            BMCWEB_LOG_ERROR("Pid Class Field illegal");
-                            messages::internalError(asyncResp->res);
-                            return;
-                        }
-                        bool isFan = *classPtr == "fan";
-                        nlohmann::json& element =
-                            isFan ? fans[name] : pids[name];
-                        config = &element;
-                        if (isFan)
-                        {
-                            url.set_fragment(
-                                ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer /
-                                 name)
-                                    .to_string());
-                            element["@odata.id"] = std::move(url);
-                            element["@odata.type"] =
-                                "#OpenBMCManager.v1_0_0.Manager.FanController";
-                        }
-                        else
-                        {
-                            url.set_fragment(
-                                ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer /
-                                 name)
-                                    .to_string());
-                            element["@odata.id"] = std::move(url);
-                            element["@odata.type"] =
-                                "#OpenBMCManager.v1_0_0.Manager.PidController";
-                        }
-                    }
-                    else
-                    {
-                        BMCWEB_LOG_ERROR("Unexpected configuration");
-                        messages::internalError(asyncResp->res);
-                        return;
-                    }
-
-                    // used for making maps out of 2 vectors
-                    const std::vector<double>* keys = nullptr;
-                    const std::vector<double>* values = nullptr;
-
-                    for (const auto& propertyPair : intfPair.second)
-                    {
-                        if (propertyPair.first == "Type" ||
-                            propertyPair.first == "Class" ||
-                            propertyPair.first == "Name")
-                        {
-                            continue;
-                        }
-
-                        // zones
-                        if (intfPair.first == pidZoneConfigurationIface)
-                        {
-                            const double* ptr =
-                                std::get_if<double>(&propertyPair.second);
-                            if (ptr == nullptr)
-                            {
-                                BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                 propertyPair.first);
-                                messages::internalError(asyncResp->res);
-                                return;
-                            }
-                            (*config)[propertyPair.first] = *ptr;
-                        }
-
-                        if (intfPair.first == stepwiseConfigurationIface)
-                        {
-                            if (propertyPair.first == "Reading" ||
-                                propertyPair.first == "Output")
-                            {
-                                const std::vector<double>* ptr =
-                                    std::get_if<std::vector<double>>(
-                                        &propertyPair.second);
-
-                                if (ptr == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                     propertyPair.first);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-
-                                if (propertyPair.first == "Reading")
-                                {
-                                    keys = ptr;
-                                }
-                                else
-                                {
-                                    values = ptr;
-                                }
-                                if (keys != nullptr && values != nullptr)
-                                {
-                                    if (keys->size() != values->size())
-                                    {
-                                        BMCWEB_LOG_ERROR(
-                                            "Reading and Output size don't match ");
-                                        messages::internalError(asyncResp->res);
-                                        return;
-                                    }
-                                    nlohmann::json& steps = (*config)["Steps"];
-                                    steps = nlohmann::json::array();
-                                    for (size_t ii = 0; ii < keys->size(); ii++)
-                                    {
-                                        nlohmann::json::object_t step;
-                                        step["Target"] = (*keys)[ii];
-                                        step["Output"] = (*values)[ii];
-                                        steps.emplace_back(std::move(step));
-                                    }
-                                }
-                            }
-                            if (propertyPair.first == "NegativeHysteresis" ||
-                                propertyPair.first == "PositiveHysteresis")
-                            {
-                                const double* ptr =
-                                    std::get_if<double>(&propertyPair.second);
-                                if (ptr == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                     propertyPair.first);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                                (*config)[propertyPair.first] = *ptr;
-                            }
-                        }
-
-                        // pid and fans are off the same configuration
-                        if (intfPair.first == pidConfigurationIface ||
-                            intfPair.first == stepwiseConfigurationIface)
-                        {
-                            if (propertyPair.first == "Zones")
-                            {
-                                const std::vector<std::string>* inputs =
-                                    std::get_if<std::vector<std::string>>(
-                                        &propertyPair.second);
-
-                                if (inputs == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Zones Pid Field Illegal");
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                                auto& data = (*config)[propertyPair.first];
-                                data = nlohmann::json::array();
-                                for (std::string itemCopy : *inputs)
-                                {
-                                    dbus::utility::escapePathForDbus(itemCopy);
-                                    nlohmann::json::object_t input;
-                                    boost::urls::url managerUrl =
-                                        boost::urls::format(
-                                            "/redfish/v1/Managers/{}#{}",
-                                            BMCWEB_REDFISH_MANAGER_URI_NAME,
-                                            ("/Oem/OpenBmc/Fan/FanZones"_json_pointer /
-                                             itemCopy)
-                                                .to_string());
-                                    input["@odata.id"] = std::move(managerUrl);
-                                    data.emplace_back(std::move(input));
-                                }
-                            }
-                            // todo(james): may never happen, but this
-                            // assumes configuration data referenced in the
-                            // PID config is provided by the same daemon, we
-                            // could add another loop to cover all cases,
-                            // but I'm okay kicking this can down the road a
-                            // bit
-
-                            else if (propertyPair.first == "Inputs" ||
-                                     propertyPair.first == "Outputs")
-                            {
-                                auto& data = (*config)[propertyPair.first];
-                                const std::vector<std::string>* inputs =
-                                    std::get_if<std::vector<std::string>>(
-                                        &propertyPair.second);
-
-                                if (inputs == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                     propertyPair.first);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                                data = *inputs;
-                            }
-                            else if (propertyPair.first == "SetPointOffset")
-                            {
-                                const std::string* ptr =
-                                    std::get_if<std::string>(
-                                        &propertyPair.second);
-
-                                if (ptr == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                     propertyPair.first);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                                // translate from dbus to redfish
-                                if (*ptr == "WarningHigh")
-                                {
-                                    (*config)["SetPointOffset"] =
-                                        "UpperThresholdNonCritical";
-                                }
-                                else if (*ptr == "WarningLow")
-                                {
-                                    (*config)["SetPointOffset"] =
-                                        "LowerThresholdNonCritical";
-                                }
-                                else if (*ptr == "CriticalHigh")
-                                {
-                                    (*config)["SetPointOffset"] =
-                                        "UpperThresholdCritical";
-                                }
-                                else if (*ptr == "CriticalLow")
-                                {
-                                    (*config)["SetPointOffset"] =
-                                        "LowerThresholdCritical";
-                                }
-                                else
-                                {
-                                    BMCWEB_LOG_ERROR("Value Illegal {}", *ptr);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                            }
-                            // doubles
-                            else if (propertyPair.first ==
-                                         "FFGainCoefficient" ||
-                                     propertyPair.first == "FFOffCoefficient" ||
-                                     propertyPair.first == "ICoefficient" ||
-                                     propertyPair.first == "ILimitMax" ||
-                                     propertyPair.first == "ILimitMin" ||
-                                     propertyPair.first ==
-                                         "PositiveHysteresis" ||
-                                     propertyPair.first ==
-                                         "NegativeHysteresis" ||
-                                     propertyPair.first == "OutLimitMax" ||
-                                     propertyPair.first == "OutLimitMin" ||
-                                     propertyPair.first == "PCoefficient" ||
-                                     propertyPair.first == "SetPoint" ||
-                                     propertyPair.first == "SlewNeg" ||
-                                     propertyPair.first == "SlewPos")
-                            {
-                                const double* ptr =
-                                    std::get_if<double>(&propertyPair.second);
-                                if (ptr == nullptr)
-                                {
-                                    BMCWEB_LOG_ERROR("Field Illegal {}",
-                                                     propertyPair.first);
-                                    messages::internalError(asyncResp->res);
-                                    return;
-                                }
-                                (*config)[propertyPair.first] = *ptr;
-                            }
-                        }
-                    }
-                }
-            }
-        });
-}
-
-enum class CreatePIDRet
-{
-    fail,
-    del,
-    patch
-};
-
-inline bool getZonesFromJsonReq(
-    const std::shared_ptr<bmcweb::AsyncResp>& response,
-    std::vector<nlohmann::json::object_t>& config,
-    std::vector<std::string>& zones)
-{
-    if (config.empty())
-    {
-        BMCWEB_LOG_ERROR("Empty Zones");
-        messages::propertyValueFormatError(response->res, config, "Zones");
-        return false;
-    }
-    for (auto& odata : config)
-    {
-        std::string path;
-        if (!redfish::json_util::readJsonObject(odata, response->res,
-                                                "@odata.id", path))
-        {
-            return false;
-        }
-        std::string input;
-
-        // 8 below comes from
-        // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left
-        //     0    1     2      3    4    5      6     7      8
-        if (!dbus::utility::getNthStringFromPath(path, 8, input))
-        {
-            BMCWEB_LOG_ERROR("Got invalid path {}", path);
-            BMCWEB_LOG_ERROR("Illegal Type Zones");
-            messages::propertyValueFormatError(response->res, odata, "Zones");
-            return false;
-        }
-        std::replace(input.begin(), input.end(), '_', ' ');
-        zones.emplace_back(std::move(input));
-    }
-    return true;
-}
-
-inline const dbus::utility::ManagedObjectType::value_type* findChassis(
-    const dbus::utility::ManagedObjectType& managedObj, std::string_view value,
-    std::string& chassis)
-{
-    BMCWEB_LOG_DEBUG("Find Chassis: {}", value);
-
-    std::string escaped(value);
-    std::replace(escaped.begin(), escaped.end(), ' ', '_');
-    escaped = "/" + escaped;
-    auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) {
-        if (obj.first.str.ends_with(escaped))
-        {
-            BMCWEB_LOG_DEBUG("Matched {}", obj.first.str);
-            return true;
-        }
-        return false;
-    });
-
-    if (it == managedObj.end())
-    {
-        return nullptr;
-    }
-    // 5 comes from <chassis-name> being the 5th element
-    // /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
-    if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
-    {
-        return &(*it);
-    }
-
-    return nullptr;
-}
-
-inline CreatePIDRet createPidInterface(
-    const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type,
-    std::string_view name, nlohmann::json& jsonValue, const std::string& path,
-    const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
-    dbus::utility::DBusPropertiesMap& output, std::string& chassis,
-    const std::string& profile)
-{
-    // common deleter
-    if (jsonValue == nullptr)
-    {
-        std::string iface;
-        if (type == "PidControllers" || type == "FanControllers")
-        {
-            iface = pidConfigurationIface;
-        }
-        else if (type == "FanZones")
-        {
-            iface = pidZoneConfigurationIface;
-        }
-        else if (type == "StepwiseControllers")
-        {
-            iface = stepwiseConfigurationIface;
-        }
-        else
-        {
-            BMCWEB_LOG_ERROR("Illegal Type {}", type);
-            messages::propertyUnknown(response->res, type);
-            return CreatePIDRet::fail;
-        }
-
-        BMCWEB_LOG_DEBUG("del {} {}", path, iface);
-        // delete interface
-        crow::connections::systemBus->async_method_call(
-            [response, path](const boost::system::error_code& ec) {
-                if (ec)
-                {
-                    BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec);
-                    messages::internalError(response->res);
-                    return;
-                }
-                messages::success(response->res);
-            },
-            "xyz.openbmc_project.EntityManager", path, iface, "Delete");
-        return CreatePIDRet::del;
-    }
-
-    const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr;
-    if (!createNewObject)
-    {
-        // if we aren't creating a new object, we should be able to find it on
-        // d-bus
-        managedItem = findChassis(managedObj, name, chassis);
-        if (managedItem == nullptr)
-        {
-            BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
-            messages::invalidObject(
-                response->res,
-                boost::urls::format("/redfish/v1/Chassis/{}", chassis));
-            return CreatePIDRet::fail;
-        }
-    }
-
-    if (!profile.empty() &&
-        (type == "PidControllers" || type == "FanControllers" ||
-         type == "StepwiseControllers"))
-    {
-        if (managedItem == nullptr)
-        {
-            output.emplace_back("Profiles", std::vector<std::string>{profile});
-        }
-        else
-        {
-            std::string interface;
-            if (type == "StepwiseControllers")
-            {
-                interface = stepwiseConfigurationIface;
-            }
-            else
-            {
-                interface = pidConfigurationIface;
-            }
-            bool ifaceFound = false;
-            for (const auto& iface : managedItem->second)
-            {
-                if (iface.first == interface)
-                {
-                    ifaceFound = true;
-                    for (const auto& prop : iface.second)
-                    {
-                        if (prop.first == "Profiles")
-                        {
-                            const std::vector<std::string>* curProfiles =
-                                std::get_if<std::vector<std::string>>(
-                                    &(prop.second));
-                            if (curProfiles == nullptr)
-                            {
-                                BMCWEB_LOG_ERROR(
-                                    "Illegal profiles in managed object");
-                                messages::internalError(response->res);
-                                return CreatePIDRet::fail;
-                            }
-                            if (std::find(curProfiles->begin(),
-                                          curProfiles->end(), profile) ==
-                                curProfiles->end())
-                            {
-                                std::vector<std::string> newProfiles =
-                                    *curProfiles;
-                                newProfiles.push_back(profile);
-                                output.emplace_back("Profiles", newProfiles);
-                            }
-                        }
-                    }
-                }
-            }
-
-            if (!ifaceFound)
-            {
-                BMCWEB_LOG_ERROR("Failed to find interface in managed object");
-                messages::internalError(response->res);
-                return CreatePIDRet::fail;
-            }
-        }
-    }
-
-    if (type == "PidControllers" || type == "FanControllers")
-    {
-        if (createNewObject)
-        {
-            output.emplace_back("Class",
-                                type == "PidControllers" ? "temp" : "fan");
-            output.emplace_back("Type", "Pid");
-        }
-
-        std::optional<std::vector<nlohmann::json::object_t>> zones;
-        std::optional<std::vector<std::string>> inputs;
-        std::optional<std::vector<std::string>> outputs;
-        std::map<std::string, std::optional<double>> doubles;
-        std::optional<std::string> setpointOffset;
-        if (!redfish::json_util::readJson(                           //
-                jsonValue, response->res,                            //
-                "FFGainCoefficient", doubles["FFGainCoefficient"],   //
-                "FFOffCoefficient", doubles["FFOffCoefficient"],     //
-                "ICoefficient", doubles["ICoefficient"],             //
-                "ILimitMax", doubles["ILimitMax"],                   //
-                "ILimitMin", doubles["ILimitMin"],                   //
-                "Inputs", inputs,                                    //
-                "NegativeHysteresis", doubles["NegativeHysteresis"], //
-                "OutLimitMax", doubles["OutLimitMax"],               //
-                "OutLimitMin", doubles["OutLimitMin"],               //
-                "Outputs", outputs,                                  //
-                "PCoefficient", doubles["PCoefficient"],             //
-                "PositiveHysteresis", doubles["PositiveHysteresis"], //
-                "SetPoint", doubles["SetPoint"],                     //
-                "SetPointOffset", setpointOffset,                    //
-                "SlewNeg", doubles["SlewNeg"],                       //
-                "SlewPos", doubles["SlewPos"],                       //
-                "Zones", zones                                       //
-                ))
-        {
-            return CreatePIDRet::fail;
-        }
-
-        if (zones)
-        {
-            std::vector<std::string> zonesStr;
-            if (!getZonesFromJsonReq(response, *zones, zonesStr))
-            {
-                BMCWEB_LOG_ERROR("Illegal Zones");
-                return CreatePIDRet::fail;
-            }
-            if (chassis.empty() &&
-                findChassis(managedObj, zonesStr[0], chassis) == nullptr)
-            {
-                BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
-                messages::invalidObject(
-                    response->res,
-                    boost::urls::format("/redfish/v1/Chassis/{}", chassis));
-                return CreatePIDRet::fail;
-            }
-            output.emplace_back("Zones", std::move(zonesStr));
-        }
-
-        if (inputs)
-        {
-            for (std::string& value : *inputs)
-            {
-                std::replace(value.begin(), value.end(), '_', ' ');
-            }
-            output.emplace_back("Inputs", *inputs);
-        }
-
-        if (outputs)
-        {
-            for (std::string& value : *outputs)
-            {
-                std::replace(value.begin(), value.end(), '_', ' ');
-            }
-            output.emplace_back("Outputs", *outputs);
-        }
-
-        if (setpointOffset)
-        {
-            // translate between redfish and dbus names
-            if (*setpointOffset == "UpperThresholdNonCritical")
-            {
-                output.emplace_back("SetPointOffset", "WarningLow");
-            }
-            else if (*setpointOffset == "LowerThresholdNonCritical")
-            {
-                output.emplace_back("SetPointOffset", "WarningHigh");
-            }
-            else if (*setpointOffset == "LowerThresholdCritical")
-            {
-                output.emplace_back("SetPointOffset", "CriticalLow");
-            }
-            else if (*setpointOffset == "UpperThresholdCritical")
-            {
-                output.emplace_back("SetPointOffset", "CriticalHigh");
-            }
-            else
-            {
-                BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset);
-                messages::propertyValueNotInList(response->res, name,
-                                                 "SetPointOffset");
-                return CreatePIDRet::fail;
-            }
-        }
-
-        // doubles
-        for (const auto& pairs : doubles)
-        {
-            if (!pairs.second)
-            {
-                continue;
-            }
-            BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second);
-            output.emplace_back(pairs.first, *pairs.second);
-        }
-    }
-
-    else if (type == "FanZones")
-    {
-        output.emplace_back("Type", "Pid.Zone");
-
-        std::optional<std::string> chassisId;
-        std::optional<double> failSafePercent;
-        std::optional<double> minThermalOutput;
-        if (!redfish::json_util::readJson(          //
-                jsonValue, response->res,           //
-                "Chassis/@odata.id", chassisId,     //
-                "FailSafePercent", failSafePercent, //
-                "MinThermalOutput", minThermalOutput))
-        {
-            return CreatePIDRet::fail;
-        }
-
-        if (chassisId)
-        {
-            // /redfish/v1/chassis/chassis_name/
-            if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis))
-            {
-                BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId);
-                messages::invalidObject(
-                    response->res,
-                    boost::urls::format("/redfish/v1/Chassis/{}", *chassisId));
-                return CreatePIDRet::fail;
-            }
-        }
-        if (minThermalOutput)
-        {
-            output.emplace_back("MinThermalOutput", *minThermalOutput);
-        }
-        if (failSafePercent)
-        {
-            output.emplace_back("FailSafePercent", *failSafePercent);
-        }
-    }
-    else if (type == "StepwiseControllers")
-    {
-        output.emplace_back("Type", "Stepwise");
-
-        std::optional<std::vector<nlohmann::json::object_t>> zones;
-        std::optional<std::vector<nlohmann::json::object_t>> steps;
-        std::optional<std::vector<std::string>> inputs;
-        std::optional<double> positiveHysteresis;
-        std::optional<double> negativeHysteresis;
-        std::optional<std::string> direction; // upper clipping curve vs lower
-        if (!redfish::json_util::readJson(    //
-                jsonValue, response->res,     //
-                "Direction", direction,       //
-                "Inputs", inputs,             //
-                "NegativeHysteresis", negativeHysteresis, //
-                "PositiveHysteresis", positiveHysteresis, //
-                "Steps", steps,                           //
-                "Zones", zones                            //
-                ))
-        {
-            return CreatePIDRet::fail;
-        }
-
-        if (zones)
-        {
-            std::vector<std::string> zonesStrs;
-            if (!getZonesFromJsonReq(response, *zones, zonesStrs))
-            {
-                BMCWEB_LOG_ERROR("Illegal Zones");
-                return CreatePIDRet::fail;
-            }
-            if (chassis.empty() &&
-                findChassis(managedObj, zonesStrs[0], chassis) == nullptr)
-            {
-                BMCWEB_LOG_ERROR("Failed to get chassis from config patch");
-                messages::invalidObject(
-                    response->res,
-                    boost::urls::format("/redfish/v1/Chassis/{}", chassis));
-                return CreatePIDRet::fail;
-            }
-            output.emplace_back("Zones", std::move(zonesStrs));
-        }
-        if (steps)
-        {
-            std::vector<double> readings;
-            std::vector<double> outputs;
-            for (auto& step : *steps)
-            {
-                double target = 0.0;
-                double out = 0.0;
-
-                if (!redfish::json_util::readJsonObject( //
-                        step, response->res,             //
-                        "Output", out,                   //
-                        "Target", target                 //
-                        ))
-                {
-                    return CreatePIDRet::fail;
-                }
-                readings.emplace_back(target);
-                outputs.emplace_back(out);
-            }
-            output.emplace_back("Reading", std::move(readings));
-            output.emplace_back("Output", std::move(outputs));
-        }
-        if (inputs)
-        {
-            for (std::string& value : *inputs)
-            {
-                std::replace(value.begin(), value.end(), '_', ' ');
-            }
-            output.emplace_back("Inputs", std::move(*inputs));
-        }
-        if (negativeHysteresis)
-        {
-            output.emplace_back("NegativeHysteresis", *negativeHysteresis);
-        }
-        if (positiveHysteresis)
-        {
-            output.emplace_back("PositiveHysteresis", *positiveHysteresis);
-        }
-        if (direction)
-        {
-            constexpr const std::array<const char*, 2> allowedDirections = {
-                "Ceiling", "Floor"};
-            if (std::ranges::find(allowedDirections, *direction) ==
-                allowedDirections.end())
-            {
-                messages::propertyValueTypeError(response->res, "Direction",
-                                                 *direction);
-                return CreatePIDRet::fail;
-            }
-            output.emplace_back("Class", *direction);
-        }
-    }
-    else
-    {
-        BMCWEB_LOG_ERROR("Illegal Type {}", type);
-        messages::propertyUnknown(response->res, type);
-        return CreatePIDRet::fail;
-    }
-    return CreatePIDRet::patch;
-}
-struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
-{
-    struct CompletionValues
-    {
-        std::vector<std::string> supportedProfiles;
-        std::string currentProfile;
-        dbus::utility::MapperGetSubTreeResponse subtree;
-    };
-
-    explicit GetPIDValues(
-        const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
-        asyncResp(asyncRespIn)
-
-    {}
-
-    void run()
-    {
-        std::shared_ptr<GetPIDValues> self = shared_from_this();
-
-        // get all configurations
-        constexpr std::array<std::string_view, 4> interfaces = {
-            pidConfigurationIface, pidZoneConfigurationIface,
-            objectManagerIface, stepwiseConfigurationIface};
-        dbus::utility::getSubTree(
-            "/", 0, interfaces,
-            [self](
-                const boost::system::error_code& ec,
-                const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
-                if (ec)
-                {
-                    BMCWEB_LOG_ERROR("{}", ec);
-                    messages::internalError(self->asyncResp->res);
-                    return;
-                }
-                self->complete.subtree = subtreeLocal;
-            });
-
-        // at the same time get the selected profile
-        constexpr std::array<std::string_view, 1> thermalModeIfaces = {
-            thermalModeIface};
-        dbus::utility::getSubTree(
-            "/", 0, thermalModeIfaces,
-            [self](
-                const boost::system::error_code& ec,
-                const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) {
-                if (ec || subtreeLocal.empty())
-                {
-                    return;
-                }
-                if (subtreeLocal[0].second.size() != 1)
-                {
-                    // invalid mapper response, should never happen
-                    BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error");
-                    messages::internalError(self->asyncResp->res);
-                    return;
-                }
-
-                const std::string& path = subtreeLocal[0].first;
-                const std::string& owner = subtreeLocal[0].second[0].first;
-
-                dbus::utility::getAllProperties(
-                    *crow::connections::systemBus, owner, path,
-                    thermalModeIface,
-                    [path, owner,
-                     self](const boost::system::error_code& ec2,
-                           const dbus::utility::DBusPropertiesMap& resp) {
-                        if (ec2)
-                        {
-                            BMCWEB_LOG_ERROR(
-                                "GetPIDValues: Can't get thermalModeIface {}",
-                                path);
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-
-                        const std::string* current = nullptr;
-                        const std::vector<std::string>* supported = nullptr;
-
-                        const bool success = sdbusplus::unpackPropertiesNoThrow(
-                            dbus_utils::UnpackErrorPrinter(), resp, "Current",
-                            current, "Supported", supported);
-
-                        if (!success)
-                        {
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-
-                        if (current == nullptr || supported == nullptr)
-                        {
-                            BMCWEB_LOG_ERROR(
-                                "GetPIDValues: thermal mode iface invalid {}",
-                                path);
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-                        self->complete.currentProfile = *current;
-                        self->complete.supportedProfiles = *supported;
-                    });
-            });
-    }
-
-    static void processingComplete(
-        const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
-        const CompletionValues& completion)
-    {
-        if (asyncResp->res.result() != boost::beast::http::status::ok)
-        {
-            return;
-        }
-        // create map of <connection, path to objMgr>>
-        boost::container::flat_map<
-            std::string, std::string, std::less<>,
-            std::vector<std::pair<std::string, std::string>>>
-            objectMgrPaths;
-        boost::container::flat_set<std::string, std::less<>,
-                                   std::vector<std::string>>
-            calledConnections;
-        for (const auto& pathGroup : completion.subtree)
-        {
-            for (const auto& connectionGroup : pathGroup.second)
-            {
-                auto findConnection =
-                    calledConnections.find(connectionGroup.first);
-                if (findConnection != calledConnections.end())
-                {
-                    break;
-                }
-                for (const std::string& interface : connectionGroup.second)
-                {
-                    if (interface == objectManagerIface)
-                    {
-                        objectMgrPaths[connectionGroup.first] = pathGroup.first;
-                    }
-                    // this list is alphabetical, so we
-                    // should have found the objMgr by now
-                    if (interface == pidConfigurationIface ||
-                        interface == pidZoneConfigurationIface ||
-                        interface == stepwiseConfigurationIface)
-                    {
-                        auto findObjMgr =
-                            objectMgrPaths.find(connectionGroup.first);
-                        if (findObjMgr == objectMgrPaths.end())
-                        {
-                            BMCWEB_LOG_DEBUG("{}Has no Object Manager",
-                                             connectionGroup.first);
-                            continue;
-                        }
-
-                        calledConnections.insert(connectionGroup.first);
-
-                        asyncPopulatePid(findObjMgr->first, findObjMgr->second,
-                                         completion.currentProfile,
-                                         completion.supportedProfiles,
-                                         asyncResp);
-                        break;
-                    }
-                }
-            }
-        }
-    }
-
-    ~GetPIDValues()
-    {
-        boost::asio::post(crow::connections::systemBus->get_io_context(),
-                          std::bind_front(&processingComplete, asyncResp,
-                                          std::move(complete)));
-    }
-
-    GetPIDValues(const GetPIDValues&) = delete;
-    GetPIDValues(GetPIDValues&&) = delete;
-    GetPIDValues& operator=(const GetPIDValues&) = delete;
-    GetPIDValues& operator=(GetPIDValues&&) = delete;
-
-    std::shared_ptr<bmcweb::AsyncResp> asyncResp;
-    CompletionValues complete;
-};
-
-struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
-{
-    SetPIDValues(
-        const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
-        std::vector<
-            std::pair<std::string, std::optional<nlohmann::json::object_t>>>&&
-            configurationsIn,
-        std::optional<std::string>& profileIn) :
-        asyncResp(asyncRespIn), configuration(std::move(configurationsIn)),
-        profile(std::move(profileIn))
-    {}
-
-    SetPIDValues(const SetPIDValues&) = delete;
-    SetPIDValues(SetPIDValues&&) = delete;
-    SetPIDValues& operator=(const SetPIDValues&) = delete;
-    SetPIDValues& operator=(SetPIDValues&&) = delete;
-
-    void run()
-    {
-        if (asyncResp->res.result() != boost::beast::http::status::ok)
-        {
-            return;
-        }
-
-        std::shared_ptr<SetPIDValues> self = shared_from_this();
-
-        // todo(james): might make sense to do a mapper call here if this
-        // interface gets more traction
-        sdbusplus::message::object_path objPath(
-            "/xyz/openbmc_project/inventory");
-        dbus::utility::getManagedObjects(
-            "xyz.openbmc_project.EntityManager", objPath,
-            [self](const boost::system::error_code& ec,
-                   const dbus::utility::ManagedObjectType& mObj) {
-                if (ec)
-                {
-                    BMCWEB_LOG_ERROR("Error communicating to Entity Manager");
-                    messages::internalError(self->asyncResp->res);
-                    return;
-                }
-                const std::array<const char*, 3> configurations = {
-                    pidConfigurationIface, pidZoneConfigurationIface,
-                    stepwiseConfigurationIface};
-
-                for (const auto& [path, object] : mObj)
-                {
-                    for (const auto& [interface, _] : object)
-                    {
-                        if (std::ranges::find(configurations, interface) !=
-                            configurations.end())
-                        {
-                            self->objectCount++;
-                            break;
-                        }
-                    }
-                }
-                self->managedObj = mObj;
-            });
-
-        // at the same time get the profile information
-        constexpr std::array<std::string_view, 1> thermalModeIfaces = {
-            thermalModeIface};
-        dbus::utility::getSubTree(
-            "/", 0, thermalModeIfaces,
-            [self](const boost::system::error_code& ec,
-                   const dbus::utility::MapperGetSubTreeResponse& subtree) {
-                if (ec || subtree.empty())
-                {
-                    return;
-                }
-                if (subtree[0].second.empty())
-                {
-                    // invalid mapper response, should never happen
-                    BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error");
-                    messages::internalError(self->asyncResp->res);
-                    return;
-                }
-
-                const std::string& path = subtree[0].first;
-                const std::string& owner = subtree[0].second[0].first;
-                dbus::utility::getAllProperties(
-                    *crow::connections::systemBus, owner, path,
-                    thermalModeIface,
-                    [self, path,
-                     owner](const boost::system::error_code& ec2,
-                            const dbus::utility::DBusPropertiesMap& r) {
-                        if (ec2)
-                        {
-                            BMCWEB_LOG_ERROR(
-                                "SetPIDValues: Can't get thermalModeIface {}",
-                                path);
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-                        const std::string* current = nullptr;
-                        const std::vector<std::string>* supported = nullptr;
-
-                        const bool success = sdbusplus::unpackPropertiesNoThrow(
-                            dbus_utils::UnpackErrorPrinter(), r, "Current",
-                            current, "Supported", supported);
-
-                        if (!success)
-                        {
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-
-                        if (current == nullptr || supported == nullptr)
-                        {
-                            BMCWEB_LOG_ERROR(
-                                "SetPIDValues: thermal mode iface invalid {}",
-                                path);
-                            messages::internalError(self->asyncResp->res);
-                            return;
-                        }
-                        self->currentProfile = *current;
-                        self->supportedProfiles = *supported;
-                        self->profileConnection = owner;
-                        self->profilePath = path;
-                    });
-            });
-    }
-    void pidSetDone()
-    {
-        if (asyncResp->res.result() != boost::beast::http::status::ok)
-        {
-            return;
-        }
-        std::shared_ptr<bmcweb::AsyncResp> response = asyncResp;
-        if (profile)
-        {
-            if (std::ranges::find(supportedProfiles, *profile) ==
-                supportedProfiles.end())
-            {
-                messages::actionParameterUnknown(response->res, "Profile",
-                                                 *profile);
-                return;
-            }
-            currentProfile = *profile;
-            sdbusplus::asio::setProperty(
-                *crow::connections::systemBus, profileConnection, profilePath,
-                thermalModeIface, "Current", *profile,
-                [response](const boost::system::error_code& ec) {
-                    if (ec)
-                    {
-                        BMCWEB_LOG_ERROR("Error patching profile{}", ec);
-                        messages::internalError(response->res);
-                    }
-                });
-        }
-
-        for (auto& containerPair : configuration)
-        {
-            auto& container = containerPair.second;
-            if (!container)
-            {
-                continue;
-            }
-
-            const std::string& type = containerPair.first;
-
-            for (auto& [name, value] : *container)
-            {
-                std::string dbusObjName = name;
-                std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_');
-                BMCWEB_LOG_DEBUG("looking for {}", name);
-
-                auto pathItr = std::ranges::find_if(
-                    managedObj, [&dbusObjName](const auto& obj) {
-                        return obj.first.filename() == dbusObjName;
-                    });
-                dbus::utility::DBusPropertiesMap output;
-
-                output.reserve(16); // The pid interface length
-
-                // determines if we're patching entity-manager or
-                // creating a new object
-                bool createNewObject = (pathItr == managedObj.end());
-                BMCWEB_LOG_DEBUG("Found = {}", !createNewObject);
-
-                std::string iface;
-                if (!createNewObject)
-                {
-                    bool findInterface = false;
-                    for (const auto& interface : pathItr->second)
-                    {
-                        if (interface.first == pidConfigurationIface)
-                        {
-                            if (type == "PidControllers" ||
-                                type == "FanControllers")
-                            {
-                                iface = pidConfigurationIface;
-                                findInterface = true;
-                                break;
-                            }
-                        }
-                        else if (interface.first == pidZoneConfigurationIface)
-                        {
-                            if (type == "FanZones")
-                            {
-                                iface = pidZoneConfigurationIface;
-                                findInterface = true;
-                                break;
-                            }
-                        }
-                        else if (interface.first == stepwiseConfigurationIface)
-                        {
-                            if (type == "StepwiseControllers")
-                            {
-                                iface = stepwiseConfigurationIface;
-                                findInterface = true;
-                                break;
-                            }
-                        }
-                    }
-
-                    // create new object if interface not found
-                    if (!findInterface)
-                    {
-                        createNewObject = true;
-                    }
-                }
-
-                if (createNewObject && value == nullptr)
-                {
-                    // can't delete a non-existent object
-                    messages::propertyValueNotInList(response->res, value,
-                                                     name);
-                    continue;
-                }
-
-                std::string path;
-                if (pathItr != managedObj.end())
-                {
-                    path = pathItr->first.str;
-                }
-
-                BMCWEB_LOG_DEBUG("Create new = {}", createNewObject);
-
-                // arbitrary limit to avoid attacks
-                constexpr const size_t controllerLimit = 500;
-                if (createNewObject && objectCount >= controllerLimit)
-                {
-                    messages::resourceExhaustion(response->res, type);
-                    continue;
-                }
-                std::string escaped = name;
-                std::replace(escaped.begin(), escaped.end(), '_', ' ');
-                output.emplace_back("Name", escaped);
-
-                std::string chassis;
-                CreatePIDRet ret = createPidInterface(
-                    response, type, name, value, path, managedObj,
-                    createNewObject, output, chassis, currentProfile);
-                if (ret == CreatePIDRet::fail)
-                {
-                    return;
-                }
-                if (ret == CreatePIDRet::del)
-                {
-                    continue;
-                }
-
-                if (!createNewObject)
-                {
-                    for (const auto& property : output)
-                    {
-                        crow::connections::systemBus->async_method_call(
-                            [response,
-                             propertyName{std::string(property.first)}](
-                                const boost::system::error_code& ec) {
-                                if (ec)
-                                {
-                                    BMCWEB_LOG_ERROR("Error patching {}: {}",
-                                                     propertyName, ec);
-                                    messages::internalError(response->res);
-                                    return;
-                                }
-                                messages::success(response->res);
-                            },
-                            "xyz.openbmc_project.EntityManager", path,
-                            "org.freedesktop.DBus.Properties", "Set", iface,
-                            property.first, property.second);
-                    }
-                }
-                else
-                {
-                    if (chassis.empty())
-                    {
-                        BMCWEB_LOG_ERROR("Failed to get chassis from config");
-                        messages::internalError(response->res);
-                        return;
-                    }
-
-                    bool foundChassis = false;
-                    for (const auto& obj : managedObj)
-                    {
-                        if (obj.first.filename() == chassis)
-                        {
-                            chassis = obj.first.str;
-                            foundChassis = true;
-                            break;
-                        }
-                    }
-                    if (!foundChassis)
-                    {
-                        BMCWEB_LOG_ERROR("Failed to find chassis on dbus");
-                        messages::resourceMissingAtURI(
-                            response->res,
-                            boost::urls::format("/redfish/v1/Chassis/{}",
-                                                chassis));
-                        return;
-                    }
-
-                    crow::connections::systemBus->async_method_call(
-                        [response](const boost::system::error_code& ec) {
-                            if (ec)
-                            {
-                                BMCWEB_LOG_ERROR("Error Adding Pid Object {}",
-                                                 ec);
-                                messages::internalError(response->res);
-                                return;
-                            }
-                            messages::success(response->res);
-                        },
-                        "xyz.openbmc_project.EntityManager", chassis,
-                        "xyz.openbmc_project.AddObject", "AddObject", output);
-                }
-            }
-        }
-    }
-
-    ~SetPIDValues()
-    {
-        try
-        {
-            pidSetDone();
-        }
-        catch (...)
-        {
-            BMCWEB_LOG_CRITICAL("pidSetDone threw exception");
-        }
-    }
-
-    std::shared_ptr<bmcweb::AsyncResp> asyncResp;
-    std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>>
-        configuration;
-    std::optional<std::string> profile;
-    dbus::utility::ManagedObjectType managedObj;
-    std::vector<std::string> supportedProfiles;
-    std::string currentProfile;
-    std::string profileConnection;
-    std::string profilePath;
-    size_t objectCount = 0;
-};
-
 /**
  * @brief Retrieves BMC manager location data over DBus
  *
@@ -2078,22 +641,7 @@
                                         BMCWEB_REDFISH_MANAGER_URI_NAME);
             }
 
-            // default oem data
-            nlohmann::json& oem = asyncResp->res.jsonValue["Oem"];
-            nlohmann::json& oemOpenbmc = oem["OpenBmc"];
-            oem["@odata.id"] =
-                boost::urls::format("/redfish/v1/Managers/{}#/Oem",
-                                    BMCWEB_REDFISH_MANAGER_URI_NAME);
-            oemOpenbmc["@odata.type"] = "#OpenBMCManager.v1_0_0.Manager";
-            oemOpenbmc["@odata.id"] =
-                boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc",
-                                    BMCWEB_REDFISH_MANAGER_URI_NAME);
-
-            nlohmann::json::object_t certificates;
-            certificates["@odata.id"] = boost::urls::format(
-                "/redfish/v1/Managers/{}/Truststore/Certificates",
-                BMCWEB_REDFISH_MANAGER_URI_NAME);
-            oemOpenbmc["Certificates"] = std::move(certificates);
+            getHandleOemOpenBmc(req, asyncResp, managerId);
 
             // Manager.Reset (an action) can be many values, OpenBMC only
             // supports BMC reboot.