19c310685SBorawski.Lukasz /* 29c310685SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation 39c310685SBorawski.Lukasz // 49c310685SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License"); 59c310685SBorawski.Lukasz // you may not use this file except in compliance with the License. 69c310685SBorawski.Lukasz // You may obtain a copy of the License at 79c310685SBorawski.Lukasz // 89c310685SBorawski.Lukasz // http://www.apache.org/licenses/LICENSE-2.0 99c310685SBorawski.Lukasz // 109c310685SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software 119c310685SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS, 129c310685SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c310685SBorawski.Lukasz // See the License for the specific language governing permissions and 149c310685SBorawski.Lukasz // limitations under the License. 159c310685SBorawski.Lukasz */ 169c310685SBorawski.Lukasz #pragma once 179c310685SBorawski.Lukasz 1813451e39SWilly Tu #include "bmcweb_config.h" 1913451e39SWilly Tu 20a51fc2d2SSui Chen #include "app.hpp" 21a51fc2d2SSui Chen #include "dbus_utility.hpp" 22a51fc2d2SSui Chen #include "query.hpp" 23c5d03ff4SJennifer Lee #include "redfish_util.hpp" 24a51fc2d2SSui Chen #include "registries/privilege_registry.hpp" 25fac6e53bSKrzysztof Grobelny #include "utils/dbus_utils.hpp" 263ccb3adbSEd Tanous #include "utils/json_utils.hpp" 27a51fc2d2SSui Chen #include "utils/sw_utils.hpp" 28a51fc2d2SSui Chen #include "utils/systemd_utils.hpp" 292b82937eSEd Tanous #include "utils/time_utils.hpp" 309c310685SBorawski.Lukasz 31e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 32ef4c65b7SEd Tanous #include <boost/url/format.hpp> 33fac6e53bSKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 34fac6e53bSKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 351214b7e7SGunnar Mills 36a170f275SEd Tanous #include <algorithm> 37e99073f5SGeorge Liu #include <array> 384bfefa74SGunnar Mills #include <cstdint> 391214b7e7SGunnar Mills #include <memory> 409970e93fSKonstantin Aladyshev #include <optional> 413544d2a7SEd Tanous #include <ranges> 421214b7e7SGunnar Mills #include <sstream> 439970e93fSKonstantin Aladyshev #include <string> 44e99073f5SGeorge Liu #include <string_view> 45abf2add6SEd Tanous #include <variant> 465b4aa86bSJames Feist 471abe55efSEd Tanous namespace redfish 481abe55efSEd Tanous { 49ed5befbdSJennifer Lee 50ed5befbdSJennifer Lee /** 512a5c4407SGunnar Mills * Function reboots the BMC. 522a5c4407SGunnar Mills * 532a5c4407SGunnar Mills * @param[in] asyncResp - Shared pointer for completing asynchronous calls 54ed5befbdSJennifer Lee */ 558d1b46d7Szhanghch05 inline void 568d1b46d7Szhanghch05 doBMCGracefulRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 57ed5befbdSJennifer Lee { 58ed5befbdSJennifer Lee const char* processName = "xyz.openbmc_project.State.BMC"; 59ed5befbdSJennifer Lee const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 60ed5befbdSJennifer Lee const char* interfaceName = "xyz.openbmc_project.State.BMC"; 61ed5befbdSJennifer Lee const std::string& propertyValue = 62ed5befbdSJennifer Lee "xyz.openbmc_project.State.BMC.Transition.Reboot"; 63ed5befbdSJennifer Lee const char* destProperty = "RequestedBMCTransition"; 64ed5befbdSJennifer Lee 65ed5befbdSJennifer Lee // Create the D-Bus variant for D-Bus call. 669ae226faSGeorge Liu sdbusplus::asio::setProperty( 679ae226faSGeorge Liu *crow::connections::systemBus, processName, objectPath, interfaceName, 689ae226faSGeorge Liu destProperty, propertyValue, 695e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 70ed5befbdSJennifer Lee // Use "Set" method to set the property value. 71ed5befbdSJennifer Lee if (ec) 72ed5befbdSJennifer Lee { 7362598e31SEd Tanous BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec); 74ed5befbdSJennifer Lee messages::internalError(asyncResp->res); 75ed5befbdSJennifer Lee return; 76ed5befbdSJennifer Lee } 77ed5befbdSJennifer Lee 78ed5befbdSJennifer Lee messages::success(asyncResp->res); 799ae226faSGeorge Liu }); 80ed5befbdSJennifer Lee } 812a5c4407SGunnar Mills 828d1b46d7Szhanghch05 inline void 838d1b46d7Szhanghch05 doBMCForceRestart(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 84f92af389SJayaprakash Mutyala { 85f92af389SJayaprakash Mutyala const char* processName = "xyz.openbmc_project.State.BMC"; 86f92af389SJayaprakash Mutyala const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 87f92af389SJayaprakash Mutyala const char* interfaceName = "xyz.openbmc_project.State.BMC"; 88f92af389SJayaprakash Mutyala const std::string& propertyValue = 89f92af389SJayaprakash Mutyala "xyz.openbmc_project.State.BMC.Transition.HardReboot"; 90f92af389SJayaprakash Mutyala const char* destProperty = "RequestedBMCTransition"; 91f92af389SJayaprakash Mutyala 92f92af389SJayaprakash Mutyala // Create the D-Bus variant for D-Bus call. 939ae226faSGeorge Liu sdbusplus::asio::setProperty( 949ae226faSGeorge Liu *crow::connections::systemBus, processName, objectPath, interfaceName, 959ae226faSGeorge Liu destProperty, propertyValue, 965e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 97f92af389SJayaprakash Mutyala // Use "Set" method to set the property value. 98f92af389SJayaprakash Mutyala if (ec) 99f92af389SJayaprakash Mutyala { 10062598e31SEd Tanous BMCWEB_LOG_DEBUG("[Set] Bad D-Bus request error: {}", ec); 101f92af389SJayaprakash Mutyala messages::internalError(asyncResp->res); 102f92af389SJayaprakash Mutyala return; 103f92af389SJayaprakash Mutyala } 104f92af389SJayaprakash Mutyala 105f92af389SJayaprakash Mutyala messages::success(asyncResp->res); 1069ae226faSGeorge Liu }); 107f92af389SJayaprakash Mutyala } 108f92af389SJayaprakash Mutyala 1092a5c4407SGunnar Mills /** 1102a5c4407SGunnar Mills * ManagerResetAction class supports the POST method for the Reset (reboot) 1112a5c4407SGunnar Mills * action. 1122a5c4407SGunnar Mills */ 1137e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetAction(App& app) 1142a5c4407SGunnar Mills { 1152a5c4407SGunnar Mills /** 1162a5c4407SGunnar Mills * Function handles POST method request. 1172a5c4407SGunnar Mills * Analyzes POST body before sending Reset (Reboot) request data to D-Bus. 118f92af389SJayaprakash Mutyala * OpenBMC supports ResetType "GracefulRestart" and "ForceRestart". 1192a5c4407SGunnar Mills */ 1207e860f15SJohn Edward Broadbent 121*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/Actions/Manager.Reset/") 122ed398213SEd Tanous .privileges(redfish::privileges::postManager) 1237e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 12445ca1b86SEd Tanous [&app](const crow::Request& req, 125*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 126*253f11b8SEd Tanous const std::string& managerId) { 1273ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 12845ca1b86SEd Tanous { 12945ca1b86SEd Tanous return; 13045ca1b86SEd Tanous } 131*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 132*253f11b8SEd Tanous { 133*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 134*253f11b8SEd Tanous return; 135*253f11b8SEd Tanous } 136*253f11b8SEd Tanous 13762598e31SEd Tanous BMCWEB_LOG_DEBUG("Post Manager Reset."); 1382a5c4407SGunnar Mills 1392a5c4407SGunnar Mills std::string resetType; 1402a5c4407SGunnar Mills 14115ed6780SWilly Tu if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", 1427e860f15SJohn Edward Broadbent resetType)) 1432a5c4407SGunnar Mills { 1442a5c4407SGunnar Mills return; 1452a5c4407SGunnar Mills } 1462a5c4407SGunnar Mills 147f92af389SJayaprakash Mutyala if (resetType == "GracefulRestart") 148f92af389SJayaprakash Mutyala { 14962598e31SEd Tanous BMCWEB_LOG_DEBUG("Proceeding with {}", resetType); 150f92af389SJayaprakash Mutyala doBMCGracefulRestart(asyncResp); 151f92af389SJayaprakash Mutyala return; 152f92af389SJayaprakash Mutyala } 1533174e4dfSEd Tanous if (resetType == "ForceRestart") 154f92af389SJayaprakash Mutyala { 15562598e31SEd Tanous BMCWEB_LOG_DEBUG("Proceeding with {}", resetType); 156f92af389SJayaprakash Mutyala doBMCForceRestart(asyncResp); 157f92af389SJayaprakash Mutyala return; 158f92af389SJayaprakash Mutyala } 15962598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", resetType); 1602a5c4407SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 1612a5c4407SGunnar Mills "ResetType"); 1622a5c4407SGunnar Mills 1632a5c4407SGunnar Mills return; 1647e860f15SJohn Edward Broadbent }); 1652a5c4407SGunnar Mills } 166ed5befbdSJennifer Lee 1673e40fc74SGunnar Mills /** 1683e40fc74SGunnar Mills * ManagerResetToDefaultsAction class supports POST method for factory reset 1693e40fc74SGunnar Mills * action. 1703e40fc74SGunnar Mills */ 1717e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetToDefaultsAction(App& app) 1723e40fc74SGunnar Mills { 1733e40fc74SGunnar Mills /** 1743e40fc74SGunnar Mills * Function handles ResetToDefaults POST method request. 1753e40fc74SGunnar Mills * 1763e40fc74SGunnar Mills * Analyzes POST body message and factory resets BMC by calling 1773e40fc74SGunnar Mills * BMC code updater factory reset followed by a BMC reboot. 1783e40fc74SGunnar Mills * 1793e40fc74SGunnar Mills * BMC code updater factory reset wipes the whole BMC read-write 1803e40fc74SGunnar Mills * filesystem which includes things like the network settings. 1813e40fc74SGunnar Mills * 1823e40fc74SGunnar Mills * OpenBMC only supports ResetToDefaultsType "ResetAll". 1833e40fc74SGunnar Mills */ 1847e860f15SJohn Edward Broadbent 1857e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, 186*253f11b8SEd Tanous "/redfish/v1/Managers/<str>/Actions/Manager.ResetToDefaults/") 187ed398213SEd Tanous .privileges(redfish::privileges::postManager) 1887e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 18945ca1b86SEd Tanous [&app](const crow::Request& req, 190*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 191*253f11b8SEd Tanous const std::string& managerId) { 1923ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19345ca1b86SEd Tanous { 19445ca1b86SEd Tanous return; 19545ca1b86SEd Tanous } 196*253f11b8SEd Tanous 197*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 198*253f11b8SEd Tanous { 199*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 200*253f11b8SEd Tanous return; 201*253f11b8SEd Tanous } 202*253f11b8SEd Tanous 20362598e31SEd Tanous BMCWEB_LOG_DEBUG("Post ResetToDefaults."); 2043e40fc74SGunnar Mills 2059970e93fSKonstantin Aladyshev std::optional<std::string> resetType; 2069970e93fSKonstantin Aladyshev std::optional<std::string> resetToDefaultsType; 2073e40fc74SGunnar Mills 2089970e93fSKonstantin Aladyshev if (!json_util::readJsonAction(req, asyncResp->res, "ResetType", 2099970e93fSKonstantin Aladyshev resetType, "ResetToDefaultsType", 2109970e93fSKonstantin Aladyshev resetToDefaultsType)) 2113e40fc74SGunnar Mills { 2129970e93fSKonstantin Aladyshev BMCWEB_LOG_DEBUG("Missing property ResetType."); 2133e40fc74SGunnar Mills 214002d39b4SEd Tanous messages::actionParameterMissing(asyncResp->res, "ResetToDefaults", 2159970e93fSKonstantin Aladyshev "ResetType"); 2163e40fc74SGunnar Mills return; 2173e40fc74SGunnar Mills } 2183e40fc74SGunnar Mills 2199970e93fSKonstantin Aladyshev if (resetToDefaultsType && !resetType) 2209970e93fSKonstantin Aladyshev { 2219970e93fSKonstantin Aladyshev BMCWEB_LOG_WARNING( 2229970e93fSKonstantin Aladyshev "Using deprecated ResetToDefaultsType, should be ResetType." 2239970e93fSKonstantin Aladyshev "Support for the ResetToDefaultsType will be dropped in 2Q24"); 2249970e93fSKonstantin Aladyshev resetType = resetToDefaultsType; 2259970e93fSKonstantin Aladyshev } 2269970e93fSKonstantin Aladyshev 2273e40fc74SGunnar Mills if (resetType != "ResetAll") 2283e40fc74SGunnar Mills { 2299970e93fSKonstantin Aladyshev BMCWEB_LOG_DEBUG("Invalid property value for ResetType: {}", 2309970e93fSKonstantin Aladyshev *resetType); 2319970e93fSKonstantin Aladyshev messages::actionParameterNotSupported(asyncResp->res, *resetType, 2329970e93fSKonstantin Aladyshev "ResetType"); 2333e40fc74SGunnar Mills return; 2343e40fc74SGunnar Mills } 2353e40fc74SGunnar Mills 2363e40fc74SGunnar Mills crow::connections::systemBus->async_method_call( 2375e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec) { 2383e40fc74SGunnar Mills if (ec) 2393e40fc74SGunnar Mills { 24062598e31SEd Tanous BMCWEB_LOG_DEBUG("Failed to ResetToDefaults: {}", ec); 2413e40fc74SGunnar Mills messages::internalError(asyncResp->res); 2423e40fc74SGunnar Mills return; 2433e40fc74SGunnar Mills } 2443e40fc74SGunnar Mills // Factory Reset doesn't actually happen until a reboot 2453e40fc74SGunnar Mills // Can't erase what the BMC is running on 2463e40fc74SGunnar Mills doBMCGracefulRestart(asyncResp); 2473e40fc74SGunnar Mills }, 2483e40fc74SGunnar Mills "xyz.openbmc_project.Software.BMC.Updater", 2493e40fc74SGunnar Mills "/xyz/openbmc_project/software", 2503e40fc74SGunnar Mills "xyz.openbmc_project.Common.FactoryReset", "Reset"); 2517e860f15SJohn Edward Broadbent }); 2523e40fc74SGunnar Mills } 2533e40fc74SGunnar Mills 2541cb1a9e6SAppaRao Puli /** 2551cb1a9e6SAppaRao Puli * ManagerResetActionInfo derived class for delivering Manager 2561cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 2571cb1a9e6SAppaRao Puli */ 2587e860f15SJohn Edward Broadbent inline void requestRoutesManagerResetActionInfo(App& app) 2591cb1a9e6SAppaRao Puli { 2601cb1a9e6SAppaRao Puli /** 2611cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 2621cb1a9e6SAppaRao Puli */ 2637e860f15SJohn Edward Broadbent 264*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ResetActionInfo/") 265ed398213SEd Tanous .privileges(redfish::privileges::getActionInfo) 2667e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 26745ca1b86SEd Tanous [&app](const crow::Request& req, 268*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 269*253f11b8SEd Tanous const std::string& managerId) { 2703ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 27145ca1b86SEd Tanous { 27245ca1b86SEd Tanous return; 27345ca1b86SEd Tanous } 2741476687dSEd Tanous 275*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 276*253f11b8SEd Tanous { 277*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 278*253f11b8SEd Tanous return; 279*253f11b8SEd Tanous } 280*253f11b8SEd Tanous 2811476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2821476687dSEd Tanous "#ActionInfo.v1_1_2.ActionInfo"; 2831476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 284*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo", 285*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2861476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Reset Action Info"; 2871476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "ResetActionInfo"; 2881476687dSEd Tanous nlohmann::json::object_t parameter; 2891476687dSEd Tanous parameter["Name"] = "ResetType"; 2901476687dSEd Tanous parameter["Required"] = true; 2911476687dSEd Tanous parameter["DataType"] = "String"; 2921476687dSEd Tanous 2931476687dSEd Tanous nlohmann::json::array_t allowableValues; 294ad539545SPatrick Williams allowableValues.emplace_back("GracefulRestart"); 295ad539545SPatrick Williams allowableValues.emplace_back("ForceRestart"); 2961476687dSEd Tanous parameter["AllowableValues"] = std::move(allowableValues); 2971476687dSEd Tanous 2981476687dSEd Tanous nlohmann::json::array_t parameters; 299ad539545SPatrick Williams parameters.emplace_back(std::move(parameter)); 3001476687dSEd Tanous 3011476687dSEd Tanous asyncResp->res.jsonValue["Parameters"] = std::move(parameters); 3027e860f15SJohn Edward Broadbent }); 3031cb1a9e6SAppaRao Puli } 3041cb1a9e6SAppaRao Puli 3055b4aa86bSJames Feist static constexpr const char* objectManagerIface = 3065b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 3075b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 3085b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 3095b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 3105b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 311b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface = 312b7a08d04SJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 31373df0db0SJames Feist static constexpr const char* thermalModeIface = 31473df0db0SJames Feist "xyz.openbmc_project.Control.ThermalMode"; 3159c310685SBorawski.Lukasz 3168d1b46d7Szhanghch05 inline void 3178d1b46d7Szhanghch05 asyncPopulatePid(const std::string& connection, const std::string& path, 31873df0db0SJames Feist const std::string& currentProfile, 31973df0db0SJames Feist const std::vector<std::string>& supportedProfiles, 3208d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 3215b4aa86bSJames Feist { 3225eb468daSGeorge Liu sdbusplus::message::object_path objPath(path); 3235eb468daSGeorge Liu dbus::utility::getManagedObjects( 3245eb468daSGeorge Liu connection, objPath, 32573df0db0SJames Feist [asyncResp, currentProfile, supportedProfiles]( 3265e7e2dc5SEd Tanous const boost::system::error_code& ec, 3275b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 3285b4aa86bSJames Feist if (ec) 3295b4aa86bSJames Feist { 33062598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 331f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3325b4aa86bSJames Feist return; 3335b4aa86bSJames Feist } 3345b4aa86bSJames Feist nlohmann::json& configRoot = 3355b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 3365b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 3375b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 338*253f11b8SEd Tanous fans["@odata.id"] = boost::urls::format( 339*253f11b8SEd Tanous "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanControllers", 340*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 3415b4aa86bSJames Feist 3425b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 3435b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 344*253f11b8SEd Tanous pids["@odata.id"] = boost::urls::format( 345*253f11b8SEd Tanous "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/PidControllers", 346*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 3475b4aa86bSJames Feist 348b7a08d04SJames Feist nlohmann::json& stepwise = configRoot["StepwiseControllers"]; 349b7a08d04SJames Feist stepwise["@odata.type"] = "#OemManager.StepwiseControllers"; 350*253f11b8SEd Tanous stepwise["@odata.id"] = boost::urls::format( 351*253f11b8SEd Tanous "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/StepwiseControllers", 352*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 353b7a08d04SJames Feist 3545b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 355*253f11b8SEd Tanous zones["@odata.id"] = boost::urls::format( 356*253f11b8SEd Tanous "/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan/FanZones", 357*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 3585b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 359*253f11b8SEd Tanous configRoot["@odata.id"] = 360*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc/Fan", 361*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 3625b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 36373df0db0SJames Feist configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles; 36473df0db0SJames Feist 36573df0db0SJames Feist if (!currentProfile.empty()) 36673df0db0SJames Feist { 36773df0db0SJames Feist configRoot["Profile"] = currentProfile; 36873df0db0SJames Feist } 369bf2ddedeSCarson Labrado BMCWEB_LOG_DEBUG("profile = {} !", currentProfile); 3705b4aa86bSJames Feist 3715b4aa86bSJames Feist for (const auto& pathPair : managedObj) 3725b4aa86bSJames Feist { 3735b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 3745b4aa86bSJames Feist { 3755b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 376b7a08d04SJames Feist intfPair.first != pidZoneConfigurationIface && 377b7a08d04SJames Feist intfPair.first != stepwiseConfigurationIface) 3785b4aa86bSJames Feist { 3795b4aa86bSJames Feist continue; 3805b4aa86bSJames Feist } 38173df0db0SJames Feist 382711ac7a9SEd Tanous std::string name; 383711ac7a9SEd Tanous 384711ac7a9SEd Tanous for (const std::pair<std::string, 385002d39b4SEd Tanous dbus::utility::DbusVariantType>& propPair : 386002d39b4SEd Tanous intfPair.second) 387711ac7a9SEd Tanous { 388711ac7a9SEd Tanous if (propPair.first == "Name") 389711ac7a9SEd Tanous { 3905b4aa86bSJames Feist const std::string* namePtr = 391711ac7a9SEd Tanous std::get_if<std::string>(&propPair.second); 3925b4aa86bSJames Feist if (namePtr == nullptr) 3935b4aa86bSJames Feist { 39462598e31SEd Tanous BMCWEB_LOG_ERROR("Pid Name Field illegal"); 395b7a08d04SJames Feist messages::internalError(asyncResp->res); 3965b4aa86bSJames Feist return; 3975b4aa86bSJames Feist } 398db697703SWilly Tu name = *namePtr; 3995b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 400711ac7a9SEd Tanous } 401711ac7a9SEd Tanous else if (propPair.first == "Profiles") 40273df0db0SJames Feist { 40373df0db0SJames Feist const std::vector<std::string>* profiles = 40473df0db0SJames Feist std::get_if<std::vector<std::string>>( 405711ac7a9SEd Tanous &propPair.second); 40673df0db0SJames Feist if (profiles == nullptr) 40773df0db0SJames Feist { 40862598e31SEd Tanous BMCWEB_LOG_ERROR("Pid Profiles Field illegal"); 40973df0db0SJames Feist messages::internalError(asyncResp->res); 41073df0db0SJames Feist return; 41173df0db0SJames Feist } 41273df0db0SJames Feist if (std::find(profiles->begin(), profiles->end(), 41373df0db0SJames Feist currentProfile) == profiles->end()) 41473df0db0SJames Feist { 41562598e31SEd Tanous BMCWEB_LOG_INFO( 41662598e31SEd Tanous "{} not supported in current profile", name); 41773df0db0SJames Feist continue; 41873df0db0SJames Feist } 41973df0db0SJames Feist } 420711ac7a9SEd Tanous } 421b7a08d04SJames Feist nlohmann::json* config = nullptr; 422c33a90ecSJames Feist const std::string* classPtr = nullptr; 423711ac7a9SEd Tanous 424711ac7a9SEd Tanous for (const std::pair<std::string, 425002d39b4SEd Tanous dbus::utility::DbusVariantType>& propPair : 426002d39b4SEd Tanous intfPair.second) 427c33a90ecSJames Feist { 428727dc83fSLei YU if (propPair.first == "Class") 429711ac7a9SEd Tanous { 430002d39b4SEd Tanous classPtr = std::get_if<std::string>(&propPair.second); 431711ac7a9SEd Tanous } 432c33a90ecSJames Feist } 433c33a90ecSJames Feist 434*253f11b8SEd Tanous boost::urls::url url( 435*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}", 436*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME)); 4375b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 4385b4aa86bSJames Feist { 4395b4aa86bSJames Feist std::string chassis; 440002d39b4SEd Tanous if (!dbus::utility::getNthStringFromPath(pathPair.first.str, 441002d39b4SEd Tanous 5, chassis)) 4425b4aa86bSJames Feist { 4435b4aa86bSJames Feist chassis = "#IllegalValue"; 4445b4aa86bSJames Feist } 4455b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 446ef4c65b7SEd Tanous zone["Chassis"]["@odata.id"] = 447ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassis); 448eddfc437SWilly Tu url.set_fragment( 449eddfc437SWilly Tu ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / name) 450eddfc437SWilly Tu .to_string()); 451eddfc437SWilly Tu zone["@odata.id"] = std::move(url); 4525b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 453b7a08d04SJames Feist config = &zone; 4545b4aa86bSJames Feist } 4555b4aa86bSJames Feist 456b7a08d04SJames Feist else if (intfPair.first == stepwiseConfigurationIface) 4575b4aa86bSJames Feist { 458c33a90ecSJames Feist if (classPtr == nullptr) 459c33a90ecSJames Feist { 46062598e31SEd Tanous BMCWEB_LOG_ERROR("Pid Class Field illegal"); 461c33a90ecSJames Feist messages::internalError(asyncResp->res); 462c33a90ecSJames Feist return; 463c33a90ecSJames Feist } 464c33a90ecSJames Feist 465b7a08d04SJames Feist nlohmann::json& controller = stepwise[name]; 466b7a08d04SJames Feist config = &controller; 467eddfc437SWilly Tu url.set_fragment( 468eddfc437SWilly Tu ("/Oem/OpenBmc/Fan/StepwiseControllers"_json_pointer / 469eddfc437SWilly Tu name) 470eddfc437SWilly Tu .to_string()); 471eddfc437SWilly Tu controller["@odata.id"] = std::move(url); 472b7a08d04SJames Feist controller["@odata.type"] = 473b7a08d04SJames Feist "#OemManager.StepwiseController"; 474b7a08d04SJames Feist 475c33a90ecSJames Feist controller["Direction"] = *classPtr; 4765b4aa86bSJames Feist } 4775b4aa86bSJames Feist 4785b4aa86bSJames Feist // pid and fans are off the same configuration 479b7a08d04SJames Feist else if (intfPair.first == pidConfigurationIface) 4805b4aa86bSJames Feist { 4815b4aa86bSJames Feist if (classPtr == nullptr) 4825b4aa86bSJames Feist { 48362598e31SEd Tanous BMCWEB_LOG_ERROR("Pid Class Field illegal"); 484a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 4855b4aa86bSJames Feist return; 4865b4aa86bSJames Feist } 4875b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 488002d39b4SEd Tanous nlohmann::json& element = isFan ? fans[name] : pids[name]; 489b7a08d04SJames Feist config = &element; 4905b4aa86bSJames Feist if (isFan) 4915b4aa86bSJames Feist { 492eddfc437SWilly Tu url.set_fragment( 493eddfc437SWilly Tu ("/Oem/OpenBmc/Fan/FanControllers"_json_pointer / 494eddfc437SWilly Tu name) 495eddfc437SWilly Tu .to_string()); 496eddfc437SWilly Tu element["@odata.id"] = std::move(url); 497002d39b4SEd Tanous element["@odata.type"] = "#OemManager.FanController"; 4985b4aa86bSJames Feist } 4995b4aa86bSJames Feist else 5005b4aa86bSJames Feist { 501eddfc437SWilly Tu url.set_fragment( 502eddfc437SWilly Tu ("/Oem/OpenBmc/Fan/PidControllers"_json_pointer / 503eddfc437SWilly Tu name) 504eddfc437SWilly Tu .to_string()); 505eddfc437SWilly Tu element["@odata.id"] = std::move(url); 506002d39b4SEd Tanous element["@odata.type"] = "#OemManager.PidController"; 5075b4aa86bSJames Feist } 508b7a08d04SJames Feist } 509b7a08d04SJames Feist else 510b7a08d04SJames Feist { 51162598e31SEd Tanous BMCWEB_LOG_ERROR("Unexpected configuration"); 512b7a08d04SJames Feist messages::internalError(asyncResp->res); 513b7a08d04SJames Feist return; 514b7a08d04SJames Feist } 515b7a08d04SJames Feist 516b7a08d04SJames Feist // used for making maps out of 2 vectors 517b7a08d04SJames Feist const std::vector<double>* keys = nullptr; 518b7a08d04SJames Feist const std::vector<double>* values = nullptr; 519b7a08d04SJames Feist 520b7a08d04SJames Feist for (const auto& propertyPair : intfPair.second) 521b7a08d04SJames Feist { 522b7a08d04SJames Feist if (propertyPair.first == "Type" || 523b7a08d04SJames Feist propertyPair.first == "Class" || 524b7a08d04SJames Feist propertyPair.first == "Name") 525b7a08d04SJames Feist { 526b7a08d04SJames Feist continue; 527b7a08d04SJames Feist } 528b7a08d04SJames Feist 529b7a08d04SJames Feist // zones 530b7a08d04SJames Feist if (intfPair.first == pidZoneConfigurationIface) 531b7a08d04SJames Feist { 532b7a08d04SJames Feist const double* ptr = 533abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 534b7a08d04SJames Feist if (ptr == nullptr) 535b7a08d04SJames Feist { 53662598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 53762598e31SEd Tanous propertyPair.first); 538b7a08d04SJames Feist messages::internalError(asyncResp->res); 539b7a08d04SJames Feist return; 540b7a08d04SJames Feist } 541b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 542b7a08d04SJames Feist } 543b7a08d04SJames Feist 544b7a08d04SJames Feist if (intfPair.first == stepwiseConfigurationIface) 545b7a08d04SJames Feist { 546b7a08d04SJames Feist if (propertyPair.first == "Reading" || 547b7a08d04SJames Feist propertyPair.first == "Output") 548b7a08d04SJames Feist { 549b7a08d04SJames Feist const std::vector<double>* ptr = 550abf2add6SEd Tanous std::get_if<std::vector<double>>( 551b7a08d04SJames Feist &propertyPair.second); 552b7a08d04SJames Feist 553b7a08d04SJames Feist if (ptr == nullptr) 554b7a08d04SJames Feist { 55562598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 55662598e31SEd Tanous propertyPair.first); 557b7a08d04SJames Feist messages::internalError(asyncResp->res); 558b7a08d04SJames Feist return; 559b7a08d04SJames Feist } 560b7a08d04SJames Feist 561b7a08d04SJames Feist if (propertyPair.first == "Reading") 562b7a08d04SJames Feist { 563b7a08d04SJames Feist keys = ptr; 564b7a08d04SJames Feist } 565b7a08d04SJames Feist else 566b7a08d04SJames Feist { 567b7a08d04SJames Feist values = ptr; 568b7a08d04SJames Feist } 569e662eae8SEd Tanous if (keys != nullptr && values != nullptr) 570b7a08d04SJames Feist { 571b7a08d04SJames Feist if (keys->size() != values->size()) 572b7a08d04SJames Feist { 57362598e31SEd Tanous BMCWEB_LOG_ERROR( 57462598e31SEd Tanous "Reading and Output size don't match "); 575b7a08d04SJames Feist messages::internalError(asyncResp->res); 576b7a08d04SJames Feist return; 577b7a08d04SJames Feist } 578b7a08d04SJames Feist nlohmann::json& steps = (*config)["Steps"]; 579b7a08d04SJames Feist steps = nlohmann::json::array(); 580b7a08d04SJames Feist for (size_t ii = 0; ii < keys->size(); ii++) 581b7a08d04SJames Feist { 5821476687dSEd Tanous nlohmann::json::object_t step; 5831476687dSEd Tanous step["Target"] = (*keys)[ii]; 5841476687dSEd Tanous step["Output"] = (*values)[ii]; 585b2ba3072SPatrick Williams steps.emplace_back(std::move(step)); 586b7a08d04SJames Feist } 587b7a08d04SJames Feist } 588b7a08d04SJames Feist } 589b7a08d04SJames Feist if (propertyPair.first == "NegativeHysteresis" || 590b7a08d04SJames Feist propertyPair.first == "PositiveHysteresis") 591b7a08d04SJames Feist { 592b7a08d04SJames Feist const double* ptr = 593abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 594b7a08d04SJames Feist if (ptr == nullptr) 595b7a08d04SJames Feist { 59662598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 59762598e31SEd Tanous propertyPair.first); 598b7a08d04SJames Feist messages::internalError(asyncResp->res); 599b7a08d04SJames Feist return; 600b7a08d04SJames Feist } 601b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 602b7a08d04SJames Feist } 603b7a08d04SJames Feist } 604b7a08d04SJames Feist 605b7a08d04SJames Feist // pid and fans are off the same configuration 606b7a08d04SJames Feist if (intfPair.first == pidConfigurationIface || 607b7a08d04SJames Feist intfPair.first == stepwiseConfigurationIface) 608b7a08d04SJames Feist { 6095b4aa86bSJames Feist if (propertyPair.first == "Zones") 6105b4aa86bSJames Feist { 6115b4aa86bSJames Feist const std::vector<std::string>* inputs = 612abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 6131b6b96c5SEd Tanous &propertyPair.second); 6145b4aa86bSJames Feist 6155b4aa86bSJames Feist if (inputs == nullptr) 6165b4aa86bSJames Feist { 61762598e31SEd Tanous BMCWEB_LOG_ERROR("Zones Pid Field Illegal"); 618a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 6195b4aa86bSJames Feist return; 6205b4aa86bSJames Feist } 621b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 6225b4aa86bSJames Feist data = nlohmann::json::array(); 6235b4aa86bSJames Feist for (std::string itemCopy : *inputs) 6245b4aa86bSJames Feist { 6255b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 6261476687dSEd Tanous nlohmann::json::object_t input; 627ef4c65b7SEd Tanous boost::urls::url managerUrl = boost::urls::format( 628*253f11b8SEd Tanous "/redfish/v1/Managers/{}#{}", 629*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME, 630eddfc437SWilly Tu ("/Oem/OpenBmc/Fan/FanZones"_json_pointer / 631eddfc437SWilly Tu itemCopy) 632eddfc437SWilly Tu .to_string()); 633eddfc437SWilly Tu input["@odata.id"] = std::move(managerUrl); 634b2ba3072SPatrick Williams data.emplace_back(std::move(input)); 6355b4aa86bSJames Feist } 6365b4aa86bSJames Feist } 6375b4aa86bSJames Feist // todo(james): may never happen, but this 6385b4aa86bSJames Feist // assumes configuration data referenced in the 6395b4aa86bSJames Feist // PID config is provided by the same daemon, we 6405b4aa86bSJames Feist // could add another loop to cover all cases, 6415b4aa86bSJames Feist // but I'm okay kicking this can down the road a 6425b4aa86bSJames Feist // bit 6435b4aa86bSJames Feist 6445b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 6455b4aa86bSJames Feist propertyPair.first == "Outputs") 6465b4aa86bSJames Feist { 647b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 6485b4aa86bSJames Feist const std::vector<std::string>* inputs = 649abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 6501b6b96c5SEd Tanous &propertyPair.second); 6515b4aa86bSJames Feist 6525b4aa86bSJames Feist if (inputs == nullptr) 6535b4aa86bSJames Feist { 65462598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 65562598e31SEd Tanous propertyPair.first); 656f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6575b4aa86bSJames Feist return; 6585b4aa86bSJames Feist } 6595b4aa86bSJames Feist data = *inputs; 660b943aaefSJames Feist } 661b943aaefSJames Feist else if (propertyPair.first == "SetPointOffset") 662b943aaefSJames Feist { 663b943aaefSJames Feist const std::string* ptr = 664002d39b4SEd Tanous std::get_if<std::string>(&propertyPair.second); 665b943aaefSJames Feist 666b943aaefSJames Feist if (ptr == nullptr) 667b943aaefSJames Feist { 66862598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 66962598e31SEd Tanous propertyPair.first); 670b943aaefSJames Feist messages::internalError(asyncResp->res); 671b943aaefSJames Feist return; 672b943aaefSJames Feist } 673b943aaefSJames Feist // translate from dbus to redfish 674b943aaefSJames Feist if (*ptr == "WarningHigh") 675b943aaefSJames Feist { 676b943aaefSJames Feist (*config)["SetPointOffset"] = 677b943aaefSJames Feist "UpperThresholdNonCritical"; 678b943aaefSJames Feist } 679b943aaefSJames Feist else if (*ptr == "WarningLow") 680b943aaefSJames Feist { 681b943aaefSJames Feist (*config)["SetPointOffset"] = 682b943aaefSJames Feist "LowerThresholdNonCritical"; 683b943aaefSJames Feist } 684b943aaefSJames Feist else if (*ptr == "CriticalHigh") 685b943aaefSJames Feist { 686b943aaefSJames Feist (*config)["SetPointOffset"] = 687b943aaefSJames Feist "UpperThresholdCritical"; 688b943aaefSJames Feist } 689b943aaefSJames Feist else if (*ptr == "CriticalLow") 690b943aaefSJames Feist { 691b943aaefSJames Feist (*config)["SetPointOffset"] = 692b943aaefSJames Feist "LowerThresholdCritical"; 693b943aaefSJames Feist } 694b943aaefSJames Feist else 695b943aaefSJames Feist { 69662598e31SEd Tanous BMCWEB_LOG_ERROR("Value Illegal {}", *ptr); 697b943aaefSJames Feist messages::internalError(asyncResp->res); 698b943aaefSJames Feist return; 699b943aaefSJames Feist } 700b943aaefSJames Feist } 701b943aaefSJames Feist // doubles 702002d39b4SEd Tanous else if (propertyPair.first == "FFGainCoefficient" || 7035b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 7045b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 7055b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 7065b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 707002d39b4SEd Tanous propertyPair.first == "PositiveHysteresis" || 708002d39b4SEd Tanous propertyPair.first == "NegativeHysteresis" || 7095b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 7105b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 7115b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 7127625cb81SJames Feist propertyPair.first == "SetPoint" || 7135b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 7145b4aa86bSJames Feist propertyPair.first == "SlewPos") 7155b4aa86bSJames Feist { 7165b4aa86bSJames Feist const double* ptr = 717abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 7185b4aa86bSJames Feist if (ptr == nullptr) 7195b4aa86bSJames Feist { 72062598e31SEd Tanous BMCWEB_LOG_ERROR("Field Illegal {}", 72162598e31SEd Tanous propertyPair.first); 722f12894f8SJason M. Bills messages::internalError(asyncResp->res); 7235b4aa86bSJames Feist return; 7245b4aa86bSJames Feist } 725b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 7265b4aa86bSJames Feist } 7275b4aa86bSJames Feist } 7285b4aa86bSJames Feist } 7295b4aa86bSJames Feist } 7305b4aa86bSJames Feist } 7315eb468daSGeorge Liu }); 7325b4aa86bSJames Feist } 733ca537928SJennifer Lee 73483ff9ab6SJames Feist enum class CreatePIDRet 73583ff9ab6SJames Feist { 73683ff9ab6SJames Feist fail, 73783ff9ab6SJames Feist del, 73883ff9ab6SJames Feist patch 73983ff9ab6SJames Feist }; 74083ff9ab6SJames Feist 7418d1b46d7Szhanghch05 inline bool 7428d1b46d7Szhanghch05 getZonesFromJsonReq(const std::shared_ptr<bmcweb::AsyncResp>& response, 7439e9b6049SEd Tanous std::vector<nlohmann::json::object_t>& config, 7445f2caaefSJames Feist std::vector<std::string>& zones) 7455f2caaefSJames Feist { 746b6baeaa4SJames Feist if (config.empty()) 747b6baeaa4SJames Feist { 74862598e31SEd Tanous BMCWEB_LOG_ERROR("Empty Zones"); 749f818b04dSEd Tanous messages::propertyValueFormatError(response->res, config, "Zones"); 750b6baeaa4SJames Feist return false; 751b6baeaa4SJames Feist } 7525f2caaefSJames Feist for (auto& odata : config) 7535f2caaefSJames Feist { 7545f2caaefSJames Feist std::string path; 7559e9b6049SEd Tanous if (!redfish::json_util::readJsonObject(odata, response->res, 7569e9b6049SEd Tanous "@odata.id", path)) 7575f2caaefSJames Feist { 7585f2caaefSJames Feist return false; 7595f2caaefSJames Feist } 7605f2caaefSJames Feist std::string input; 76161adbda3SJames Feist 76261adbda3SJames Feist // 8 below comes from 76361adbda3SJames Feist // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left 76461adbda3SJames Feist // 0 1 2 3 4 5 6 7 8 76561adbda3SJames Feist if (!dbus::utility::getNthStringFromPath(path, 8, input)) 7665f2caaefSJames Feist { 76762598e31SEd Tanous BMCWEB_LOG_ERROR("Got invalid path {}", path); 76862598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal Type Zones"); 769f818b04dSEd Tanous messages::propertyValueFormatError(response->res, odata, "Zones"); 7705f2caaefSJames Feist return false; 7715f2caaefSJames Feist } 772a170f275SEd Tanous std::replace(input.begin(), input.end(), '_', ' '); 7735f2caaefSJames Feist zones.emplace_back(std::move(input)); 7745f2caaefSJames Feist } 7755f2caaefSJames Feist return true; 7765f2caaefSJames Feist } 7775f2caaefSJames Feist 778711ac7a9SEd Tanous inline const dbus::utility::ManagedObjectType::value_type* 77973df0db0SJames Feist findChassis(const dbus::utility::ManagedObjectType& managedObj, 7809e9b6049SEd Tanous std::string_view value, std::string& chassis) 781b6baeaa4SJames Feist { 78262598e31SEd Tanous BMCWEB_LOG_DEBUG("Find Chassis: {}", value); 783b6baeaa4SJames Feist 7849e9b6049SEd Tanous std::string escaped(value); 7856ce82fabSYaswanth Reddy M std::replace(escaped.begin(), escaped.end(), ' ', '_'); 786b6baeaa4SJames Feist escaped = "/" + escaped; 7873544d2a7SEd Tanous auto it = std::ranges::find_if(managedObj, [&escaped](const auto& obj) { 78818f8f608SEd Tanous if (obj.first.str.ends_with(escaped)) 789b6baeaa4SJames Feist { 79062598e31SEd Tanous BMCWEB_LOG_DEBUG("Matched {}", obj.first.str); 791b6baeaa4SJames Feist return true; 792b6baeaa4SJames Feist } 793b6baeaa4SJames Feist return false; 794b6baeaa4SJames Feist }); 795b6baeaa4SJames Feist 796b6baeaa4SJames Feist if (it == managedObj.end()) 797b6baeaa4SJames Feist { 79873df0db0SJames Feist return nullptr; 799b6baeaa4SJames Feist } 800b6baeaa4SJames Feist // 5 comes from <chassis-name> being the 5th element 801b6baeaa4SJames Feist // /xyz/openbmc_project/inventory/system/chassis/<chassis-name> 80273df0db0SJames Feist if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis)) 80373df0db0SJames Feist { 80473df0db0SJames Feist return &(*it); 80573df0db0SJames Feist } 80673df0db0SJames Feist 80773df0db0SJames Feist return nullptr; 808b6baeaa4SJames Feist } 809b6baeaa4SJames Feist 81023a21a1cSEd Tanous inline CreatePIDRet createPidInterface( 8118d1b46d7Szhanghch05 const std::shared_ptr<bmcweb::AsyncResp>& response, const std::string& type, 8129e9b6049SEd Tanous std::string_view name, nlohmann::json& jsonValue, const std::string& path, 81383ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 814b9d36b47SEd Tanous dbus::utility::DBusPropertiesMap& output, std::string& chassis, 815b9d36b47SEd Tanous const std::string& profile) 81683ff9ab6SJames Feist { 8175f2caaefSJames Feist // common deleter 8189e9b6049SEd Tanous if (jsonValue == nullptr) 8195f2caaefSJames Feist { 8205f2caaefSJames Feist std::string iface; 8215f2caaefSJames Feist if (type == "PidControllers" || type == "FanControllers") 8225f2caaefSJames Feist { 8235f2caaefSJames Feist iface = pidConfigurationIface; 8245f2caaefSJames Feist } 8255f2caaefSJames Feist else if (type == "FanZones") 8265f2caaefSJames Feist { 8275f2caaefSJames Feist iface = pidZoneConfigurationIface; 8285f2caaefSJames Feist } 8295f2caaefSJames Feist else if (type == "StepwiseControllers") 8305f2caaefSJames Feist { 8315f2caaefSJames Feist iface = stepwiseConfigurationIface; 8325f2caaefSJames Feist } 8335f2caaefSJames Feist else 8345f2caaefSJames Feist { 83562598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal Type {}", type); 8365f2caaefSJames Feist messages::propertyUnknown(response->res, type); 8375f2caaefSJames Feist return CreatePIDRet::fail; 8385f2caaefSJames Feist } 8396ee7f774SJames Feist 84062598e31SEd Tanous BMCWEB_LOG_DEBUG("del {} {}", path, iface); 8415f2caaefSJames Feist // delete interface 8425f2caaefSJames Feist crow::connections::systemBus->async_method_call( 8435e7e2dc5SEd Tanous [response, path](const boost::system::error_code& ec) { 8445f2caaefSJames Feist if (ec) 8455f2caaefSJames Feist { 84662598e31SEd Tanous BMCWEB_LOG_ERROR("Error patching {}: {}", path, ec); 8475f2caaefSJames Feist messages::internalError(response->res); 848b6baeaa4SJames Feist return; 8495f2caaefSJames Feist } 850b6baeaa4SJames Feist messages::success(response->res); 8515f2caaefSJames Feist }, 8525f2caaefSJames Feist "xyz.openbmc_project.EntityManager", path, iface, "Delete"); 8535f2caaefSJames Feist return CreatePIDRet::del; 8545f2caaefSJames Feist } 8555f2caaefSJames Feist 856711ac7a9SEd Tanous const dbus::utility::ManagedObjectType::value_type* managedItem = nullptr; 857b6baeaa4SJames Feist if (!createNewObject) 858b6baeaa4SJames Feist { 859b6baeaa4SJames Feist // if we aren't creating a new object, we should be able to find it on 860b6baeaa4SJames Feist // d-bus 8619e9b6049SEd Tanous managedItem = findChassis(managedObj, name, chassis); 86273df0db0SJames Feist if (managedItem == nullptr) 863b6baeaa4SJames Feist { 86462598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get chassis from config patch"); 865ef4c65b7SEd Tanous messages::invalidObject( 866ef4c65b7SEd Tanous response->res, 867ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassis)); 868b6baeaa4SJames Feist return CreatePIDRet::fail; 869b6baeaa4SJames Feist } 870b6baeaa4SJames Feist } 871b6baeaa4SJames Feist 87226f6976fSEd Tanous if (!profile.empty() && 87373df0db0SJames Feist (type == "PidControllers" || type == "FanControllers" || 87473df0db0SJames Feist type == "StepwiseControllers")) 87573df0db0SJames Feist { 87673df0db0SJames Feist if (managedItem == nullptr) 87773df0db0SJames Feist { 878b9d36b47SEd Tanous output.emplace_back("Profiles", std::vector<std::string>{profile}); 87973df0db0SJames Feist } 88073df0db0SJames Feist else 88173df0db0SJames Feist { 88273df0db0SJames Feist std::string interface; 88373df0db0SJames Feist if (type == "StepwiseControllers") 88473df0db0SJames Feist { 88573df0db0SJames Feist interface = stepwiseConfigurationIface; 88673df0db0SJames Feist } 88773df0db0SJames Feist else 88873df0db0SJames Feist { 88973df0db0SJames Feist interface = pidConfigurationIface; 89073df0db0SJames Feist } 891711ac7a9SEd Tanous bool ifaceFound = false; 892711ac7a9SEd Tanous for (const auto& iface : managedItem->second) 893711ac7a9SEd Tanous { 894711ac7a9SEd Tanous if (iface.first == interface) 895711ac7a9SEd Tanous { 896711ac7a9SEd Tanous ifaceFound = true; 897711ac7a9SEd Tanous for (const auto& prop : iface.second) 898711ac7a9SEd Tanous { 899711ac7a9SEd Tanous if (prop.first == "Profiles") 900711ac7a9SEd Tanous { 901711ac7a9SEd Tanous const std::vector<std::string>* curProfiles = 902711ac7a9SEd Tanous std::get_if<std::vector<std::string>>( 903711ac7a9SEd Tanous &(prop.second)); 904711ac7a9SEd Tanous if (curProfiles == nullptr) 905711ac7a9SEd Tanous { 90662598e31SEd Tanous BMCWEB_LOG_ERROR( 90762598e31SEd Tanous "Illegal profiles in managed object"); 908711ac7a9SEd Tanous messages::internalError(response->res); 909711ac7a9SEd Tanous return CreatePIDRet::fail; 910711ac7a9SEd Tanous } 911711ac7a9SEd Tanous if (std::find(curProfiles->begin(), 912711ac7a9SEd Tanous curProfiles->end(), 913711ac7a9SEd Tanous profile) == curProfiles->end()) 914711ac7a9SEd Tanous { 915711ac7a9SEd Tanous std::vector<std::string> newProfiles = 916711ac7a9SEd Tanous *curProfiles; 917711ac7a9SEd Tanous newProfiles.push_back(profile); 918b9d36b47SEd Tanous output.emplace_back("Profiles", newProfiles); 919711ac7a9SEd Tanous } 920711ac7a9SEd Tanous } 921711ac7a9SEd Tanous } 922711ac7a9SEd Tanous } 923711ac7a9SEd Tanous } 924711ac7a9SEd Tanous 925711ac7a9SEd Tanous if (!ifaceFound) 92673df0db0SJames Feist { 92762598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find interface in managed object"); 92873df0db0SJames Feist messages::internalError(response->res); 92973df0db0SJames Feist return CreatePIDRet::fail; 93073df0db0SJames Feist } 93173df0db0SJames Feist } 93273df0db0SJames Feist } 93373df0db0SJames Feist 93483ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 93583ff9ab6SJames Feist { 93683ff9ab6SJames Feist if (createNewObject) 93783ff9ab6SJames Feist { 938b9d36b47SEd Tanous output.emplace_back("Class", 939b9d36b47SEd Tanous type == "PidControllers" ? "temp" : "fan"); 940b9d36b47SEd Tanous output.emplace_back("Type", "Pid"); 94183ff9ab6SJames Feist } 9425f2caaefSJames Feist 9439e9b6049SEd Tanous std::optional<std::vector<nlohmann::json::object_t>> zones; 9445f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 9455f2caaefSJames Feist std::optional<std::vector<std::string>> outputs; 9465f2caaefSJames Feist std::map<std::string, std::optional<double>> doubles; 947b943aaefSJames Feist std::optional<std::string> setpointOffset; 9485f2caaefSJames Feist if (!redfish::json_util::readJson( 9499e9b6049SEd Tanous jsonValue, response->res, "Inputs", inputs, "Outputs", outputs, 9505f2caaefSJames Feist "Zones", zones, "FFGainCoefficient", 9515f2caaefSJames Feist doubles["FFGainCoefficient"], "FFOffCoefficient", 9525f2caaefSJames Feist doubles["FFOffCoefficient"], "ICoefficient", 9535f2caaefSJames Feist doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], 9545f2caaefSJames Feist "ILimitMin", doubles["ILimitMin"], "OutLimitMax", 9555f2caaefSJames Feist doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], 9565f2caaefSJames Feist "PCoefficient", doubles["PCoefficient"], "SetPoint", 957b943aaefSJames Feist doubles["SetPoint"], "SetPointOffset", setpointOffset, 958b943aaefSJames Feist "SlewNeg", doubles["SlewNeg"], "SlewPos", doubles["SlewPos"], 959b943aaefSJames Feist "PositiveHysteresis", doubles["PositiveHysteresis"], 960b943aaefSJames Feist "NegativeHysteresis", doubles["NegativeHysteresis"])) 96183ff9ab6SJames Feist { 9625f2caaefSJames Feist return CreatePIDRet::fail; 96383ff9ab6SJames Feist } 9645f2caaefSJames Feist if (zones) 9655f2caaefSJames Feist { 9665f2caaefSJames Feist std::vector<std::string> zonesStr; 9675f2caaefSJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStr)) 9685f2caaefSJames Feist { 96962598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal Zones"); 9705f2caaefSJames Feist return CreatePIDRet::fail; 9715f2caaefSJames Feist } 972b6baeaa4SJames Feist if (chassis.empty() && 973e662eae8SEd Tanous findChassis(managedObj, zonesStr[0], chassis) == nullptr) 974b6baeaa4SJames Feist { 97562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get chassis from config patch"); 976ace85d60SEd Tanous messages::invalidObject( 977ef4c65b7SEd Tanous response->res, 978ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassis)); 979b6baeaa4SJames Feist return CreatePIDRet::fail; 980b6baeaa4SJames Feist } 981b9d36b47SEd Tanous output.emplace_back("Zones", std::move(zonesStr)); 9825f2caaefSJames Feist } 983afb9ee06SEd Tanous 984afb9ee06SEd Tanous if (inputs) 9855f2caaefSJames Feist { 986afb9ee06SEd Tanous for (std::string& value : *inputs) 98783ff9ab6SJames Feist { 988a170f275SEd Tanous std::replace(value.begin(), value.end(), '_', ' '); 98983ff9ab6SJames Feist } 990afb9ee06SEd Tanous output.emplace_back("Inputs", *inputs); 991afb9ee06SEd Tanous } 992afb9ee06SEd Tanous 993afb9ee06SEd Tanous if (outputs) 9945f2caaefSJames Feist { 995afb9ee06SEd Tanous for (std::string& value : *outputs) 9965f2caaefSJames Feist { 997afb9ee06SEd Tanous std::replace(value.begin(), value.end(), '_', ' '); 9985f2caaefSJames Feist } 999afb9ee06SEd Tanous output.emplace_back("Outputs", *outputs); 100083ff9ab6SJames Feist } 100183ff9ab6SJames Feist 1002b943aaefSJames Feist if (setpointOffset) 1003b943aaefSJames Feist { 1004b943aaefSJames Feist // translate between redfish and dbus names 1005b943aaefSJames Feist if (*setpointOffset == "UpperThresholdNonCritical") 1006b943aaefSJames Feist { 1007b9d36b47SEd Tanous output.emplace_back("SetPointOffset", "WarningLow"); 1008b943aaefSJames Feist } 1009b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdNonCritical") 1010b943aaefSJames Feist { 1011b9d36b47SEd Tanous output.emplace_back("SetPointOffset", "WarningHigh"); 1012b943aaefSJames Feist } 1013b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdCritical") 1014b943aaefSJames Feist { 1015b9d36b47SEd Tanous output.emplace_back("SetPointOffset", "CriticalLow"); 1016b943aaefSJames Feist } 1017b943aaefSJames Feist else if (*setpointOffset == "UpperThresholdCritical") 1018b943aaefSJames Feist { 1019b9d36b47SEd Tanous output.emplace_back("SetPointOffset", "CriticalHigh"); 1020b943aaefSJames Feist } 1021b943aaefSJames Feist else 1022b943aaefSJames Feist { 102362598e31SEd Tanous BMCWEB_LOG_ERROR("Invalid setpointoffset {}", *setpointOffset); 10249e9b6049SEd Tanous messages::propertyValueNotInList(response->res, name, 1025ace85d60SEd Tanous "SetPointOffset"); 1026b943aaefSJames Feist return CreatePIDRet::fail; 1027b943aaefSJames Feist } 1028b943aaefSJames Feist } 1029b943aaefSJames Feist 103083ff9ab6SJames Feist // doubles 10315f2caaefSJames Feist for (const auto& pairs : doubles) 103283ff9ab6SJames Feist { 10335f2caaefSJames Feist if (!pairs.second) 103483ff9ab6SJames Feist { 10355f2caaefSJames Feist continue; 103683ff9ab6SJames Feist } 103762598e31SEd Tanous BMCWEB_LOG_DEBUG("{} = {}", pairs.first, *pairs.second); 1038b9d36b47SEd Tanous output.emplace_back(pairs.first, *pairs.second); 10395f2caaefSJames Feist } 104083ff9ab6SJames Feist } 104183ff9ab6SJames Feist 104283ff9ab6SJames Feist else if (type == "FanZones") 104383ff9ab6SJames Feist { 1044b9d36b47SEd Tanous output.emplace_back("Type", "Pid.Zone"); 104583ff9ab6SJames Feist 10469e9b6049SEd Tanous std::optional<std::string> chassisId; 10475f2caaefSJames Feist std::optional<double> failSafePercent; 1048d3ec07f8SJames Feist std::optional<double> minThermalOutput; 10499e9b6049SEd Tanous if (!redfish::json_util::readJson(jsonValue, response->res, 10509e9b6049SEd Tanous "Chassis/@odata.id", chassisId, 10519e9b6049SEd Tanous "FailSafePercent", failSafePercent, 10529e9b6049SEd Tanous "MinThermalOutput", minThermalOutput)) 105383ff9ab6SJames Feist { 105483ff9ab6SJames Feist return CreatePIDRet::fail; 105583ff9ab6SJames Feist } 10565f2caaefSJames Feist 10579e9b6049SEd Tanous if (chassisId) 105883ff9ab6SJames Feist { 1059717794d5SAppaRao Puli // /redfish/v1/chassis/chassis_name/ 10609e9b6049SEd Tanous if (!dbus::utility::getNthStringFromPath(*chassisId, 3, chassis)) 106183ff9ab6SJames Feist { 10629e9b6049SEd Tanous BMCWEB_LOG_ERROR("Got invalid path {}", *chassisId); 1063ace85d60SEd Tanous messages::invalidObject( 1064ef4c65b7SEd Tanous response->res, 10659e9b6049SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", *chassisId)); 106683ff9ab6SJames Feist return CreatePIDRet::fail; 106783ff9ab6SJames Feist } 106883ff9ab6SJames Feist } 1069d3ec07f8SJames Feist if (minThermalOutput) 107083ff9ab6SJames Feist { 1071b9d36b47SEd Tanous output.emplace_back("MinThermalOutput", *minThermalOutput); 10725f2caaefSJames Feist } 10735f2caaefSJames Feist if (failSafePercent) 107483ff9ab6SJames Feist { 1075b9d36b47SEd Tanous output.emplace_back("FailSafePercent", *failSafePercent); 10765f2caaefSJames Feist } 10775f2caaefSJames Feist } 10785f2caaefSJames Feist else if (type == "StepwiseControllers") 10795f2caaefSJames Feist { 1080b9d36b47SEd Tanous output.emplace_back("Type", "Stepwise"); 10815f2caaefSJames Feist 10829e9b6049SEd Tanous std::optional<std::vector<nlohmann::json::object_t>> zones; 10839e9b6049SEd Tanous std::optional<std::vector<nlohmann::json::object_t>> steps; 10845f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 10855f2caaefSJames Feist std::optional<double> positiveHysteresis; 10865f2caaefSJames Feist std::optional<double> negativeHysteresis; 1087c33a90ecSJames Feist std::optional<std::string> direction; // upper clipping curve vs lower 10885f2caaefSJames Feist if (!redfish::json_util::readJson( 10899e9b6049SEd Tanous jsonValue, response->res, "Zones", zones, "Steps", steps, 1090b6baeaa4SJames Feist "Inputs", inputs, "PositiveHysteresis", positiveHysteresis, 1091c33a90ecSJames Feist "NegativeHysteresis", negativeHysteresis, "Direction", 1092c33a90ecSJames Feist direction)) 10935f2caaefSJames Feist { 109483ff9ab6SJames Feist return CreatePIDRet::fail; 109583ff9ab6SJames Feist } 10965f2caaefSJames Feist 10975f2caaefSJames Feist if (zones) 109883ff9ab6SJames Feist { 1099b6baeaa4SJames Feist std::vector<std::string> zonesStrs; 1100b6baeaa4SJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStrs)) 11015f2caaefSJames Feist { 110262598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal Zones"); 110383ff9ab6SJames Feist return CreatePIDRet::fail; 110483ff9ab6SJames Feist } 1105b6baeaa4SJames Feist if (chassis.empty() && 1106e662eae8SEd Tanous findChassis(managedObj, zonesStrs[0], chassis) == nullptr) 1107b6baeaa4SJames Feist { 110862598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get chassis from config patch"); 1109ace85d60SEd Tanous messages::invalidObject( 1110ef4c65b7SEd Tanous response->res, 1111ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassis)); 1112b6baeaa4SJames Feist return CreatePIDRet::fail; 1113b6baeaa4SJames Feist } 1114b9d36b47SEd Tanous output.emplace_back("Zones", std::move(zonesStrs)); 11155f2caaefSJames Feist } 11165f2caaefSJames Feist if (steps) 11175f2caaefSJames Feist { 11185f2caaefSJames Feist std::vector<double> readings; 11195f2caaefSJames Feist std::vector<double> outputs; 11205f2caaefSJames Feist for (auto& step : *steps) 11215f2caaefSJames Feist { 1122543f4400SEd Tanous double target = 0.0; 1123543f4400SEd Tanous double out = 0.0; 11245f2caaefSJames Feist 11259e9b6049SEd Tanous if (!redfish::json_util::readJsonObject( 11269e9b6049SEd Tanous step, response->res, "Target", target, "Output", out)) 11275f2caaefSJames Feist { 11285f2caaefSJames Feist return CreatePIDRet::fail; 11295f2caaefSJames Feist } 11305f2caaefSJames Feist readings.emplace_back(target); 113123a21a1cSEd Tanous outputs.emplace_back(out); 11325f2caaefSJames Feist } 1133b9d36b47SEd Tanous output.emplace_back("Reading", std::move(readings)); 1134b9d36b47SEd Tanous output.emplace_back("Output", std::move(outputs)); 11355f2caaefSJames Feist } 11365f2caaefSJames Feist if (inputs) 11375f2caaefSJames Feist { 11385f2caaefSJames Feist for (std::string& value : *inputs) 11395f2caaefSJames Feist { 1140a170f275SEd Tanous std::replace(value.begin(), value.end(), '_', ' '); 11415f2caaefSJames Feist } 1142b9d36b47SEd Tanous output.emplace_back("Inputs", std::move(*inputs)); 11435f2caaefSJames Feist } 11445f2caaefSJames Feist if (negativeHysteresis) 11455f2caaefSJames Feist { 1146b9d36b47SEd Tanous output.emplace_back("NegativeHysteresis", *negativeHysteresis); 11475f2caaefSJames Feist } 11485f2caaefSJames Feist if (positiveHysteresis) 11495f2caaefSJames Feist { 1150b9d36b47SEd Tanous output.emplace_back("PositiveHysteresis", *positiveHysteresis); 115183ff9ab6SJames Feist } 1152c33a90ecSJames Feist if (direction) 1153c33a90ecSJames Feist { 1154c33a90ecSJames Feist constexpr const std::array<const char*, 2> allowedDirections = { 1155c33a90ecSJames Feist "Ceiling", "Floor"}; 11563544d2a7SEd Tanous if (std::ranges::find(allowedDirections, *direction) == 11573544d2a7SEd Tanous allowedDirections.end()) 1158c33a90ecSJames Feist { 1159c33a90ecSJames Feist messages::propertyValueTypeError(response->res, "Direction", 1160c33a90ecSJames Feist *direction); 1161c33a90ecSJames Feist return CreatePIDRet::fail; 1162c33a90ecSJames Feist } 1163b9d36b47SEd Tanous output.emplace_back("Class", *direction); 1164c33a90ecSJames Feist } 116583ff9ab6SJames Feist } 116683ff9ab6SJames Feist else 116783ff9ab6SJames Feist { 116862598e31SEd Tanous BMCWEB_LOG_ERROR("Illegal Type {}", type); 116935a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 117083ff9ab6SJames Feist return CreatePIDRet::fail; 117183ff9ab6SJames Feist } 117283ff9ab6SJames Feist return CreatePIDRet::patch; 117383ff9ab6SJames Feist } 117473df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues> 117573df0db0SJames Feist { 11766936afe4SEd Tanous struct CompletionValues 11776936afe4SEd Tanous { 11786936afe4SEd Tanous std::vector<std::string> supportedProfiles; 11796936afe4SEd Tanous std::string currentProfile; 11806936afe4SEd Tanous dbus::utility::MapperGetSubTreeResponse subtree; 11816936afe4SEd Tanous }; 118283ff9ab6SJames Feist 11834e23a444SEd Tanous explicit GetPIDValues( 11844e23a444SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) : 118523a21a1cSEd Tanous asyncResp(asyncRespIn) 118673df0db0SJames Feist 11871214b7e7SGunnar Mills {} 11889c310685SBorawski.Lukasz 118973df0db0SJames Feist void run() 11905b4aa86bSJames Feist { 119173df0db0SJames Feist std::shared_ptr<GetPIDValues> self = shared_from_this(); 119273df0db0SJames Feist 119373df0db0SJames Feist // get all configurations 1194e99073f5SGeorge Liu constexpr std::array<std::string_view, 4> interfaces = { 1195e99073f5SGeorge Liu pidConfigurationIface, pidZoneConfigurationIface, 1196e99073f5SGeorge Liu objectManagerIface, stepwiseConfigurationIface}; 1197e99073f5SGeorge Liu dbus::utility::getSubTree( 1198e99073f5SGeorge Liu "/", 0, interfaces, 1199b9d36b47SEd Tanous [self]( 1200e99073f5SGeorge Liu const boost::system::error_code& ec, 1201b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) { 12025b4aa86bSJames Feist if (ec) 12035b4aa86bSJames Feist { 120462598e31SEd Tanous BMCWEB_LOG_ERROR("{}", ec); 120573df0db0SJames Feist messages::internalError(self->asyncResp->res); 120673df0db0SJames Feist return; 120773df0db0SJames Feist } 12086936afe4SEd Tanous self->complete.subtree = subtreeLocal; 1209e99073f5SGeorge Liu }); 121073df0db0SJames Feist 121173df0db0SJames Feist // at the same time get the selected profile 1212e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> thermalModeIfaces = { 1213e99073f5SGeorge Liu thermalModeIface}; 1214e99073f5SGeorge Liu dbus::utility::getSubTree( 1215e99073f5SGeorge Liu "/", 0, thermalModeIfaces, 1216b9d36b47SEd Tanous [self]( 1217e99073f5SGeorge Liu const boost::system::error_code& ec, 1218b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtreeLocal) { 121923a21a1cSEd Tanous if (ec || subtreeLocal.empty()) 122073df0db0SJames Feist { 122173df0db0SJames Feist return; 122273df0db0SJames Feist } 122323a21a1cSEd Tanous if (subtreeLocal[0].second.size() != 1) 122473df0db0SJames Feist { 122573df0db0SJames Feist // invalid mapper response, should never happen 122662598e31SEd Tanous BMCWEB_LOG_ERROR("GetPIDValues: Mapper Error"); 122773df0db0SJames Feist messages::internalError(self->asyncResp->res); 12285b4aa86bSJames Feist return; 12295b4aa86bSJames Feist } 12305b4aa86bSJames Feist 123123a21a1cSEd Tanous const std::string& path = subtreeLocal[0].first; 123223a21a1cSEd Tanous const std::string& owner = subtreeLocal[0].second[0].first; 1233fac6e53bSKrzysztof Grobelny 1234fac6e53bSKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1235fac6e53bSKrzysztof Grobelny *crow::connections::systemBus, owner, path, thermalModeIface, 1236168e20c1SEd Tanous [path, owner, 12375e7e2dc5SEd Tanous self](const boost::system::error_code& ec2, 1238b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& resp) { 123923a21a1cSEd Tanous if (ec2) 124073df0db0SJames Feist { 124162598e31SEd Tanous BMCWEB_LOG_ERROR( 124262598e31SEd Tanous "GetPIDValues: Can't get thermalModeIface {}", path); 124373df0db0SJames Feist messages::internalError(self->asyncResp->res); 124473df0db0SJames Feist return; 124573df0db0SJames Feist } 1246fac6e53bSKrzysztof Grobelny 1247271584abSEd Tanous const std::string* current = nullptr; 1248271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 1249fac6e53bSKrzysztof Grobelny 1250fac6e53bSKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1251fac6e53bSKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), resp, "Current", current, 1252fac6e53bSKrzysztof Grobelny "Supported", supported); 1253fac6e53bSKrzysztof Grobelny 1254fac6e53bSKrzysztof Grobelny if (!success) 125573df0db0SJames Feist { 1256002d39b4SEd Tanous messages::internalError(self->asyncResp->res); 125773df0db0SJames Feist return; 125873df0db0SJames Feist } 1259fac6e53bSKrzysztof Grobelny 126073df0db0SJames Feist if (current == nullptr || supported == nullptr) 126173df0db0SJames Feist { 126262598e31SEd Tanous BMCWEB_LOG_ERROR( 126362598e31SEd Tanous "GetPIDValues: thermal mode iface invalid {}", path); 126473df0db0SJames Feist messages::internalError(self->asyncResp->res); 126573df0db0SJames Feist return; 126673df0db0SJames Feist } 12676936afe4SEd Tanous self->complete.currentProfile = *current; 12686936afe4SEd Tanous self->complete.supportedProfiles = *supported; 1269fac6e53bSKrzysztof Grobelny }); 1270e99073f5SGeorge Liu }); 127173df0db0SJames Feist } 127273df0db0SJames Feist 12736936afe4SEd Tanous static void 12746936afe4SEd Tanous processingComplete(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 12756936afe4SEd Tanous const CompletionValues& completion) 127673df0db0SJames Feist { 127773df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 127873df0db0SJames Feist { 127973df0db0SJames Feist return; 128073df0db0SJames Feist } 12815b4aa86bSJames Feist // create map of <connection, path to objMgr>> 12826936afe4SEd Tanous boost::container::flat_map< 12836936afe4SEd Tanous std::string, std::string, std::less<>, 12846936afe4SEd Tanous std::vector<std::pair<std::string, std::string>>> 12856936afe4SEd Tanous objectMgrPaths; 12866936afe4SEd Tanous boost::container::flat_set<std::string, std::less<>, 12876936afe4SEd Tanous std::vector<std::string>> 12886936afe4SEd Tanous calledConnections; 12896936afe4SEd Tanous for (const auto& pathGroup : completion.subtree) 12905b4aa86bSJames Feist { 12915b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 12925b4aa86bSJames Feist { 12936bce33bcSJames Feist auto findConnection = 12946bce33bcSJames Feist calledConnections.find(connectionGroup.first); 12956bce33bcSJames Feist if (findConnection != calledConnections.end()) 12966bce33bcSJames Feist { 12976bce33bcSJames Feist break; 12986bce33bcSJames Feist } 129973df0db0SJames Feist for (const std::string& interface : connectionGroup.second) 13005b4aa86bSJames Feist { 13015b4aa86bSJames Feist if (interface == objectManagerIface) 13025b4aa86bSJames Feist { 130373df0db0SJames Feist objectMgrPaths[connectionGroup.first] = pathGroup.first; 13045b4aa86bSJames Feist } 13055b4aa86bSJames Feist // this list is alphabetical, so we 13065b4aa86bSJames Feist // should have found the objMgr by now 13075b4aa86bSJames Feist if (interface == pidConfigurationIface || 1308b7a08d04SJames Feist interface == pidZoneConfigurationIface || 1309b7a08d04SJames Feist interface == stepwiseConfigurationIface) 13105b4aa86bSJames Feist { 13115b4aa86bSJames Feist auto findObjMgr = 13125b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 13135b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 13145b4aa86bSJames Feist { 131562598e31SEd Tanous BMCWEB_LOG_DEBUG("{}Has no Object Manager", 131662598e31SEd Tanous connectionGroup.first); 13175b4aa86bSJames Feist continue; 13185b4aa86bSJames Feist } 13196bce33bcSJames Feist 13206bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 13216bce33bcSJames Feist 132273df0db0SJames Feist asyncPopulatePid(findObjMgr->first, findObjMgr->second, 13236936afe4SEd Tanous completion.currentProfile, 13246936afe4SEd Tanous completion.supportedProfiles, 132573df0db0SJames Feist asyncResp); 13265b4aa86bSJames Feist break; 13275b4aa86bSJames Feist } 13285b4aa86bSJames Feist } 13295b4aa86bSJames Feist } 13305b4aa86bSJames Feist } 133173df0db0SJames Feist } 133273df0db0SJames Feist 13336936afe4SEd Tanous ~GetPIDValues() 13346936afe4SEd Tanous { 13356936afe4SEd Tanous boost::asio::post(crow::connections::systemBus->get_io_context(), 13366936afe4SEd Tanous std::bind_front(&processingComplete, asyncResp, 13376936afe4SEd Tanous std::move(complete))); 13386936afe4SEd Tanous } 13396936afe4SEd Tanous 1340ecd6a3a2SEd Tanous GetPIDValues(const GetPIDValues&) = delete; 1341ecd6a3a2SEd Tanous GetPIDValues(GetPIDValues&&) = delete; 1342ecd6a3a2SEd Tanous GetPIDValues& operator=(const GetPIDValues&) = delete; 1343ecd6a3a2SEd Tanous GetPIDValues& operator=(GetPIDValues&&) = delete; 1344ecd6a3a2SEd Tanous 13458d1b46d7Szhanghch05 std::shared_ptr<bmcweb::AsyncResp> asyncResp; 13466936afe4SEd Tanous CompletionValues complete; 134773df0db0SJames Feist }; 134873df0db0SJames Feist 134973df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues> 135073df0db0SJames Feist { 13519e9b6049SEd Tanous SetPIDValues( 13529e9b6049SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn, 13539e9b6049SEd Tanous std::vector< 13549e9b6049SEd Tanous std::pair<std::string, std::optional<nlohmann::json::object_t>>>&& 13559e9b6049SEd Tanous configurationsIn, 13569e9b6049SEd Tanous std::optional<std::string>& profileIn) : 13579e9b6049SEd Tanous asyncResp(asyncRespIn), 13589e9b6049SEd Tanous configuration(std::move(configurationsIn)), 13599e9b6049SEd Tanous profile(std::move(profileIn)) 13609e9b6049SEd Tanous {} 1361ecd6a3a2SEd Tanous 1362ecd6a3a2SEd Tanous SetPIDValues(const SetPIDValues&) = delete; 1363ecd6a3a2SEd Tanous SetPIDValues(SetPIDValues&&) = delete; 1364ecd6a3a2SEd Tanous SetPIDValues& operator=(const SetPIDValues&) = delete; 1365ecd6a3a2SEd Tanous SetPIDValues& operator=(SetPIDValues&&) = delete; 1366ecd6a3a2SEd Tanous 136773df0db0SJames Feist void run() 136873df0db0SJames Feist { 136973df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 137073df0db0SJames Feist { 137173df0db0SJames Feist return; 137273df0db0SJames Feist } 137373df0db0SJames Feist 137473df0db0SJames Feist std::shared_ptr<SetPIDValues> self = shared_from_this(); 137573df0db0SJames Feist 137673df0db0SJames Feist // todo(james): might make sense to do a mapper call here if this 137773df0db0SJames Feist // interface gets more traction 13785eb468daSGeorge Liu sdbusplus::message::object_path objPath( 13795eb468daSGeorge Liu "/xyz/openbmc_project/inventory"); 13805eb468daSGeorge Liu dbus::utility::getManagedObjects( 13815eb468daSGeorge Liu "xyz.openbmc_project.EntityManager", objPath, 13825e7e2dc5SEd Tanous [self](const boost::system::error_code& ec, 1383914e2d5dSEd Tanous const dbus::utility::ManagedObjectType& mObj) { 138473df0db0SJames Feist if (ec) 138573df0db0SJames Feist { 138662598e31SEd Tanous BMCWEB_LOG_ERROR("Error communicating to Entity Manager"); 138773df0db0SJames Feist messages::internalError(self->asyncResp->res); 138873df0db0SJames Feist return; 138973df0db0SJames Feist } 1390e69d9de2SJames Feist const std::array<const char*, 3> configurations = { 1391e69d9de2SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 1392e69d9de2SJames Feist stepwiseConfigurationIface}; 1393e69d9de2SJames Feist 139414b0b8d5SJames Feist for (const auto& [path, object] : mObj) 1395e69d9de2SJames Feist { 139614b0b8d5SJames Feist for (const auto& [interface, _] : object) 1397e69d9de2SJames Feist { 13983544d2a7SEd Tanous if (std::ranges::find(configurations, interface) != 13993544d2a7SEd Tanous configurations.end()) 1400e69d9de2SJames Feist { 140114b0b8d5SJames Feist self->objectCount++; 1402e69d9de2SJames Feist break; 1403e69d9de2SJames Feist } 1404e69d9de2SJames Feist } 1405e69d9de2SJames Feist } 1406914e2d5dSEd Tanous self->managedObj = mObj; 14075eb468daSGeorge Liu }); 140873df0db0SJames Feist 140973df0db0SJames Feist // at the same time get the profile information 1410e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> thermalModeIfaces = { 1411e99073f5SGeorge Liu thermalModeIface}; 1412e99073f5SGeorge Liu dbus::utility::getSubTree( 1413e99073f5SGeorge Liu "/", 0, thermalModeIfaces, 1414e99073f5SGeorge Liu [self](const boost::system::error_code& ec, 1415b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 141673df0db0SJames Feist if (ec || subtree.empty()) 141773df0db0SJames Feist { 141873df0db0SJames Feist return; 141973df0db0SJames Feist } 142073df0db0SJames Feist if (subtree[0].second.empty()) 142173df0db0SJames Feist { 142273df0db0SJames Feist // invalid mapper response, should never happen 142362598e31SEd Tanous BMCWEB_LOG_ERROR("SetPIDValues: Mapper Error"); 142473df0db0SJames Feist messages::internalError(self->asyncResp->res); 142573df0db0SJames Feist return; 142673df0db0SJames Feist } 142773df0db0SJames Feist 142873df0db0SJames Feist const std::string& path = subtree[0].first; 142973df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 1430fac6e53bSKrzysztof Grobelny sdbusplus::asio::getAllProperties( 1431fac6e53bSKrzysztof Grobelny *crow::connections::systemBus, owner, path, thermalModeIface, 14325e7e2dc5SEd Tanous [self, path, owner](const boost::system::error_code& ec2, 1433b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& r) { 1434cb13a392SEd Tanous if (ec2) 143573df0db0SJames Feist { 143662598e31SEd Tanous BMCWEB_LOG_ERROR( 143762598e31SEd Tanous "SetPIDValues: Can't get thermalModeIface {}", path); 143873df0db0SJames Feist messages::internalError(self->asyncResp->res); 143973df0db0SJames Feist return; 144073df0db0SJames Feist } 1441271584abSEd Tanous const std::string* current = nullptr; 1442271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 1443fac6e53bSKrzysztof Grobelny 1444fac6e53bSKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 1445fac6e53bSKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), r, "Current", current, 1446fac6e53bSKrzysztof Grobelny "Supported", supported); 1447fac6e53bSKrzysztof Grobelny 1448fac6e53bSKrzysztof Grobelny if (!success) 144973df0db0SJames Feist { 1450002d39b4SEd Tanous messages::internalError(self->asyncResp->res); 145173df0db0SJames Feist return; 145273df0db0SJames Feist } 1453fac6e53bSKrzysztof Grobelny 145473df0db0SJames Feist if (current == nullptr || supported == nullptr) 145573df0db0SJames Feist { 145662598e31SEd Tanous BMCWEB_LOG_ERROR( 145762598e31SEd Tanous "SetPIDValues: thermal mode iface invalid {}", path); 145873df0db0SJames Feist messages::internalError(self->asyncResp->res); 145973df0db0SJames Feist return; 146073df0db0SJames Feist } 146173df0db0SJames Feist self->currentProfile = *current; 146273df0db0SJames Feist self->supportedProfiles = *supported; 146373df0db0SJames Feist self->profileConnection = owner; 146473df0db0SJames Feist self->profilePath = path; 1465fac6e53bSKrzysztof Grobelny }); 1466e99073f5SGeorge Liu }); 146773df0db0SJames Feist } 146824b2fe81SEd Tanous void pidSetDone() 146973df0db0SJames Feist { 147073df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 147173df0db0SJames Feist { 147273df0db0SJames Feist return; 14735b4aa86bSJames Feist } 14748d1b46d7Szhanghch05 std::shared_ptr<bmcweb::AsyncResp> response = asyncResp; 147573df0db0SJames Feist if (profile) 147673df0db0SJames Feist { 14773544d2a7SEd Tanous if (std::ranges::find(supportedProfiles, *profile) == 14783544d2a7SEd Tanous supportedProfiles.end()) 147973df0db0SJames Feist { 148073df0db0SJames Feist messages::actionParameterUnknown(response->res, "Profile", 148173df0db0SJames Feist *profile); 148273df0db0SJames Feist return; 148373df0db0SJames Feist } 148473df0db0SJames Feist currentProfile = *profile; 14859ae226faSGeorge Liu sdbusplus::asio::setProperty( 14869ae226faSGeorge Liu *crow::connections::systemBus, profileConnection, profilePath, 14879ae226faSGeorge Liu thermalModeIface, "Current", *profile, 14885e7e2dc5SEd Tanous [response](const boost::system::error_code& ec) { 148973df0db0SJames Feist if (ec) 149073df0db0SJames Feist { 149162598e31SEd Tanous BMCWEB_LOG_ERROR("Error patching profile{}", ec); 149273df0db0SJames Feist messages::internalError(response->res); 149373df0db0SJames Feist } 14949ae226faSGeorge Liu }); 149573df0db0SJames Feist } 149673df0db0SJames Feist 149773df0db0SJames Feist for (auto& containerPair : configuration) 149873df0db0SJames Feist { 149973df0db0SJames Feist auto& container = containerPair.second; 150073df0db0SJames Feist if (!container) 150173df0db0SJames Feist { 150273df0db0SJames Feist continue; 150373df0db0SJames Feist } 15046ee7f774SJames Feist 150502cad96eSEd Tanous const std::string& type = containerPair.first; 150673df0db0SJames Feist 15079e9b6049SEd Tanous for (auto& [name, value] : *container) 150873df0db0SJames Feist { 1509cddbf3dfSPotin Lai std::string dbusObjName = name; 1510cddbf3dfSPotin Lai std::replace(dbusObjName.begin(), dbusObjName.end(), ' ', '_'); 151162598e31SEd Tanous BMCWEB_LOG_DEBUG("looking for {}", name); 15126ee7f774SJames Feist 15133544d2a7SEd Tanous auto pathItr = std::ranges::find_if( 15143544d2a7SEd Tanous managedObj, [&dbusObjName](const auto& obj) { 151518f8f608SEd Tanous return obj.first.parent_path() == dbusObjName; 151673df0db0SJames Feist }); 1517b9d36b47SEd Tanous dbus::utility::DBusPropertiesMap output; 151873df0db0SJames Feist 151973df0db0SJames Feist output.reserve(16); // The pid interface length 152073df0db0SJames Feist 152173df0db0SJames Feist // determines if we're patching entity-manager or 152273df0db0SJames Feist // creating a new object 152373df0db0SJames Feist bool createNewObject = (pathItr == managedObj.end()); 152462598e31SEd Tanous BMCWEB_LOG_DEBUG("Found = {}", !createNewObject); 15256ee7f774SJames Feist 152673df0db0SJames Feist std::string iface; 1527ea2b670dSEd Tanous if (!createNewObject) 1528ea2b670dSEd Tanous { 15298be2b5b6SPotin Lai bool findInterface = false; 1530ea2b670dSEd Tanous for (const auto& interface : pathItr->second) 1531ea2b670dSEd Tanous { 1532ea2b670dSEd Tanous if (interface.first == pidConfigurationIface) 1533ea2b670dSEd Tanous { 1534ea2b670dSEd Tanous if (type == "PidControllers" || 1535ea2b670dSEd Tanous type == "FanControllers") 153673df0db0SJames Feist { 153773df0db0SJames Feist iface = pidConfigurationIface; 15388be2b5b6SPotin Lai findInterface = true; 15398be2b5b6SPotin Lai break; 154073df0db0SJames Feist } 154173df0db0SJames Feist } 1542ea2b670dSEd Tanous else if (interface.first == pidZoneConfigurationIface) 154373df0db0SJames Feist { 1544ea2b670dSEd Tanous if (type == "FanZones") 154573df0db0SJames Feist { 1546da39350aSPavanKumarIntel iface = pidZoneConfigurationIface; 15478be2b5b6SPotin Lai findInterface = true; 15488be2b5b6SPotin Lai break; 154973df0db0SJames Feist } 155073df0db0SJames Feist } 1551ea2b670dSEd Tanous else if (interface.first == stepwiseConfigurationIface) 1552ea2b670dSEd Tanous { 1553ea2b670dSEd Tanous if (type == "StepwiseControllers") 155473df0db0SJames Feist { 155573df0db0SJames Feist iface = stepwiseConfigurationIface; 15568be2b5b6SPotin Lai findInterface = true; 15578be2b5b6SPotin Lai break; 15588be2b5b6SPotin Lai } 15598be2b5b6SPotin Lai } 15608be2b5b6SPotin Lai } 15618be2b5b6SPotin Lai 15628be2b5b6SPotin Lai // create new object if interface not found 15638be2b5b6SPotin Lai if (!findInterface) 15648be2b5b6SPotin Lai { 156573df0db0SJames Feist createNewObject = true; 156673df0db0SJames Feist } 1567ea2b670dSEd Tanous } 15686ee7f774SJames Feist 15699e9b6049SEd Tanous if (createNewObject && value == nullptr) 15706ee7f774SJames Feist { 15714e0453b1SGunnar Mills // can't delete a non-existent object 15729e9b6049SEd Tanous messages::propertyValueNotInList(response->res, value, 1573e2616cc5SEd Tanous name); 15746ee7f774SJames Feist continue; 15756ee7f774SJames Feist } 15766ee7f774SJames Feist 15776ee7f774SJames Feist std::string path; 15786ee7f774SJames Feist if (pathItr != managedObj.end()) 15796ee7f774SJames Feist { 15806ee7f774SJames Feist path = pathItr->first.str; 15816ee7f774SJames Feist } 15826ee7f774SJames Feist 158362598e31SEd Tanous BMCWEB_LOG_DEBUG("Create new = {}", createNewObject); 1584e69d9de2SJames Feist 1585e69d9de2SJames Feist // arbitrary limit to avoid attacks 1586e69d9de2SJames Feist constexpr const size_t controllerLimit = 500; 158714b0b8d5SJames Feist if (createNewObject && objectCount >= controllerLimit) 1588e69d9de2SJames Feist { 1589e69d9de2SJames Feist messages::resourceExhaustion(response->res, type); 1590e69d9de2SJames Feist continue; 1591e69d9de2SJames Feist } 1592a170f275SEd Tanous std::string escaped = name; 1593a170f275SEd Tanous std::replace(escaped.begin(), escaped.end(), '_', ' '); 1594a170f275SEd Tanous output.emplace_back("Name", escaped); 159573df0db0SJames Feist 159673df0db0SJames Feist std::string chassis; 159773df0db0SJames Feist CreatePIDRet ret = createPidInterface( 15989e9b6049SEd Tanous response, type, name, value, path, managedObj, 15999e9b6049SEd Tanous createNewObject, output, chassis, currentProfile); 160073df0db0SJames Feist if (ret == CreatePIDRet::fail) 160173df0db0SJames Feist { 160273df0db0SJames Feist return; 160373df0db0SJames Feist } 16043174e4dfSEd Tanous if (ret == CreatePIDRet::del) 160573df0db0SJames Feist { 160673df0db0SJames Feist continue; 160773df0db0SJames Feist } 160873df0db0SJames Feist 160973df0db0SJames Feist if (!createNewObject) 161073df0db0SJames Feist { 161173df0db0SJames Feist for (const auto& property : output) 161273df0db0SJames Feist { 16137a696974SPotin Lai crow::connections::systemBus->async_method_call( 161473df0db0SJames Feist [response, 161573df0db0SJames Feist propertyName{std::string(property.first)}]( 16165e7e2dc5SEd Tanous const boost::system::error_code& ec) { 161773df0db0SJames Feist if (ec) 161873df0db0SJames Feist { 161962598e31SEd Tanous BMCWEB_LOG_ERROR("Error patching {}: {}", 162062598e31SEd Tanous propertyName, ec); 162173df0db0SJames Feist messages::internalError(response->res); 162273df0db0SJames Feist return; 162373df0db0SJames Feist } 162473df0db0SJames Feist messages::success(response->res); 16257a696974SPotin Lai }, 16267a696974SPotin Lai "xyz.openbmc_project.EntityManager", path, 16277a696974SPotin Lai "org.freedesktop.DBus.Properties", "Set", iface, 16287a696974SPotin Lai property.first, property.second); 162973df0db0SJames Feist } 163073df0db0SJames Feist } 163173df0db0SJames Feist else 163273df0db0SJames Feist { 163373df0db0SJames Feist if (chassis.empty()) 163473df0db0SJames Feist { 163562598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to get chassis from config"); 1636ace85d60SEd Tanous messages::internalError(response->res); 163773df0db0SJames Feist return; 163873df0db0SJames Feist } 163973df0db0SJames Feist 164073df0db0SJames Feist bool foundChassis = false; 164173df0db0SJames Feist for (const auto& obj : managedObj) 164273df0db0SJames Feist { 164318f8f608SEd Tanous if (obj.first.parent_path() == chassis) 164473df0db0SJames Feist { 164573df0db0SJames Feist chassis = obj.first.str; 164673df0db0SJames Feist foundChassis = true; 164773df0db0SJames Feist break; 164873df0db0SJames Feist } 164973df0db0SJames Feist } 165073df0db0SJames Feist if (!foundChassis) 165173df0db0SJames Feist { 165262598e31SEd Tanous BMCWEB_LOG_ERROR("Failed to find chassis on dbus"); 165373df0db0SJames Feist messages::resourceMissingAtURI( 1654ace85d60SEd Tanous response->res, 1655ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", 1656ef4c65b7SEd Tanous chassis)); 165773df0db0SJames Feist return; 165873df0db0SJames Feist } 165973df0db0SJames Feist 166073df0db0SJames Feist crow::connections::systemBus->async_method_call( 16615e7e2dc5SEd Tanous [response](const boost::system::error_code& ec) { 166273df0db0SJames Feist if (ec) 166373df0db0SJames Feist { 166462598e31SEd Tanous BMCWEB_LOG_ERROR("Error Adding Pid Object {}", ec); 166573df0db0SJames Feist messages::internalError(response->res); 166673df0db0SJames Feist return; 166773df0db0SJames Feist } 166873df0db0SJames Feist messages::success(response->res); 166973df0db0SJames Feist }, 167073df0db0SJames Feist "xyz.openbmc_project.EntityManager", chassis, 167173df0db0SJames Feist "xyz.openbmc_project.AddObject", "AddObject", output); 167273df0db0SJames Feist } 167373df0db0SJames Feist } 167473df0db0SJames Feist } 167573df0db0SJames Feist } 167624b2fe81SEd Tanous 167724b2fe81SEd Tanous ~SetPIDValues() 167824b2fe81SEd Tanous { 167924b2fe81SEd Tanous try 168024b2fe81SEd Tanous { 168124b2fe81SEd Tanous pidSetDone(); 168224b2fe81SEd Tanous } 168324b2fe81SEd Tanous catch (...) 168424b2fe81SEd Tanous { 168562598e31SEd Tanous BMCWEB_LOG_CRITICAL("pidSetDone threw exception"); 168624b2fe81SEd Tanous } 168724b2fe81SEd Tanous } 168824b2fe81SEd Tanous 16898d1b46d7Szhanghch05 std::shared_ptr<bmcweb::AsyncResp> asyncResp; 16909e9b6049SEd Tanous std::vector<std::pair<std::string, std::optional<nlohmann::json::object_t>>> 169173df0db0SJames Feist configuration; 169273df0db0SJames Feist std::optional<std::string> profile; 169373df0db0SJames Feist dbus::utility::ManagedObjectType managedObj; 169473df0db0SJames Feist std::vector<std::string> supportedProfiles; 169573df0db0SJames Feist std::string currentProfile; 169673df0db0SJames Feist std::string profileConnection; 169773df0db0SJames Feist std::string profilePath; 169814b0b8d5SJames Feist size_t objectCount = 0; 169973df0db0SJames Feist }; 170073df0db0SJames Feist 1701071d8fdfSSunnySrivastava1984 /** 1702071d8fdfSSunnySrivastava1984 * @brief Retrieves BMC manager location data over DBus 1703071d8fdfSSunnySrivastava1984 * 1704ac106bf6SEd Tanous * @param[in] asyncResp Shared pointer for completing asynchronous calls 1705071d8fdfSSunnySrivastava1984 * @param[in] connectionName - service name 1706071d8fdfSSunnySrivastava1984 * @param[in] path - object path 1707071d8fdfSSunnySrivastava1984 * @return none 1708071d8fdfSSunnySrivastava1984 */ 1709ac106bf6SEd Tanous inline void getLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1710071d8fdfSSunnySrivastava1984 const std::string& connectionName, 1711071d8fdfSSunnySrivastava1984 const std::string& path) 1712071d8fdfSSunnySrivastava1984 { 171362598e31SEd Tanous BMCWEB_LOG_DEBUG("Get BMC manager Location data."); 1714071d8fdfSSunnySrivastava1984 17151e1e598dSJonathan Doman sdbusplus::asio::getProperty<std::string>( 17161e1e598dSJonathan Doman *crow::connections::systemBus, connectionName, path, 17171e1e598dSJonathan Doman "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 1718ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec, 17191e1e598dSJonathan Doman const std::string& property) { 1720071d8fdfSSunnySrivastava1984 if (ec) 1721071d8fdfSSunnySrivastava1984 { 172262598e31SEd Tanous BMCWEB_LOG_DEBUG("DBUS response error for " 172362598e31SEd Tanous "Location"); 1724ac106bf6SEd Tanous messages::internalError(asyncResp->res); 1725071d8fdfSSunnySrivastava1984 return; 1726071d8fdfSSunnySrivastava1984 } 1727071d8fdfSSunnySrivastava1984 1728ac106bf6SEd Tanous asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 17291e1e598dSJonathan Doman property; 17301e1e598dSJonathan Doman }); 1731071d8fdfSSunnySrivastava1984 } 17327e860f15SJohn Edward Broadbent // avoid name collision systems.hpp 17337e860f15SJohn Edward Broadbent inline void 1734ac106bf6SEd Tanous managerGetLastResetTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 17354bf2b033SGunnar Mills { 173662598e31SEd Tanous BMCWEB_LOG_DEBUG("Getting Manager Last Reset Time"); 17374bf2b033SGunnar Mills 17381e1e598dSJonathan Doman sdbusplus::asio::getProperty<uint64_t>( 17391e1e598dSJonathan Doman *crow::connections::systemBus, "xyz.openbmc_project.State.BMC", 17401e1e598dSJonathan Doman "/xyz/openbmc_project/state/bmc0", "xyz.openbmc_project.State.BMC", 17411e1e598dSJonathan Doman "LastRebootTime", 1742ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec, 17431e1e598dSJonathan Doman const uint64_t lastResetTime) { 17444bf2b033SGunnar Mills if (ec) 17454bf2b033SGunnar Mills { 174662598e31SEd Tanous BMCWEB_LOG_DEBUG("D-BUS response error {}", ec); 17474bf2b033SGunnar Mills return; 17484bf2b033SGunnar Mills } 17494bf2b033SGunnar Mills 17504bf2b033SGunnar Mills // LastRebootTime is epoch time, in milliseconds 17514bf2b033SGunnar Mills // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19 17521e1e598dSJonathan Doman uint64_t lastResetTimeStamp = lastResetTime / 1000; 17534bf2b033SGunnar Mills 17544bf2b033SGunnar Mills // Convert to ISO 8601 standard 1755ac106bf6SEd Tanous asyncResp->res.jsonValue["LastResetTime"] = 17562b82937eSEd Tanous redfish::time_utils::getDateTimeUint(lastResetTimeStamp); 17571e1e598dSJonathan Doman }); 17584bf2b033SGunnar Mills } 17594bf2b033SGunnar Mills 17604bfefa74SGunnar Mills /** 17614bfefa74SGunnar Mills * @brief Set the running firmware image 17624bfefa74SGunnar Mills * 1763ac106bf6SEd Tanous * @param[i,o] asyncResp - Async response object 17644bfefa74SGunnar Mills * @param[i] runningFirmwareTarget - Image to make the running image 17654bfefa74SGunnar Mills * 17664bfefa74SGunnar Mills * @return void 17674bfefa74SGunnar Mills */ 17687e860f15SJohn Edward Broadbent inline void 1769ac106bf6SEd Tanous setActiveFirmwareImage(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1770f23b7296SEd Tanous const std::string& runningFirmwareTarget) 17714bfefa74SGunnar Mills { 17724bfefa74SGunnar Mills // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id> 1773f23b7296SEd Tanous std::string::size_type idPos = runningFirmwareTarget.rfind('/'); 17744bfefa74SGunnar Mills if (idPos == std::string::npos) 17754bfefa74SGunnar Mills { 1776ac106bf6SEd Tanous messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget, 17774bfefa74SGunnar Mills "@odata.id"); 177862598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't parse firmware ID!"); 17794bfefa74SGunnar Mills return; 17804bfefa74SGunnar Mills } 17814bfefa74SGunnar Mills idPos++; 17824bfefa74SGunnar Mills if (idPos >= runningFirmwareTarget.size()) 17834bfefa74SGunnar Mills { 1784ac106bf6SEd Tanous messages::propertyValueNotInList(asyncResp->res, runningFirmwareTarget, 17854bfefa74SGunnar Mills "@odata.id"); 178662598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid firmware ID."); 17874bfefa74SGunnar Mills return; 17884bfefa74SGunnar Mills } 17894bfefa74SGunnar Mills std::string firmwareId = runningFirmwareTarget.substr(idPos); 17904bfefa74SGunnar Mills 17914bfefa74SGunnar Mills // Make sure the image is valid before setting priority 17925eb468daSGeorge Liu sdbusplus::message::object_path objPath("/xyz/openbmc_project/software"); 17935eb468daSGeorge Liu dbus::utility::getManagedObjects( 17945eb468daSGeorge Liu "xyz.openbmc_project.Software.BMC.Updater", objPath, 17955eb468daSGeorge Liu [asyncResp, firmwareId, runningFirmwareTarget]( 17965eb468daSGeorge Liu const boost::system::error_code& ec, 17975eb468daSGeorge Liu const dbus::utility::ManagedObjectType& subtree) { 17984bfefa74SGunnar Mills if (ec) 17994bfefa74SGunnar Mills { 180062598e31SEd Tanous BMCWEB_LOG_DEBUG("D-Bus response error getting objects."); 1801ac106bf6SEd Tanous messages::internalError(asyncResp->res); 18024bfefa74SGunnar Mills return; 18034bfefa74SGunnar Mills } 18044bfefa74SGunnar Mills 180526f6976fSEd Tanous if (subtree.empty()) 18064bfefa74SGunnar Mills { 180762598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find image!"); 1808ac106bf6SEd Tanous messages::internalError(asyncResp->res); 18094bfefa74SGunnar Mills return; 18104bfefa74SGunnar Mills } 18114bfefa74SGunnar Mills 18124bfefa74SGunnar Mills bool foundImage = false; 181302cad96eSEd Tanous for (const auto& object : subtree) 18144bfefa74SGunnar Mills { 18154bfefa74SGunnar Mills const std::string& path = 18164bfefa74SGunnar Mills static_cast<const std::string&>(object.first); 1817f23b7296SEd Tanous std::size_t idPos2 = path.rfind('/'); 18184bfefa74SGunnar Mills 18194bfefa74SGunnar Mills if (idPos2 == std::string::npos) 18204bfefa74SGunnar Mills { 18214bfefa74SGunnar Mills continue; 18224bfefa74SGunnar Mills } 18234bfefa74SGunnar Mills 18244bfefa74SGunnar Mills idPos2++; 18254bfefa74SGunnar Mills if (idPos2 >= path.size()) 18264bfefa74SGunnar Mills { 18274bfefa74SGunnar Mills continue; 18284bfefa74SGunnar Mills } 18294bfefa74SGunnar Mills 18304bfefa74SGunnar Mills if (path.substr(idPos2) == firmwareId) 18314bfefa74SGunnar Mills { 18324bfefa74SGunnar Mills foundImage = true; 18334bfefa74SGunnar Mills break; 18344bfefa74SGunnar Mills } 18354bfefa74SGunnar Mills } 18364bfefa74SGunnar Mills 18374bfefa74SGunnar Mills if (!foundImage) 18384bfefa74SGunnar Mills { 1839ac106bf6SEd Tanous messages::propertyValueNotInList( 1840ac106bf6SEd Tanous asyncResp->res, runningFirmwareTarget, "@odata.id"); 184162598e31SEd Tanous BMCWEB_LOG_DEBUG("Invalid firmware ID."); 18424bfefa74SGunnar Mills return; 18434bfefa74SGunnar Mills } 18444bfefa74SGunnar Mills 184562598e31SEd Tanous BMCWEB_LOG_DEBUG("Setting firmware version {} to priority 0.", 184662598e31SEd Tanous firmwareId); 18474bfefa74SGunnar Mills 18484bfefa74SGunnar Mills // Only support Immediate 18494bfefa74SGunnar Mills // An addition could be a Redfish Setting like 18504bfefa74SGunnar Mills // ActiveSoftwareImageApplyTime and support OnReset 18519ae226faSGeorge Liu sdbusplus::asio::setProperty( 18529ae226faSGeorge Liu *crow::connections::systemBus, 18539ae226faSGeorge Liu "xyz.openbmc_project.Software.BMC.Updater", 18549ae226faSGeorge Liu "/xyz/openbmc_project/software/" + firmwareId, 18559ae226faSGeorge Liu "xyz.openbmc_project.Software.RedundancyPriority", "Priority", 18569ae226faSGeorge Liu static_cast<uint8_t>(0), 1857ac106bf6SEd Tanous [asyncResp](const boost::system::error_code& ec2) { 18588a592810SEd Tanous if (ec2) 18594bfefa74SGunnar Mills { 186062598e31SEd Tanous BMCWEB_LOG_DEBUG("D-Bus response error setting."); 1861ac106bf6SEd Tanous messages::internalError(asyncResp->res); 18624bfefa74SGunnar Mills return; 18634bfefa74SGunnar Mills } 1864ac106bf6SEd Tanous doBMCGracefulRestart(asyncResp); 18659ae226faSGeorge Liu }); 18665eb468daSGeorge Liu }); 18674bfefa74SGunnar Mills } 18684bfefa74SGunnar Mills 1869c51afd54SEd Tanous inline void 1870c51afd54SEd Tanous afterSetDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1871c51afd54SEd Tanous const boost::system::error_code& ec, 1872c51afd54SEd Tanous const sdbusplus::message_t& msg) 1873c51afd54SEd Tanous { 1874c51afd54SEd Tanous if (ec) 1875c51afd54SEd Tanous { 1876c51afd54SEd Tanous BMCWEB_LOG_DEBUG("Failed to set elapsed time. DBUS response error {}", 1877c51afd54SEd Tanous ec); 1878c51afd54SEd Tanous const sd_bus_error* dbusError = msg.get_error(); 1879c51afd54SEd Tanous if (dbusError != nullptr) 1880c51afd54SEd Tanous { 1881c51afd54SEd Tanous std::string_view errorName(dbusError->name); 1882c51afd54SEd Tanous if (errorName == 1883c51afd54SEd Tanous "org.freedesktop.timedate1.AutomaticTimeSyncEnabled") 1884c51afd54SEd Tanous { 1885c51afd54SEd Tanous BMCWEB_LOG_DEBUG("Setting conflict"); 1886c51afd54SEd Tanous messages::propertyValueConflict( 1887c51afd54SEd Tanous asyncResp->res, "DateTime", 1888c51afd54SEd Tanous "Managers/NetworkProtocol/NTPProcotolEnabled"); 1889c51afd54SEd Tanous return; 1890c51afd54SEd Tanous } 1891c51afd54SEd Tanous } 1892c51afd54SEd Tanous messages::internalError(asyncResp->res); 1893c51afd54SEd Tanous return; 1894c51afd54SEd Tanous } 1895c51afd54SEd Tanous asyncResp->res.result(boost::beast::http::status::no_content); 1896c51afd54SEd Tanous } 1897c51afd54SEd Tanous 1898c51afd54SEd Tanous inline void setDateTime(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1899c51afd54SEd Tanous const std::string& datetime) 1900af5d6058SSantosh Puranik { 190162598e31SEd Tanous BMCWEB_LOG_DEBUG("Set date time: {}", datetime); 1902af5d6058SSantosh Puranik 1903c2e32007SEd Tanous std::optional<redfish::time_utils::usSinceEpoch> us = 1904c2e32007SEd Tanous redfish::time_utils::dateStringToEpoch(datetime); 1905c2e32007SEd Tanous if (!us) 1906af5d6058SSantosh Puranik { 1907ac106bf6SEd Tanous messages::propertyValueFormatError(asyncResp->res, datetime, 1908ac106bf6SEd Tanous "DateTime"); 1909c2e32007SEd Tanous return; 1910c2e32007SEd Tanous } 1911c51afd54SEd Tanous // Set the absolute datetime 1912c51afd54SEd Tanous bool relative = false; 1913c51afd54SEd Tanous bool interactive = false; 1914c51afd54SEd Tanous crow::connections::systemBus->async_method_call( 1915c51afd54SEd Tanous [asyncResp](const boost::system::error_code& ec, 1916c51afd54SEd Tanous const sdbusplus::message_t& msg) { 1917c51afd54SEd Tanous afterSetDateTime(asyncResp, ec, msg); 1918c51afd54SEd Tanous }, 1919c51afd54SEd Tanous "org.freedesktop.timedate1", "/org/freedesktop/timedate1", 1920c51afd54SEd Tanous "org.freedesktop.timedate1", "SetTime", us->count(), relative, 1921c51afd54SEd Tanous interactive); 192283ff9ab6SJames Feist } 19239c310685SBorawski.Lukasz 192475815e5cSEd Tanous inline void 192575815e5cSEd Tanous checkForQuiesced(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 192675815e5cSEd Tanous { 192775815e5cSEd Tanous sdbusplus::asio::getProperty<std::string>( 192875815e5cSEd Tanous *crow::connections::systemBus, "org.freedesktop.systemd1", 192975815e5cSEd Tanous "/org/freedesktop/systemd1/unit/obmc-bmc-service-quiesce@0.target", 193075815e5cSEd Tanous "org.freedesktop.systemd1.Unit", "ActiveState", 193175815e5cSEd Tanous [asyncResp](const boost::system::error_code& ec, 193275815e5cSEd Tanous const std::string& val) { 193375815e5cSEd Tanous if (!ec) 193475815e5cSEd Tanous { 193575815e5cSEd Tanous if (val == "active") 193675815e5cSEd Tanous { 193775815e5cSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 193875815e5cSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Quiesced"; 193975815e5cSEd Tanous return; 194075815e5cSEd Tanous } 194175815e5cSEd Tanous } 194275815e5cSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 194375815e5cSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 194475815e5cSEd Tanous }); 194575815e5cSEd Tanous } 194675815e5cSEd Tanous 19477e860f15SJohn Edward Broadbent inline void requestRoutesManager(App& app) 19487e860f15SJohn Edward Broadbent { 19497e860f15SJohn Edward Broadbent std::string uuid = persistent_data::getConfig().systemUuid; 19509c310685SBorawski.Lukasz 1951*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/") 1952ed398213SEd Tanous .privileges(redfish::privileges::getManager) 1953002d39b4SEd Tanous .methods(boost::beast::http::verb::get)( 1954002d39b4SEd Tanous [&app, uuid](const crow::Request& req, 1955*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1956*253f11b8SEd Tanous const std::string& managerId) { 19573ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 195845ca1b86SEd Tanous { 195945ca1b86SEd Tanous return; 196045ca1b86SEd Tanous } 1961*253f11b8SEd Tanous 1962*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 1963*253f11b8SEd Tanous { 1964*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 1965*253f11b8SEd Tanous return; 1966*253f11b8SEd Tanous } 1967*253f11b8SEd Tanous 1968*253f11b8SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 1969*253f11b8SEd Tanous "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME); 1970a51fc2d2SSui Chen asyncResp->res.jsonValue["@odata.type"] = "#Manager.v1_14_0.Manager"; 1971*253f11b8SEd Tanous asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME; 19727e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Name"] = "OpenBmc Manager"; 19737e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Description"] = 19747e860f15SJohn Edward Broadbent "Baseboard Management Controller"; 19757e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["PowerState"] = "On"; 19761476687dSEd Tanous 19777e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ManagerType"] = "BMC"; 19787e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["UUID"] = systemd_utils::getUuid(); 19797e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid; 1980002d39b4SEd Tanous asyncResp->res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model 19817e860f15SJohn Edward Broadbent 19821476687dSEd Tanous asyncResp->res.jsonValue["LogServices"]["@odata.id"] = 1983*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/LogServices", 1984*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 19851476687dSEd Tanous asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] = 1986*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol", 1987*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 19881476687dSEd Tanous asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] = 1989*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces", 1990*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 19917e860f15SJohn Edward Broadbent 199225b54dbaSEd Tanous if constexpr (BMCWEB_VM_NBDPROXY) 199336c0f2a3SEd Tanous { 19941476687dSEd Tanous asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] = 1995*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia", 1996*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 199736c0f2a3SEd Tanous } 19987e860f15SJohn Edward Broadbent 19997e860f15SJohn Edward Broadbent // default oem data 20007e860f15SJohn Edward Broadbent nlohmann::json& oem = asyncResp->res.jsonValue["Oem"]; 20017e860f15SJohn Edward Broadbent nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 20027e860f15SJohn Edward Broadbent oem["@odata.type"] = "#OemManager.Oem"; 2003*253f11b8SEd Tanous oem["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}#/Oem", 2004*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 20057e860f15SJohn Edward Broadbent oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 2006*253f11b8SEd Tanous oemOpenbmc["@odata.id"] = 2007*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}#/Oem/OpenBmc", 2008*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 20091476687dSEd Tanous 20101476687dSEd Tanous nlohmann::json::object_t certificates; 2011*253f11b8SEd Tanous certificates["@odata.id"] = boost::urls::format( 2012*253f11b8SEd Tanous "/redfish/v1/Managers/{}/Truststore/Certificates", 2013*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 20141476687dSEd Tanous oemOpenbmc["Certificates"] = std::move(certificates); 20157e860f15SJohn Edward Broadbent 20167e860f15SJohn Edward Broadbent // Manager.Reset (an action) can be many values, OpenBMC only 20177e860f15SJohn Edward Broadbent // supports BMC reboot. 20187e860f15SJohn Edward Broadbent nlohmann::json& managerReset = 20197e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Actions"]["#Manager.Reset"]; 20207e860f15SJohn Edward Broadbent managerReset["target"] = 2021*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/Actions/Manager.Reset", 2022*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 20237e860f15SJohn Edward Broadbent managerReset["@Redfish.ActionInfo"] = 2024*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo", 2025*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 20267e860f15SJohn Edward Broadbent 20277e860f15SJohn Edward Broadbent // ResetToDefaults (Factory Reset) has values like 20287e860f15SJohn Edward Broadbent // PreserveNetworkAndUsers and PreserveNetwork that aren't supported 20297e860f15SJohn Edward Broadbent // on OpenBMC 20307e860f15SJohn Edward Broadbent nlohmann::json& resetToDefaults = 20317e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"]; 2032*253f11b8SEd Tanous resetToDefaults["target"] = boost::urls::format( 2033*253f11b8SEd Tanous "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults", 2034*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2035613dabeaSEd Tanous resetToDefaults["ResetType@Redfish.AllowableValues"] = 2036613dabeaSEd Tanous nlohmann::json::array_t({"ResetAll"}); 20377e860f15SJohn Edward Broadbent 20387c8c4058STejas Patil std::pair<std::string, std::string> redfishDateTimeOffset = 20392b82937eSEd Tanous redfish::time_utils::getDateTimeOffsetNow(); 20407c8c4058STejas Patil 20417c8c4058STejas Patil asyncResp->res.jsonValue["DateTime"] = redfishDateTimeOffset.first; 20427c8c4058STejas Patil asyncResp->res.jsonValue["DateTimeLocalOffset"] = 20437c8c4058STejas Patil redfishDateTimeOffset.second; 20447e860f15SJohn Edward Broadbent 20450e8ac5e7SGunnar Mills // TODO (Gunnar): Remove these one day since moved to ComputerSystem 20460e8ac5e7SGunnar Mills // Still used by OCP profiles 20470e8ac5e7SGunnar Mills // https://github.com/opencomputeproject/OCP-Profiles/issues/23 20487e860f15SJohn Edward Broadbent // Fill in SerialConsole info 20497e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["SerialConsole"]["ServiceEnabled"] = true; 2050002d39b4SEd Tanous asyncResp->res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 2051613dabeaSEd Tanous asyncResp->res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = 2052613dabeaSEd Tanous nlohmann::json::array_t({"IPMI", "SSH"}); 205325b54dbaSEd Tanous if constexpr (BMCWEB_KVM) 205425b54dbaSEd Tanous { 20557e860f15SJohn Edward Broadbent // Fill in GraphicalConsole info 205625b54dbaSEd Tanous asyncResp->res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = 205725b54dbaSEd Tanous true; 205825b54dbaSEd Tanous asyncResp->res 205925b54dbaSEd Tanous .jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; 206025b54dbaSEd Tanous asyncResp->res 206125b54dbaSEd Tanous .jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = 2062613dabeaSEd Tanous nlohmann::json::array_t({"KVMIP"}); 206325b54dbaSEd Tanous } 206425b54dbaSEd Tanous if constexpr (!BMCWEB_EXPERIMENTAL_REDFISH_MULTI_COMPUTER_SYSTEM) 20657f3e84a1SEd Tanous { 20667f3e84a1SEd Tanous asyncResp->res.jsonValue["Links"]["ManagerForServers@odata.count"] = 20677f3e84a1SEd Tanous 1; 20681476687dSEd Tanous 20691476687dSEd Tanous nlohmann::json::array_t managerForServers; 20701476687dSEd Tanous nlohmann::json::object_t manager; 2071*253f11b8SEd Tanous manager["@odata.id"] = std::format("/redfish/v1/Systems/{}", 2072*253f11b8SEd Tanous BMCWEB_REDFISH_SYSTEM_URI_NAME); 2073ad539545SPatrick Williams managerForServers.emplace_back(std::move(manager)); 20741476687dSEd Tanous 20751476687dSEd Tanous asyncResp->res.jsonValue["Links"]["ManagerForServers"] = 20761476687dSEd Tanous std::move(managerForServers); 20777f3e84a1SEd Tanous } 20787e860f15SJohn Edward Broadbent 2079eee0013eSWilly Tu sw_util::populateSoftwareInformation(asyncResp, sw_util::bmcPurpose, 20807e860f15SJohn Edward Broadbent "FirmwareVersion", true); 20817e860f15SJohn Edward Broadbent 20827e860f15SJohn Edward Broadbent managerGetLastResetTime(asyncResp); 20837e860f15SJohn Edward Broadbent 2084a51fc2d2SSui Chen // ManagerDiagnosticData is added for all BMCs. 2085a51fc2d2SSui Chen nlohmann::json& managerDiagnosticData = 2086a51fc2d2SSui Chen asyncResp->res.jsonValue["ManagerDiagnosticData"]; 2087a51fc2d2SSui Chen managerDiagnosticData["@odata.id"] = 2088*253f11b8SEd Tanous boost::urls::format("/redfish/v1/Managers/{}/ManagerDiagnosticData", 2089*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 2090a51fc2d2SSui Chen 209125b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA) 209225b54dbaSEd Tanous { 20937e860f15SJohn Edward Broadbent auto pids = std::make_shared<GetPIDValues>(asyncResp); 20947e860f15SJohn Edward Broadbent pids->run(); 209525b54dbaSEd Tanous } 20967e860f15SJohn Edward Broadbent 2097002d39b4SEd Tanous getMainChassisId(asyncResp, 2098002d39b4SEd Tanous [](const std::string& chassisId, 2099002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& aRsp) { 2100002d39b4SEd Tanous aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] = 1; 21011476687dSEd Tanous nlohmann::json::array_t managerForChassis; 21028a592810SEd Tanous nlohmann::json::object_t managerObj; 2103ef4c65b7SEd Tanous boost::urls::url chassiUrl = 2104ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/Chassis/{}", chassisId); 2105eddfc437SWilly Tu managerObj["@odata.id"] = chassiUrl; 2106ad539545SPatrick Williams managerForChassis.emplace_back(std::move(managerObj)); 21071476687dSEd Tanous aRsp->res.jsonValue["Links"]["ManagerForChassis"] = 21081476687dSEd Tanous std::move(managerForChassis); 21091476687dSEd Tanous aRsp->res.jsonValue["Links"]["ManagerInChassis"]["@odata.id"] = 2110eddfc437SWilly Tu chassiUrl; 21117e860f15SJohn Edward Broadbent }); 21127e860f15SJohn Edward Broadbent 21131e1e598dSJonathan Doman sdbusplus::asio::getProperty<double>( 21141e1e598dSJonathan Doman *crow::connections::systemBus, "org.freedesktop.systemd1", 2115002d39b4SEd Tanous "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", 2116002d39b4SEd Tanous "Progress", 211775815e5cSEd Tanous [asyncResp](const boost::system::error_code& ec, double val) { 21187e860f15SJohn Edward Broadbent if (ec) 21191abe55efSEd Tanous { 212062598e31SEd Tanous BMCWEB_LOG_ERROR("Error while getting progress"); 21217e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 21227e860f15SJohn Edward Broadbent return; 21237e860f15SJohn Edward Broadbent } 21241e1e598dSJonathan Doman if (val < 1.0) 21257e860f15SJohn Edward Broadbent { 212675815e5cSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 2127002d39b4SEd Tanous asyncResp->res.jsonValue["Status"]["State"] = "Starting"; 212875815e5cSEd Tanous return; 21297e860f15SJohn Edward Broadbent } 213075815e5cSEd Tanous checkForQuiesced(asyncResp); 21311e1e598dSJonathan Doman }); 21329c310685SBorawski.Lukasz 2133e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 2134e99073f5SGeorge Liu "xyz.openbmc_project.Inventory.Item.Bmc"}; 2135e99073f5SGeorge Liu dbus::utility::getSubTree( 2136e99073f5SGeorge Liu "/xyz/openbmc_project/inventory", 0, interfaces, 21377e860f15SJohn Edward Broadbent [asyncResp]( 2138e99073f5SGeorge Liu const boost::system::error_code& ec, 2139b9d36b47SEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 21407e860f15SJohn Edward Broadbent if (ec) 21411abe55efSEd Tanous { 214262598e31SEd Tanous BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); 21437e860f15SJohn Edward Broadbent return; 21447e860f15SJohn Edward Broadbent } 214526f6976fSEd Tanous if (subtree.empty()) 21467e860f15SJohn Edward Broadbent { 214762598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!"); 21487e860f15SJohn Edward Broadbent return; 21497e860f15SJohn Edward Broadbent } 21507e860f15SJohn Edward Broadbent // Assume only 1 bmc D-Bus object 21517e860f15SJohn Edward Broadbent // Throw an error if there is more than 1 21527e860f15SJohn Edward Broadbent if (subtree.size() > 1) 21537e860f15SJohn Edward Broadbent { 215462598e31SEd Tanous BMCWEB_LOG_DEBUG("Found more than 1 bmc D-Bus object!"); 21557e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 21567e860f15SJohn Edward Broadbent return; 21577e860f15SJohn Edward Broadbent } 21587e860f15SJohn Edward Broadbent 2159002d39b4SEd Tanous if (subtree[0].first.empty() || subtree[0].second.size() != 1) 21607e860f15SJohn Edward Broadbent { 216162598e31SEd Tanous BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!"); 21627e860f15SJohn Edward Broadbent messages::internalError(asyncResp->res); 21637e860f15SJohn Edward Broadbent return; 21647e860f15SJohn Edward Broadbent } 21657e860f15SJohn Edward Broadbent 21667e860f15SJohn Edward Broadbent const std::string& path = subtree[0].first; 2167002d39b4SEd Tanous const std::string& connectionName = subtree[0].second[0].first; 21687e860f15SJohn Edward Broadbent 2169002d39b4SEd Tanous for (const auto& interfaceName : subtree[0].second[0].second) 21707e860f15SJohn Edward Broadbent { 21717e860f15SJohn Edward Broadbent if (interfaceName == 21727e860f15SJohn Edward Broadbent "xyz.openbmc_project.Inventory.Decorator.Asset") 21737e860f15SJohn Edward Broadbent { 2174fac6e53bSKrzysztof Grobelny sdbusplus::asio::getAllProperties( 2175fac6e53bSKrzysztof Grobelny *crow::connections::systemBus, connectionName, path, 2176fac6e53bSKrzysztof Grobelny "xyz.openbmc_project.Inventory.Decorator.Asset", 21775e7e2dc5SEd Tanous [asyncResp](const boost::system::error_code& ec2, 2178b9d36b47SEd Tanous const dbus::utility::DBusPropertiesMap& 21797e860f15SJohn Edward Broadbent propertiesList) { 21808a592810SEd Tanous if (ec2) 21817e860f15SJohn Edward Broadbent { 218262598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't get bmc asset!"); 21837e860f15SJohn Edward Broadbent return; 21847e860f15SJohn Edward Broadbent } 21857e860f15SJohn Edward Broadbent 2186fac6e53bSKrzysztof Grobelny const std::string* partNumber = nullptr; 2187fac6e53bSKrzysztof Grobelny const std::string* serialNumber = nullptr; 2188fac6e53bSKrzysztof Grobelny const std::string* manufacturer = nullptr; 2189fac6e53bSKrzysztof Grobelny const std::string* model = nullptr; 2190fac6e53bSKrzysztof Grobelny const std::string* sparePartNumber = nullptr; 2191fac6e53bSKrzysztof Grobelny 2192fac6e53bSKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 2193fac6e53bSKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 2194fac6e53bSKrzysztof Grobelny "PartNumber", partNumber, "SerialNumber", 2195fac6e53bSKrzysztof Grobelny serialNumber, "Manufacturer", manufacturer, "Model", 2196fac6e53bSKrzysztof Grobelny model, "SparePartNumber", sparePartNumber); 2197fac6e53bSKrzysztof Grobelny 2198fac6e53bSKrzysztof Grobelny if (!success) 21997e860f15SJohn Edward Broadbent { 2200002d39b4SEd Tanous messages::internalError(asyncResp->res); 22017e860f15SJohn Edward Broadbent return; 22027e860f15SJohn Edward Broadbent } 2203fac6e53bSKrzysztof Grobelny 2204fac6e53bSKrzysztof Grobelny if (partNumber != nullptr) 2205fac6e53bSKrzysztof Grobelny { 2206fac6e53bSKrzysztof Grobelny asyncResp->res.jsonValue["PartNumber"] = 2207fac6e53bSKrzysztof Grobelny *partNumber; 22087e860f15SJohn Edward Broadbent } 2209fac6e53bSKrzysztof Grobelny 2210fac6e53bSKrzysztof Grobelny if (serialNumber != nullptr) 2211fac6e53bSKrzysztof Grobelny { 2212fac6e53bSKrzysztof Grobelny asyncResp->res.jsonValue["SerialNumber"] = 2213fac6e53bSKrzysztof Grobelny *serialNumber; 22147e860f15SJohn Edward Broadbent } 2215fac6e53bSKrzysztof Grobelny 2216fac6e53bSKrzysztof Grobelny if (manufacturer != nullptr) 2217fac6e53bSKrzysztof Grobelny { 2218fac6e53bSKrzysztof Grobelny asyncResp->res.jsonValue["Manufacturer"] = 2219fac6e53bSKrzysztof Grobelny *manufacturer; 2220fac6e53bSKrzysztof Grobelny } 2221fac6e53bSKrzysztof Grobelny 2222fac6e53bSKrzysztof Grobelny if (model != nullptr) 2223fac6e53bSKrzysztof Grobelny { 2224fac6e53bSKrzysztof Grobelny asyncResp->res.jsonValue["Model"] = *model; 2225fac6e53bSKrzysztof Grobelny } 2226fac6e53bSKrzysztof Grobelny 2227fac6e53bSKrzysztof Grobelny if (sparePartNumber != nullptr) 2228fac6e53bSKrzysztof Grobelny { 2229fac6e53bSKrzysztof Grobelny asyncResp->res.jsonValue["SparePartNumber"] = 2230fac6e53bSKrzysztof Grobelny *sparePartNumber; 2231fac6e53bSKrzysztof Grobelny } 2232fac6e53bSKrzysztof Grobelny }); 22337e860f15SJohn Edward Broadbent } 2234002d39b4SEd Tanous else if (interfaceName == 22350fda0f12SGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode") 22367e860f15SJohn Edward Broadbent { 22377e860f15SJohn Edward Broadbent getLocation(asyncResp, connectionName, path); 22387e860f15SJohn Edward Broadbent } 22397e860f15SJohn Edward Broadbent } 2240e99073f5SGeorge Liu }); 22417e860f15SJohn Edward Broadbent }); 22427e860f15SJohn Edward Broadbent 2243*253f11b8SEd Tanous BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/") 2244ed398213SEd Tanous .privileges(redfish::privileges::patchManager) 224545ca1b86SEd Tanous .methods(boost::beast::http::verb::patch)( 224645ca1b86SEd Tanous [&app](const crow::Request& req, 2247*253f11b8SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2248*253f11b8SEd Tanous const std::string& managerId) { 22493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 225045ca1b86SEd Tanous { 225145ca1b86SEd Tanous return; 225245ca1b86SEd Tanous } 2253*253f11b8SEd Tanous 2254*253f11b8SEd Tanous if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) 2255*253f11b8SEd Tanous { 2256*253f11b8SEd Tanous messages::resourceNotFound(asyncResp->res, "Manager", managerId); 2257*253f11b8SEd Tanous return; 2258*253f11b8SEd Tanous } 2259*253f11b8SEd Tanous 22609e9b6049SEd Tanous std::optional<std::string> activeSoftwareImageOdataId; 22617e860f15SJohn Edward Broadbent std::optional<std::string> datetime; 22629e9b6049SEd Tanous std::optional<nlohmann::json::object_t> pidControllers; 22639e9b6049SEd Tanous std::optional<nlohmann::json::object_t> fanControllers; 22649e9b6049SEd Tanous std::optional<nlohmann::json::object_t> fanZones; 22659e9b6049SEd Tanous std::optional<nlohmann::json::object_t> stepwiseControllers; 22669e9b6049SEd Tanous std::optional<std::string> profile; 22677e860f15SJohn Edward Broadbent 22689e9b6049SEd Tanous // clang-format off 22699e9b6049SEd Tanous if (!json_util::readJsonPatch(req, asyncResp->res, 22709e9b6049SEd Tanous "DateTime", datetime, 22719e9b6049SEd Tanous "Links/ActiveSoftwareImage/@odata.id", activeSoftwareImageOdataId, 22729e9b6049SEd Tanous "Oem/OpenBmc/Fan/FanControllers", fanControllers, 22739e9b6049SEd Tanous "Oem/OpenBmc/Fan/FanZones", fanZones, 22749e9b6049SEd Tanous "Oem/OpenBmc/Fan/PidControllers", pidControllers, 22759e9b6049SEd Tanous "Oem/OpenBmc/Fan/Profile", profile, 22769e9b6049SEd Tanous "Oem/OpenBmc/Fan/StepwiseControllers", stepwiseControllers 22779e9b6049SEd Tanous )) 22787e860f15SJohn Edward Broadbent { 22797e860f15SJohn Edward Broadbent return; 22807e860f15SJohn Edward Broadbent } 22819e9b6049SEd Tanous // clang-format on 22827e860f15SJohn Edward Broadbent 22839e9b6049SEd Tanous if (pidControllers || fanControllers || fanZones || 22849e9b6049SEd Tanous stepwiseControllers || profile) 22857e860f15SJohn Edward Broadbent { 228625b54dbaSEd Tanous if constexpr (BMCWEB_REDFISH_OEM_MANAGER_FAN_DATA) 228725b54dbaSEd Tanous { 228825b54dbaSEd Tanous std::vector<std::pair<std::string, 228925b54dbaSEd Tanous std::optional<nlohmann::json::object_t>>> 22909e9b6049SEd Tanous configuration; 22919e9b6049SEd Tanous if (pidControllers) 22927e860f15SJohn Edward Broadbent { 22939e9b6049SEd Tanous configuration.emplace_back("PidControllers", 22949e9b6049SEd Tanous std::move(pidControllers)); 22957e860f15SJohn Edward Broadbent } 22969e9b6049SEd Tanous if (fanControllers) 22977e860f15SJohn Edward Broadbent { 22989e9b6049SEd Tanous configuration.emplace_back("FanControllers", 22999e9b6049SEd Tanous std::move(fanControllers)); 23007e860f15SJohn Edward Broadbent } 23019e9b6049SEd Tanous if (fanZones) 23027e860f15SJohn Edward Broadbent { 23039e9b6049SEd Tanous configuration.emplace_back("FanZones", std::move(fanZones)); 23049e9b6049SEd Tanous } 23059e9b6049SEd Tanous if (stepwiseControllers) 23069e9b6049SEd Tanous { 23079e9b6049SEd Tanous configuration.emplace_back("StepwiseControllers", 23089e9b6049SEd Tanous std::move(stepwiseControllers)); 23099e9b6049SEd Tanous } 23109e9b6049SEd Tanous auto pid = std::make_shared<SetPIDValues>( 23119e9b6049SEd Tanous asyncResp, std::move(configuration), profile); 23127e860f15SJohn Edward Broadbent pid->run(); 231325b54dbaSEd Tanous } 231425b54dbaSEd Tanous else 231525b54dbaSEd Tanous { 231654dce7f5SGunnar Mills messages::propertyUnknown(asyncResp->res, "Oem"); 231754dce7f5SGunnar Mills return; 231825b54dbaSEd Tanous } 23197e860f15SJohn Edward Broadbent } 23209e9b6049SEd Tanous 23219e9b6049SEd Tanous if (activeSoftwareImageOdataId) 23227e860f15SJohn Edward Broadbent { 23239e9b6049SEd Tanous setActiveFirmwareImage(asyncResp, *activeSoftwareImageOdataId); 23247e860f15SJohn Edward Broadbent } 23257e860f15SJohn Edward Broadbent 23267e860f15SJohn Edward Broadbent if (datetime) 23277e860f15SJohn Edward Broadbent { 2328c51afd54SEd Tanous setDateTime(asyncResp, *datetime); 23297e860f15SJohn Edward Broadbent } 23307e860f15SJohn Edward Broadbent }); 23317e860f15SJohn Edward Broadbent } 23327e860f15SJohn Edward Broadbent 23337e860f15SJohn Edward Broadbent inline void requestRoutesManagerCollection(App& app) 23347e860f15SJohn Edward Broadbent { 23357e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/Managers/") 2336ed398213SEd Tanous .privileges(redfish::privileges::getManagerCollection) 23377e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 233845ca1b86SEd Tanous [&app](const crow::Request& req, 23397e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 23403ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 234145ca1b86SEd Tanous { 234245ca1b86SEd Tanous return; 234345ca1b86SEd Tanous } 234483ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 234583ff9ab6SJames Feist // because it has a duplicate entry for members 23468d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 23478d1b46d7Szhanghch05 asyncResp->res.jsonValue["@odata.type"] = 23488d1b46d7Szhanghch05 "#ManagerCollection.ManagerCollection"; 23498d1b46d7Szhanghch05 asyncResp->res.jsonValue["Name"] = "Manager Collection"; 23508d1b46d7Szhanghch05 asyncResp->res.jsonValue["Members@odata.count"] = 1; 23511476687dSEd Tanous nlohmann::json::array_t members; 23521476687dSEd Tanous nlohmann::json& bmc = members.emplace_back(); 2353*253f11b8SEd Tanous bmc["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}", 2354*253f11b8SEd Tanous BMCWEB_REDFISH_MANAGER_URI_NAME); 23551476687dSEd Tanous asyncResp->res.jsonValue["Members"] = std::move(members); 23567e860f15SJohn Edward Broadbent }); 23579c310685SBorawski.Lukasz } 23589c310685SBorawski.Lukasz } // namespace redfish 2359