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 18b49ac873SJames Feist #include "health.hpp" 199c310685SBorawski.Lukasz #include "node.hpp" 20c5d03ff4SJennifer Lee #include "redfish_util.hpp" 219c310685SBorawski.Lukasz 225b4aa86bSJames Feist #include <boost/algorithm/string/replace.hpp> 23af5d6058SSantosh Puranik #include <boost/date_time.hpp> 245b4aa86bSJames Feist #include <dbus_utility.hpp> 25e90c5052SAndrew Geissler #include <utils/fw_utils.hpp> 267bffdb7eSBernard Wong #include <utils/systemd_utils.hpp> 271214b7e7SGunnar Mills 281214b7e7SGunnar Mills #include <memory> 291214b7e7SGunnar Mills #include <sstream> 30abf2add6SEd Tanous #include <variant> 315b4aa86bSJames Feist 321abe55efSEd Tanous namespace redfish 331abe55efSEd Tanous { 34ed5befbdSJennifer Lee 35ed5befbdSJennifer Lee /** 362a5c4407SGunnar Mills * Function reboots the BMC. 372a5c4407SGunnar Mills * 382a5c4407SGunnar Mills * @param[in] asyncResp - Shared pointer for completing asynchronous calls 39ed5befbdSJennifer Lee */ 402a5c4407SGunnar Mills void doBMCGracefulRestart(std::shared_ptr<AsyncResp> asyncResp) 41ed5befbdSJennifer Lee { 42ed5befbdSJennifer Lee const char* processName = "xyz.openbmc_project.State.BMC"; 43ed5befbdSJennifer Lee const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 44ed5befbdSJennifer Lee const char* interfaceName = "xyz.openbmc_project.State.BMC"; 45ed5befbdSJennifer Lee const std::string& propertyValue = 46ed5befbdSJennifer Lee "xyz.openbmc_project.State.BMC.Transition.Reboot"; 47ed5befbdSJennifer Lee const char* destProperty = "RequestedBMCTransition"; 48ed5befbdSJennifer Lee 49ed5befbdSJennifer Lee // Create the D-Bus variant for D-Bus call. 50ed5befbdSJennifer Lee VariantType dbusPropertyValue(propertyValue); 51ed5befbdSJennifer Lee 52ed5befbdSJennifer Lee crow::connections::systemBus->async_method_call( 53ed5befbdSJennifer Lee [asyncResp](const boost::system::error_code ec) { 54ed5befbdSJennifer Lee // Use "Set" method to set the property value. 55ed5befbdSJennifer Lee if (ec) 56ed5befbdSJennifer Lee { 572a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec; 58ed5befbdSJennifer Lee messages::internalError(asyncResp->res); 59ed5befbdSJennifer Lee return; 60ed5befbdSJennifer Lee } 61ed5befbdSJennifer Lee 62ed5befbdSJennifer Lee messages::success(asyncResp->res); 63ed5befbdSJennifer Lee }, 64ed5befbdSJennifer Lee processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 65ed5befbdSJennifer Lee interfaceName, destProperty, dbusPropertyValue); 66ed5befbdSJennifer Lee } 672a5c4407SGunnar Mills 682a5c4407SGunnar Mills /** 692a5c4407SGunnar Mills * ManagerResetAction class supports the POST method for the Reset (reboot) 702a5c4407SGunnar Mills * action. 712a5c4407SGunnar Mills */ 722a5c4407SGunnar Mills class ManagerResetAction : public Node 732a5c4407SGunnar Mills { 742a5c4407SGunnar Mills public: 752a5c4407SGunnar Mills ManagerResetAction(CrowApp& app) : 762a5c4407SGunnar Mills Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/") 772a5c4407SGunnar Mills { 782a5c4407SGunnar Mills entityPrivileges = { 792a5c4407SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 802a5c4407SGunnar Mills } 812a5c4407SGunnar Mills 822a5c4407SGunnar Mills private: 832a5c4407SGunnar Mills /** 842a5c4407SGunnar Mills * Function handles POST method request. 852a5c4407SGunnar Mills * Analyzes POST body before sending Reset (Reboot) request data to D-Bus. 862a5c4407SGunnar Mills * OpenBMC only supports ResetType "GracefulRestart". 872a5c4407SGunnar Mills */ 882a5c4407SGunnar Mills void doPost(crow::Response& res, const crow::Request& req, 892a5c4407SGunnar Mills const std::vector<std::string>& params) override 902a5c4407SGunnar Mills { 912a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Post Manager Reset."; 922a5c4407SGunnar Mills 932a5c4407SGunnar Mills std::string resetType; 942a5c4407SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 952a5c4407SGunnar Mills 962a5c4407SGunnar Mills if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 972a5c4407SGunnar Mills { 982a5c4407SGunnar Mills return; 992a5c4407SGunnar Mills } 1002a5c4407SGunnar Mills 1012a5c4407SGunnar Mills if (resetType != "GracefulRestart") 1022a5c4407SGunnar Mills { 1032a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 1042a5c4407SGunnar Mills << resetType; 1052a5c4407SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 1062a5c4407SGunnar Mills "ResetType"); 1072a5c4407SGunnar Mills 1082a5c4407SGunnar Mills return; 1092a5c4407SGunnar Mills } 1102a5c4407SGunnar Mills doBMCGracefulRestart(asyncResp); 1112a5c4407SGunnar Mills } 112ed5befbdSJennifer Lee }; 113ed5befbdSJennifer Lee 1143e40fc74SGunnar Mills /** 1153e40fc74SGunnar Mills * ManagerResetToDefaultsAction class supports POST method for factory reset 1163e40fc74SGunnar Mills * action. 1173e40fc74SGunnar Mills */ 1183e40fc74SGunnar Mills class ManagerResetToDefaultsAction : public Node 1193e40fc74SGunnar Mills { 1203e40fc74SGunnar Mills public: 1213e40fc74SGunnar Mills ManagerResetToDefaultsAction(CrowApp& app) : 1223e40fc74SGunnar Mills Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults/") 1233e40fc74SGunnar Mills { 1243e40fc74SGunnar Mills entityPrivileges = { 1253e40fc74SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 1263e40fc74SGunnar Mills } 1273e40fc74SGunnar Mills 1283e40fc74SGunnar Mills private: 1293e40fc74SGunnar Mills /** 1303e40fc74SGunnar Mills * Function handles ResetToDefaults POST method request. 1313e40fc74SGunnar Mills * 1323e40fc74SGunnar Mills * Analyzes POST body message and factory resets BMC by calling 1333e40fc74SGunnar Mills * BMC code updater factory reset followed by a BMC reboot. 1343e40fc74SGunnar Mills * 1353e40fc74SGunnar Mills * BMC code updater factory reset wipes the whole BMC read-write 1363e40fc74SGunnar Mills * filesystem which includes things like the network settings. 1373e40fc74SGunnar Mills * 1383e40fc74SGunnar Mills * OpenBMC only supports ResetToDefaultsType "ResetAll". 1393e40fc74SGunnar Mills */ 1403e40fc74SGunnar Mills void doPost(crow::Response& res, const crow::Request& req, 1413e40fc74SGunnar Mills const std::vector<std::string>& params) override 1423e40fc74SGunnar Mills { 1433e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Post ResetToDefaults."; 1443e40fc74SGunnar Mills 1453e40fc74SGunnar Mills std::string resetType; 1463e40fc74SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 1473e40fc74SGunnar Mills 1483e40fc74SGunnar Mills if (!json_util::readJson(req, asyncResp->res, "ResetToDefaultsType", 1493e40fc74SGunnar Mills resetType)) 1503e40fc74SGunnar Mills { 1513e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Missing property ResetToDefaultsType."; 1523e40fc74SGunnar Mills 1533e40fc74SGunnar Mills messages::actionParameterMissing(asyncResp->res, "ResetToDefaults", 1543e40fc74SGunnar Mills "ResetToDefaultsType"); 1553e40fc74SGunnar Mills return; 1563e40fc74SGunnar Mills } 1573e40fc74SGunnar Mills 1583e40fc74SGunnar Mills if (resetType != "ResetAll") 1593e40fc74SGunnar Mills { 1603e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid property value for " 1613e40fc74SGunnar Mills "ResetToDefaultsType: " 1623e40fc74SGunnar Mills << resetType; 1633e40fc74SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 1643e40fc74SGunnar Mills "ResetToDefaultsType"); 1653e40fc74SGunnar Mills return; 1663e40fc74SGunnar Mills } 1673e40fc74SGunnar Mills 1683e40fc74SGunnar Mills crow::connections::systemBus->async_method_call( 1693e40fc74SGunnar Mills [asyncResp](const boost::system::error_code ec) { 1703e40fc74SGunnar Mills if (ec) 1713e40fc74SGunnar Mills { 1723e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Failed to ResetToDefaults: " << ec; 1733e40fc74SGunnar Mills messages::internalError(asyncResp->res); 1743e40fc74SGunnar Mills return; 1753e40fc74SGunnar Mills } 1763e40fc74SGunnar Mills // Factory Reset doesn't actually happen until a reboot 1773e40fc74SGunnar Mills // Can't erase what the BMC is running on 1783e40fc74SGunnar Mills doBMCGracefulRestart(asyncResp); 1793e40fc74SGunnar Mills }, 1803e40fc74SGunnar Mills "xyz.openbmc_project.Software.BMC.Updater", 1813e40fc74SGunnar Mills "/xyz/openbmc_project/software", 1823e40fc74SGunnar Mills "xyz.openbmc_project.Common.FactoryReset", "Reset"); 1833e40fc74SGunnar Mills } 1843e40fc74SGunnar Mills }; 1853e40fc74SGunnar Mills 1861cb1a9e6SAppaRao Puli /** 1871cb1a9e6SAppaRao Puli * ManagerResetActionInfo derived class for delivering Manager 1881cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 1891cb1a9e6SAppaRao Puli */ 1901cb1a9e6SAppaRao Puli class ManagerResetActionInfo : public Node 1911cb1a9e6SAppaRao Puli { 1921cb1a9e6SAppaRao Puli public: 1931cb1a9e6SAppaRao Puli /* 1941cb1a9e6SAppaRao Puli * Default Constructor 1951cb1a9e6SAppaRao Puli */ 1961cb1a9e6SAppaRao Puli ManagerResetActionInfo(CrowApp& app) : 1971cb1a9e6SAppaRao Puli Node(app, "/redfish/v1/Managers/bmc/ResetActionInfo/") 1981cb1a9e6SAppaRao Puli { 1991cb1a9e6SAppaRao Puli entityPrivileges = { 2001cb1a9e6SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 2011cb1a9e6SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 2021cb1a9e6SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2031cb1a9e6SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2041cb1a9e6SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2051cb1a9e6SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2061cb1a9e6SAppaRao Puli } 2071cb1a9e6SAppaRao Puli 2081cb1a9e6SAppaRao Puli private: 2091cb1a9e6SAppaRao Puli /** 2101cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 2111cb1a9e6SAppaRao Puli */ 2121cb1a9e6SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 2131cb1a9e6SAppaRao Puli const std::vector<std::string>& params) override 2141cb1a9e6SAppaRao Puli { 2151cb1a9e6SAppaRao Puli res.jsonValue = { 2161cb1a9e6SAppaRao Puli {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2171cb1a9e6SAppaRao Puli {"@odata.id", "/redfish/v1/Managers/bmc/ResetActionInfo"}, 2181cb1a9e6SAppaRao Puli {"Name", "Reset Action Info"}, 2191cb1a9e6SAppaRao Puli {"Id", "ResetActionInfo"}, 2201cb1a9e6SAppaRao Puli {"Parameters", 2211cb1a9e6SAppaRao Puli {{{"Name", "ResetType"}, 2221cb1a9e6SAppaRao Puli {"Required", true}, 2231cb1a9e6SAppaRao Puli {"DataType", "String"}, 2241cb1a9e6SAppaRao Puli {"AllowableValues", {"GracefulRestart"}}}}}}; 2251cb1a9e6SAppaRao Puli res.end(); 2261cb1a9e6SAppaRao Puli } 2271cb1a9e6SAppaRao Puli }; 2281cb1a9e6SAppaRao Puli 2295b4aa86bSJames Feist static constexpr const char* objectManagerIface = 2305b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 2315b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 2325b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 2335b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 2345b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 235b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface = 236b7a08d04SJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 23773df0db0SJames Feist static constexpr const char* thermalModeIface = 23873df0db0SJames Feist "xyz.openbmc_project.Control.ThermalMode"; 2399c310685SBorawski.Lukasz 2405b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection, 2415b4aa86bSJames Feist const std::string& path, 24273df0db0SJames Feist const std::string& currentProfile, 24373df0db0SJames Feist const std::vector<std::string>& supportedProfiles, 2445b4aa86bSJames Feist std::shared_ptr<AsyncResp> asyncResp) 2455b4aa86bSJames Feist { 2465b4aa86bSJames Feist 2475b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 24873df0db0SJames Feist [asyncResp, currentProfile, supportedProfiles]( 24973df0db0SJames Feist const boost::system::error_code ec, 2505b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 2515b4aa86bSJames Feist if (ec) 2525b4aa86bSJames Feist { 2535b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 2545b4aa86bSJames Feist asyncResp->res.jsonValue.clear(); 255f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2565b4aa86bSJames Feist return; 2575b4aa86bSJames Feist } 2585b4aa86bSJames Feist nlohmann::json& configRoot = 2595b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 2605b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 2615b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 2625b4aa86bSJames Feist fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" 2635b4aa86bSJames Feist "Fan/FanControllers"; 2645b4aa86bSJames Feist 2655b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 2665b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 2675b4aa86bSJames Feist pids["@odata.id"] = 2685b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; 2695b4aa86bSJames Feist 270b7a08d04SJames Feist nlohmann::json& stepwise = configRoot["StepwiseControllers"]; 271b7a08d04SJames Feist stepwise["@odata.type"] = "#OemManager.StepwiseControllers"; 272b7a08d04SJames Feist stepwise["@odata.id"] = 273b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers"; 274b7a08d04SJames Feist 2755b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 2765b4aa86bSJames Feist zones["@odata.id"] = 2775b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; 2785b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 2795b4aa86bSJames Feist configRoot["@odata.id"] = 2805b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; 2815b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 28273df0db0SJames Feist configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles; 28373df0db0SJames Feist 28473df0db0SJames Feist if (!currentProfile.empty()) 28573df0db0SJames Feist { 28673df0db0SJames Feist configRoot["Profile"] = currentProfile; 28773df0db0SJames Feist } 28873df0db0SJames Feist BMCWEB_LOG_ERROR << "profile = " << currentProfile << " !"; 2895b4aa86bSJames Feist 2905b4aa86bSJames Feist for (const auto& pathPair : managedObj) 2915b4aa86bSJames Feist { 2925b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 2935b4aa86bSJames Feist { 2945b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 295b7a08d04SJames Feist intfPair.first != pidZoneConfigurationIface && 296b7a08d04SJames Feist intfPair.first != stepwiseConfigurationIface) 2975b4aa86bSJames Feist { 2985b4aa86bSJames Feist continue; 2995b4aa86bSJames Feist } 3005b4aa86bSJames Feist auto findName = intfPair.second.find("Name"); 3015b4aa86bSJames Feist if (findName == intfPair.second.end()) 3025b4aa86bSJames Feist { 3035b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Field missing Name"; 304a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 3055b4aa86bSJames Feist return; 3065b4aa86bSJames Feist } 30773df0db0SJames Feist 3085b4aa86bSJames Feist const std::string* namePtr = 309abf2add6SEd Tanous std::get_if<std::string>(&findName->second); 3105b4aa86bSJames Feist if (namePtr == nullptr) 3115b4aa86bSJames Feist { 3125b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Name Field illegal"; 313b7a08d04SJames Feist messages::internalError(asyncResp->res); 3145b4aa86bSJames Feist return; 3155b4aa86bSJames Feist } 3165b4aa86bSJames Feist std::string name = *namePtr; 3175b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 31873df0db0SJames Feist 31973df0db0SJames Feist auto findProfiles = intfPair.second.find("Profiles"); 32073df0db0SJames Feist if (findProfiles != intfPair.second.end()) 32173df0db0SJames Feist { 32273df0db0SJames Feist const std::vector<std::string>* profiles = 32373df0db0SJames Feist std::get_if<std::vector<std::string>>( 32473df0db0SJames Feist &findProfiles->second); 32573df0db0SJames Feist if (profiles == nullptr) 32673df0db0SJames Feist { 32773df0db0SJames Feist BMCWEB_LOG_ERROR << "Pid Profiles Field illegal"; 32873df0db0SJames Feist messages::internalError(asyncResp->res); 32973df0db0SJames Feist return; 33073df0db0SJames Feist } 33173df0db0SJames Feist if (std::find(profiles->begin(), profiles->end(), 33273df0db0SJames Feist currentProfile) == profiles->end()) 33373df0db0SJames Feist { 33473df0db0SJames Feist BMCWEB_LOG_INFO 33573df0db0SJames Feist << name << " not supported in current profile"; 33673df0db0SJames Feist continue; 33773df0db0SJames Feist } 33873df0db0SJames Feist } 339b7a08d04SJames Feist nlohmann::json* config = nullptr; 340c33a90ecSJames Feist 341c33a90ecSJames Feist const std::string* classPtr = nullptr; 342c33a90ecSJames Feist auto findClass = intfPair.second.find("Class"); 343c33a90ecSJames Feist if (findClass != intfPair.second.end()) 344c33a90ecSJames Feist { 345c33a90ecSJames Feist classPtr = std::get_if<std::string>(&findClass->second); 346c33a90ecSJames Feist } 347c33a90ecSJames Feist 3485b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 3495b4aa86bSJames Feist { 3505b4aa86bSJames Feist std::string chassis; 3515b4aa86bSJames Feist if (!dbus::utility::getNthStringFromPath( 3525b4aa86bSJames Feist pathPair.first.str, 5, chassis)) 3535b4aa86bSJames Feist { 3545b4aa86bSJames Feist chassis = "#IllegalValue"; 3555b4aa86bSJames Feist } 3565b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 3575b4aa86bSJames Feist zone["Chassis"] = { 3585b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; 3595b4aa86bSJames Feist zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" 3605b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 3615b4aa86bSJames Feist name; 3625b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 363b7a08d04SJames Feist config = &zone; 3645b4aa86bSJames Feist } 3655b4aa86bSJames Feist 366b7a08d04SJames Feist else if (intfPair.first == stepwiseConfigurationIface) 3675b4aa86bSJames Feist { 368c33a90ecSJames Feist if (classPtr == nullptr) 369c33a90ecSJames Feist { 370c33a90ecSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 371c33a90ecSJames Feist messages::internalError(asyncResp->res); 372c33a90ecSJames Feist return; 373c33a90ecSJames Feist } 374c33a90ecSJames Feist 375b7a08d04SJames Feist nlohmann::json& controller = stepwise[name]; 376b7a08d04SJames Feist config = &controller; 3775b4aa86bSJames Feist 378b7a08d04SJames Feist controller["@odata.id"] = 379b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/" 380b7a08d04SJames Feist "OpenBmc/Fan/StepwiseControllers/" + 381271584abSEd Tanous name; 382b7a08d04SJames Feist controller["@odata.type"] = 383b7a08d04SJames Feist "#OemManager.StepwiseController"; 384b7a08d04SJames Feist 385c33a90ecSJames Feist controller["Direction"] = *classPtr; 3865b4aa86bSJames Feist } 3875b4aa86bSJames Feist 3885b4aa86bSJames Feist // pid and fans are off the same configuration 389b7a08d04SJames Feist else if (intfPair.first == pidConfigurationIface) 3905b4aa86bSJames Feist { 391c33a90ecSJames Feist 3925b4aa86bSJames Feist if (classPtr == nullptr) 3935b4aa86bSJames Feist { 3945b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 395a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 3965b4aa86bSJames Feist return; 3975b4aa86bSJames Feist } 3985b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 3995b4aa86bSJames Feist nlohmann::json& element = 4005b4aa86bSJames Feist isFan ? fans[name] : pids[name]; 401b7a08d04SJames Feist config = &element; 4025b4aa86bSJames Feist if (isFan) 4035b4aa86bSJames Feist { 4045b4aa86bSJames Feist element["@odata.id"] = 4055b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 4065b4aa86bSJames Feist "OpenBmc/Fan/FanControllers/" + 407271584abSEd Tanous name; 4085b4aa86bSJames Feist element["@odata.type"] = 4095b4aa86bSJames Feist "#OemManager.FanController"; 4105b4aa86bSJames Feist } 4115b4aa86bSJames Feist else 4125b4aa86bSJames Feist { 4135b4aa86bSJames Feist element["@odata.id"] = 4145b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 4155b4aa86bSJames Feist "OpenBmc/Fan/PidControllers/" + 416271584abSEd Tanous name; 4175b4aa86bSJames Feist element["@odata.type"] = 4185b4aa86bSJames Feist "#OemManager.PidController"; 4195b4aa86bSJames Feist } 420b7a08d04SJames Feist } 421b7a08d04SJames Feist else 422b7a08d04SJames Feist { 423b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Unexpected configuration"; 424b7a08d04SJames Feist messages::internalError(asyncResp->res); 425b7a08d04SJames Feist return; 426b7a08d04SJames Feist } 427b7a08d04SJames Feist 428b7a08d04SJames Feist // used for making maps out of 2 vectors 429b7a08d04SJames Feist const std::vector<double>* keys = nullptr; 430b7a08d04SJames Feist const std::vector<double>* values = nullptr; 431b7a08d04SJames Feist 432b7a08d04SJames Feist for (const auto& propertyPair : intfPair.second) 433b7a08d04SJames Feist { 434b7a08d04SJames Feist if (propertyPair.first == "Type" || 435b7a08d04SJames Feist propertyPair.first == "Class" || 436b7a08d04SJames Feist propertyPair.first == "Name") 437b7a08d04SJames Feist { 438b7a08d04SJames Feist continue; 439b7a08d04SJames Feist } 440b7a08d04SJames Feist 441b7a08d04SJames Feist // zones 442b7a08d04SJames Feist if (intfPair.first == pidZoneConfigurationIface) 443b7a08d04SJames Feist { 444b7a08d04SJames Feist const double* ptr = 445abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 446b7a08d04SJames Feist if (ptr == nullptr) 447b7a08d04SJames Feist { 448b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 449b7a08d04SJames Feist << propertyPair.first; 450b7a08d04SJames Feist messages::internalError(asyncResp->res); 451b7a08d04SJames Feist return; 452b7a08d04SJames Feist } 453b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 454b7a08d04SJames Feist } 455b7a08d04SJames Feist 456b7a08d04SJames Feist if (intfPair.first == stepwiseConfigurationIface) 457b7a08d04SJames Feist { 458b7a08d04SJames Feist if (propertyPair.first == "Reading" || 459b7a08d04SJames Feist propertyPair.first == "Output") 460b7a08d04SJames Feist { 461b7a08d04SJames Feist const std::vector<double>* ptr = 462abf2add6SEd Tanous std::get_if<std::vector<double>>( 463b7a08d04SJames Feist &propertyPair.second); 464b7a08d04SJames Feist 465b7a08d04SJames Feist if (ptr == nullptr) 466b7a08d04SJames Feist { 467b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 468b7a08d04SJames Feist << propertyPair.first; 469b7a08d04SJames Feist messages::internalError(asyncResp->res); 470b7a08d04SJames Feist return; 471b7a08d04SJames Feist } 472b7a08d04SJames Feist 473b7a08d04SJames Feist if (propertyPair.first == "Reading") 474b7a08d04SJames Feist { 475b7a08d04SJames Feist keys = ptr; 476b7a08d04SJames Feist } 477b7a08d04SJames Feist else 478b7a08d04SJames Feist { 479b7a08d04SJames Feist values = ptr; 480b7a08d04SJames Feist } 481b7a08d04SJames Feist if (keys && values) 482b7a08d04SJames Feist { 483b7a08d04SJames Feist if (keys->size() != values->size()) 484b7a08d04SJames Feist { 485b7a08d04SJames Feist BMCWEB_LOG_ERROR 486b7a08d04SJames Feist << "Reading and Output size don't " 487b7a08d04SJames Feist "match "; 488b7a08d04SJames Feist messages::internalError(asyncResp->res); 489b7a08d04SJames Feist return; 490b7a08d04SJames Feist } 491b7a08d04SJames Feist nlohmann::json& steps = (*config)["Steps"]; 492b7a08d04SJames Feist steps = nlohmann::json::array(); 493b7a08d04SJames Feist for (size_t ii = 0; ii < keys->size(); ii++) 494b7a08d04SJames Feist { 495b7a08d04SJames Feist steps.push_back( 496b7a08d04SJames Feist {{"Target", (*keys)[ii]}, 497b7a08d04SJames Feist {"Output", (*values)[ii]}}); 498b7a08d04SJames Feist } 499b7a08d04SJames Feist } 500b7a08d04SJames Feist } 501b7a08d04SJames Feist if (propertyPair.first == "NegativeHysteresis" || 502b7a08d04SJames Feist propertyPair.first == "PositiveHysteresis") 503b7a08d04SJames Feist { 504b7a08d04SJames Feist const double* ptr = 505abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 506b7a08d04SJames Feist if (ptr == nullptr) 507b7a08d04SJames Feist { 508b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 509b7a08d04SJames Feist << propertyPair.first; 510b7a08d04SJames Feist messages::internalError(asyncResp->res); 511b7a08d04SJames Feist return; 512b7a08d04SJames Feist } 513b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 514b7a08d04SJames Feist } 515b7a08d04SJames Feist } 516b7a08d04SJames Feist 517b7a08d04SJames Feist // pid and fans are off the same configuration 518b7a08d04SJames Feist if (intfPair.first == pidConfigurationIface || 519b7a08d04SJames Feist intfPair.first == stepwiseConfigurationIface) 520b7a08d04SJames Feist { 5215b4aa86bSJames Feist 5225b4aa86bSJames Feist if (propertyPair.first == "Zones") 5235b4aa86bSJames Feist { 5245b4aa86bSJames Feist const std::vector<std::string>* inputs = 525abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 5261b6b96c5SEd Tanous &propertyPair.second); 5275b4aa86bSJames Feist 5285b4aa86bSJames Feist if (inputs == nullptr) 5295b4aa86bSJames Feist { 5305b4aa86bSJames Feist BMCWEB_LOG_ERROR 5315b4aa86bSJames Feist << "Zones Pid Field Illegal"; 532a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5335b4aa86bSJames Feist return; 5345b4aa86bSJames Feist } 535b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 5365b4aa86bSJames Feist data = nlohmann::json::array(); 5375b4aa86bSJames Feist for (std::string itemCopy : *inputs) 5385b4aa86bSJames Feist { 5395b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 5405b4aa86bSJames Feist data.push_back( 5415b4aa86bSJames Feist {{"@odata.id", 5425b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 5435b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 5445b4aa86bSJames Feist itemCopy}}); 5455b4aa86bSJames Feist } 5465b4aa86bSJames Feist } 5475b4aa86bSJames Feist // todo(james): may never happen, but this 5485b4aa86bSJames Feist // assumes configuration data referenced in the 5495b4aa86bSJames Feist // PID config is provided by the same daemon, we 5505b4aa86bSJames Feist // could add another loop to cover all cases, 5515b4aa86bSJames Feist // but I'm okay kicking this can down the road a 5525b4aa86bSJames Feist // bit 5535b4aa86bSJames Feist 5545b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 5555b4aa86bSJames Feist propertyPair.first == "Outputs") 5565b4aa86bSJames Feist { 557b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 5585b4aa86bSJames Feist const std::vector<std::string>* inputs = 559abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 5601b6b96c5SEd Tanous &propertyPair.second); 5615b4aa86bSJames Feist 5625b4aa86bSJames Feist if (inputs == nullptr) 5635b4aa86bSJames Feist { 5645b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 5655b4aa86bSJames Feist << propertyPair.first; 566f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5675b4aa86bSJames Feist return; 5685b4aa86bSJames Feist } 5695b4aa86bSJames Feist data = *inputs; 570b943aaefSJames Feist } 571b943aaefSJames Feist else if (propertyPair.first == "SetPointOffset") 572b943aaefSJames Feist { 573b943aaefSJames Feist const std::string* ptr = 574b943aaefSJames Feist std::get_if<std::string>( 575b943aaefSJames Feist &propertyPair.second); 576b943aaefSJames Feist 577b943aaefSJames Feist if (ptr == nullptr) 578b943aaefSJames Feist { 579b943aaefSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 580b943aaefSJames Feist << propertyPair.first; 581b943aaefSJames Feist messages::internalError(asyncResp->res); 582b943aaefSJames Feist return; 583b943aaefSJames Feist } 584b943aaefSJames Feist // translate from dbus to redfish 585b943aaefSJames Feist if (*ptr == "WarningHigh") 586b943aaefSJames Feist { 587b943aaefSJames Feist (*config)["SetPointOffset"] = 588b943aaefSJames Feist "UpperThresholdNonCritical"; 589b943aaefSJames Feist } 590b943aaefSJames Feist else if (*ptr == "WarningLow") 591b943aaefSJames Feist { 592b943aaefSJames Feist (*config)["SetPointOffset"] = 593b943aaefSJames Feist "LowerThresholdNonCritical"; 594b943aaefSJames Feist } 595b943aaefSJames Feist else if (*ptr == "CriticalHigh") 596b943aaefSJames Feist { 597b943aaefSJames Feist (*config)["SetPointOffset"] = 598b943aaefSJames Feist "UpperThresholdCritical"; 599b943aaefSJames Feist } 600b943aaefSJames Feist else if (*ptr == "CriticalLow") 601b943aaefSJames Feist { 602b943aaefSJames Feist (*config)["SetPointOffset"] = 603b943aaefSJames Feist "LowerThresholdCritical"; 604b943aaefSJames Feist } 605b943aaefSJames Feist else 606b943aaefSJames Feist { 607b943aaefSJames Feist BMCWEB_LOG_ERROR << "Value Illegal " 608b943aaefSJames Feist << *ptr; 609b943aaefSJames Feist messages::internalError(asyncResp->res); 610b943aaefSJames Feist return; 611b943aaefSJames Feist } 612b943aaefSJames Feist } 613b943aaefSJames Feist // doubles 6145b4aa86bSJames Feist else if (propertyPair.first == 6155b4aa86bSJames Feist "FFGainCoefficient" || 6165b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 6175b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 6185b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 6195b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 620aad1a257SJames Feist propertyPair.first == 621aad1a257SJames Feist "PositiveHysteresis" || 622aad1a257SJames Feist propertyPair.first == 623aad1a257SJames Feist "NegativeHysteresis" || 6245b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 6255b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 6265b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 6277625cb81SJames Feist propertyPair.first == "SetPoint" || 6285b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 6295b4aa86bSJames Feist propertyPair.first == "SlewPos") 6305b4aa86bSJames Feist { 6315b4aa86bSJames Feist const double* ptr = 632abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 6335b4aa86bSJames Feist if (ptr == nullptr) 6345b4aa86bSJames Feist { 6355b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 6365b4aa86bSJames Feist << propertyPair.first; 637f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6385b4aa86bSJames Feist return; 6395b4aa86bSJames Feist } 640b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 6415b4aa86bSJames Feist } 6425b4aa86bSJames Feist } 6435b4aa86bSJames Feist } 6445b4aa86bSJames Feist } 6455b4aa86bSJames Feist } 6465b4aa86bSJames Feist }, 6475b4aa86bSJames Feist connection, path, objectManagerIface, "GetManagedObjects"); 6485b4aa86bSJames Feist } 649ca537928SJennifer Lee 65083ff9ab6SJames Feist enum class CreatePIDRet 65183ff9ab6SJames Feist { 65283ff9ab6SJames Feist fail, 65383ff9ab6SJames Feist del, 65483ff9ab6SJames Feist patch 65583ff9ab6SJames Feist }; 65683ff9ab6SJames Feist 6575f2caaefSJames Feist static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response, 6585f2caaefSJames Feist std::vector<nlohmann::json>& config, 6595f2caaefSJames Feist std::vector<std::string>& zones) 6605f2caaefSJames Feist { 661b6baeaa4SJames Feist if (config.empty()) 662b6baeaa4SJames Feist { 663b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Empty Zones"; 664b6baeaa4SJames Feist messages::propertyValueFormatError(response->res, 665b6baeaa4SJames Feist nlohmann::json::array(), "Zones"); 666b6baeaa4SJames Feist return false; 667b6baeaa4SJames Feist } 6685f2caaefSJames Feist for (auto& odata : config) 6695f2caaefSJames Feist { 6705f2caaefSJames Feist std::string path; 6715f2caaefSJames Feist if (!redfish::json_util::readJson(odata, response->res, "@odata.id", 6725f2caaefSJames Feist path)) 6735f2caaefSJames Feist { 6745f2caaefSJames Feist return false; 6755f2caaefSJames Feist } 6765f2caaefSJames Feist std::string input; 67761adbda3SJames Feist 67861adbda3SJames Feist // 8 below comes from 67961adbda3SJames Feist // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left 68061adbda3SJames Feist // 0 1 2 3 4 5 6 7 8 68161adbda3SJames Feist if (!dbus::utility::getNthStringFromPath(path, 8, input)) 6825f2caaefSJames Feist { 6835f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << path; 6845f2caaefSJames Feist BMCWEB_LOG_ERROR << "Illegal Type Zones"; 6855f2caaefSJames Feist messages::propertyValueFormatError(response->res, odata.dump(), 6865f2caaefSJames Feist "Zones"); 6875f2caaefSJames Feist return false; 6885f2caaefSJames Feist } 6895f2caaefSJames Feist boost::replace_all(input, "_", " "); 6905f2caaefSJames Feist zones.emplace_back(std::move(input)); 6915f2caaefSJames Feist } 6925f2caaefSJames Feist return true; 6935f2caaefSJames Feist } 6945f2caaefSJames Feist 69573df0db0SJames Feist static const dbus::utility::ManagedItem* 69673df0db0SJames Feist findChassis(const dbus::utility::ManagedObjectType& managedObj, 697b6baeaa4SJames Feist const std::string& value, std::string& chassis) 698b6baeaa4SJames Feist { 699b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n"; 700b6baeaa4SJames Feist 701b6baeaa4SJames Feist std::string escaped = boost::replace_all_copy(value, " ", "_"); 702b6baeaa4SJames Feist escaped = "/" + escaped; 703b6baeaa4SJames Feist auto it = std::find_if( 704b6baeaa4SJames Feist managedObj.begin(), managedObj.end(), [&escaped](const auto& obj) { 705b6baeaa4SJames Feist if (boost::algorithm::ends_with(obj.first.str, escaped)) 706b6baeaa4SJames Feist { 707b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Matched " << obj.first.str << "\n"; 708b6baeaa4SJames Feist return true; 709b6baeaa4SJames Feist } 710b6baeaa4SJames Feist return false; 711b6baeaa4SJames Feist }); 712b6baeaa4SJames Feist 713b6baeaa4SJames Feist if (it == managedObj.end()) 714b6baeaa4SJames Feist { 71573df0db0SJames Feist return nullptr; 716b6baeaa4SJames Feist } 717b6baeaa4SJames Feist // 5 comes from <chassis-name> being the 5th element 718b6baeaa4SJames Feist // /xyz/openbmc_project/inventory/system/chassis/<chassis-name> 71973df0db0SJames Feist if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis)) 72073df0db0SJames Feist { 72173df0db0SJames Feist return &(*it); 72273df0db0SJames Feist } 72373df0db0SJames Feist 72473df0db0SJames Feist return nullptr; 725b6baeaa4SJames Feist } 726b6baeaa4SJames Feist 72783ff9ab6SJames Feist static CreatePIDRet createPidInterface( 72883ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 729b6baeaa4SJames Feist nlohmann::json::iterator it, const std::string& path, 73083ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 73183ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 73283ff9ab6SJames Feist output, 73373df0db0SJames Feist std::string& chassis, const std::string& profile) 73483ff9ab6SJames Feist { 73583ff9ab6SJames Feist 7365f2caaefSJames Feist // common deleter 737b6baeaa4SJames Feist if (it.value() == nullptr) 7385f2caaefSJames Feist { 7395f2caaefSJames Feist std::string iface; 7405f2caaefSJames Feist if (type == "PidControllers" || type == "FanControllers") 7415f2caaefSJames Feist { 7425f2caaefSJames Feist iface = pidConfigurationIface; 7435f2caaefSJames Feist } 7445f2caaefSJames Feist else if (type == "FanZones") 7455f2caaefSJames Feist { 7465f2caaefSJames Feist iface = pidZoneConfigurationIface; 7475f2caaefSJames Feist } 7485f2caaefSJames Feist else if (type == "StepwiseControllers") 7495f2caaefSJames Feist { 7505f2caaefSJames Feist iface = stepwiseConfigurationIface; 7515f2caaefSJames Feist } 7525f2caaefSJames Feist else 7535f2caaefSJames Feist { 7545f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " 7555f2caaefSJames Feist << type; 7565f2caaefSJames Feist messages::propertyUnknown(response->res, type); 7575f2caaefSJames Feist return CreatePIDRet::fail; 7585f2caaefSJames Feist } 7596ee7f774SJames Feist 7606ee7f774SJames Feist BMCWEB_LOG_DEBUG << "del " << path << " " << iface << "\n"; 7615f2caaefSJames Feist // delete interface 7625f2caaefSJames Feist crow::connections::systemBus->async_method_call( 7635f2caaefSJames Feist [response, path](const boost::system::error_code ec) { 7645f2caaefSJames Feist if (ec) 7655f2caaefSJames Feist { 7665f2caaefSJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec; 7675f2caaefSJames Feist messages::internalError(response->res); 768b6baeaa4SJames Feist return; 7695f2caaefSJames Feist } 770b6baeaa4SJames Feist messages::success(response->res); 7715f2caaefSJames Feist }, 7725f2caaefSJames Feist "xyz.openbmc_project.EntityManager", path, iface, "Delete"); 7735f2caaefSJames Feist return CreatePIDRet::del; 7745f2caaefSJames Feist } 7755f2caaefSJames Feist 77673df0db0SJames Feist const dbus::utility::ManagedItem* managedItem = nullptr; 777b6baeaa4SJames Feist if (!createNewObject) 778b6baeaa4SJames Feist { 779b6baeaa4SJames Feist // if we aren't creating a new object, we should be able to find it on 780b6baeaa4SJames Feist // d-bus 78173df0db0SJames Feist managedItem = findChassis(managedObj, it.key(), chassis); 78273df0db0SJames Feist if (managedItem == nullptr) 783b6baeaa4SJames Feist { 784b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 785b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 786b6baeaa4SJames Feist return CreatePIDRet::fail; 787b6baeaa4SJames Feist } 788b6baeaa4SJames Feist } 789b6baeaa4SJames Feist 79073df0db0SJames Feist if (profile.size() && 79173df0db0SJames Feist (type == "PidControllers" || type == "FanControllers" || 79273df0db0SJames Feist type == "StepwiseControllers")) 79373df0db0SJames Feist { 79473df0db0SJames Feist if (managedItem == nullptr) 79573df0db0SJames Feist { 79673df0db0SJames Feist output["Profiles"] = std::vector<std::string>{profile}; 79773df0db0SJames Feist } 79873df0db0SJames Feist else 79973df0db0SJames Feist { 80073df0db0SJames Feist std::string interface; 80173df0db0SJames Feist if (type == "StepwiseControllers") 80273df0db0SJames Feist { 80373df0db0SJames Feist interface = stepwiseConfigurationIface; 80473df0db0SJames Feist } 80573df0db0SJames Feist else 80673df0db0SJames Feist { 80773df0db0SJames Feist interface = pidConfigurationIface; 80873df0db0SJames Feist } 80973df0db0SJames Feist auto findConfig = managedItem->second.find(interface); 81073df0db0SJames Feist if (findConfig == managedItem->second.end()) 81173df0db0SJames Feist { 81273df0db0SJames Feist BMCWEB_LOG_ERROR 81373df0db0SJames Feist << "Failed to find interface in managed object"; 81473df0db0SJames Feist messages::internalError(response->res); 81573df0db0SJames Feist return CreatePIDRet::fail; 81673df0db0SJames Feist } 81773df0db0SJames Feist auto findProfiles = findConfig->second.find("Profiles"); 81873df0db0SJames Feist if (findProfiles != findConfig->second.end()) 81973df0db0SJames Feist { 82073df0db0SJames Feist const std::vector<std::string>* curProfiles = 82173df0db0SJames Feist std::get_if<std::vector<std::string>>( 82273df0db0SJames Feist &(findProfiles->second)); 82373df0db0SJames Feist if (curProfiles == nullptr) 82473df0db0SJames Feist { 82573df0db0SJames Feist BMCWEB_LOG_ERROR << "Illegal profiles in managed object"; 82673df0db0SJames Feist messages::internalError(response->res); 82773df0db0SJames Feist return CreatePIDRet::fail; 82873df0db0SJames Feist } 82973df0db0SJames Feist if (std::find(curProfiles->begin(), curProfiles->end(), 83073df0db0SJames Feist profile) == curProfiles->end()) 83173df0db0SJames Feist { 83273df0db0SJames Feist std::vector<std::string> newProfiles = *curProfiles; 83373df0db0SJames Feist newProfiles.push_back(profile); 83473df0db0SJames Feist output["Profiles"] = newProfiles; 83573df0db0SJames Feist } 83673df0db0SJames Feist } 83773df0db0SJames Feist } 83873df0db0SJames Feist } 83973df0db0SJames Feist 84083ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 84183ff9ab6SJames Feist { 84283ff9ab6SJames Feist if (createNewObject) 84383ff9ab6SJames Feist { 84483ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 84583ff9ab6SJames Feist : std::string("fan"); 84683ff9ab6SJames Feist output["Type"] = std::string("Pid"); 84783ff9ab6SJames Feist } 8485f2caaefSJames Feist 8495f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 8505f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 8515f2caaefSJames Feist std::optional<std::vector<std::string>> outputs; 8525f2caaefSJames Feist std::map<std::string, std::optional<double>> doubles; 853b943aaefSJames Feist std::optional<std::string> setpointOffset; 8545f2caaefSJames Feist if (!redfish::json_util::readJson( 855b6baeaa4SJames Feist it.value(), response->res, "Inputs", inputs, "Outputs", outputs, 8565f2caaefSJames Feist "Zones", zones, "FFGainCoefficient", 8575f2caaefSJames Feist doubles["FFGainCoefficient"], "FFOffCoefficient", 8585f2caaefSJames Feist doubles["FFOffCoefficient"], "ICoefficient", 8595f2caaefSJames Feist doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], 8605f2caaefSJames Feist "ILimitMin", doubles["ILimitMin"], "OutLimitMax", 8615f2caaefSJames Feist doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], 8625f2caaefSJames Feist "PCoefficient", doubles["PCoefficient"], "SetPoint", 863b943aaefSJames Feist doubles["SetPoint"], "SetPointOffset", setpointOffset, 864b943aaefSJames Feist "SlewNeg", doubles["SlewNeg"], "SlewPos", doubles["SlewPos"], 865b943aaefSJames Feist "PositiveHysteresis", doubles["PositiveHysteresis"], 866b943aaefSJames Feist "NegativeHysteresis", doubles["NegativeHysteresis"])) 86783ff9ab6SJames Feist { 8685f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 869b6baeaa4SJames Feist << it.value().dump(); 8705f2caaefSJames Feist return CreatePIDRet::fail; 87183ff9ab6SJames Feist } 8725f2caaefSJames Feist if (zones) 8735f2caaefSJames Feist { 8745f2caaefSJames Feist std::vector<std::string> zonesStr; 8755f2caaefSJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStr)) 8765f2caaefSJames Feist { 8775f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 8785f2caaefSJames Feist return CreatePIDRet::fail; 8795f2caaefSJames Feist } 880b6baeaa4SJames Feist if (chassis.empty() && 881b6baeaa4SJames Feist !findChassis(managedObj, zonesStr[0], chassis)) 882b6baeaa4SJames Feist { 883b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 884b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 885b6baeaa4SJames Feist return CreatePIDRet::fail; 886b6baeaa4SJames Feist } 887b6baeaa4SJames Feist 8885f2caaefSJames Feist output["Zones"] = std::move(zonesStr); 8895f2caaefSJames Feist } 8905f2caaefSJames Feist if (inputs || outputs) 8915f2caaefSJames Feist { 8925f2caaefSJames Feist std::array<std::optional<std::vector<std::string>>*, 2> containers = 8935f2caaefSJames Feist {&inputs, &outputs}; 8945f2caaefSJames Feist size_t index = 0; 8955f2caaefSJames Feist for (const auto& containerPtr : containers) 8965f2caaefSJames Feist { 8975f2caaefSJames Feist std::optional<std::vector<std::string>>& container = 8985f2caaefSJames Feist *containerPtr; 8995f2caaefSJames Feist if (!container) 9005f2caaefSJames Feist { 9015f2caaefSJames Feist index++; 9025f2caaefSJames Feist continue; 90383ff9ab6SJames Feist } 90483ff9ab6SJames Feist 9055f2caaefSJames Feist for (std::string& value : *container) 90683ff9ab6SJames Feist { 9075f2caaefSJames Feist boost::replace_all(value, "_", " "); 90883ff9ab6SJames Feist } 9095f2caaefSJames Feist std::string key; 9105f2caaefSJames Feist if (index == 0) 9115f2caaefSJames Feist { 9125f2caaefSJames Feist key = "Inputs"; 9135f2caaefSJames Feist } 9145f2caaefSJames Feist else 9155f2caaefSJames Feist { 9165f2caaefSJames Feist key = "Outputs"; 9175f2caaefSJames Feist } 9185f2caaefSJames Feist output[key] = *container; 9195f2caaefSJames Feist index++; 9205f2caaefSJames Feist } 92183ff9ab6SJames Feist } 92283ff9ab6SJames Feist 923b943aaefSJames Feist if (setpointOffset) 924b943aaefSJames Feist { 925b943aaefSJames Feist // translate between redfish and dbus names 926b943aaefSJames Feist if (*setpointOffset == "UpperThresholdNonCritical") 927b943aaefSJames Feist { 928b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningLow"); 929b943aaefSJames Feist } 930b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdNonCritical") 931b943aaefSJames Feist { 932b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningHigh"); 933b943aaefSJames Feist } 934b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdCritical") 935b943aaefSJames Feist { 936b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalLow"); 937b943aaefSJames Feist } 938b943aaefSJames Feist else if (*setpointOffset == "UpperThresholdCritical") 939b943aaefSJames Feist { 940b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalHigh"); 941b943aaefSJames Feist } 942b943aaefSJames Feist else 943b943aaefSJames Feist { 944b943aaefSJames Feist BMCWEB_LOG_ERROR << "Invalid setpointoffset " 945b943aaefSJames Feist << *setpointOffset; 946b943aaefSJames Feist messages::invalidObject(response->res, it.key()); 947b943aaefSJames Feist return CreatePIDRet::fail; 948b943aaefSJames Feist } 949b943aaefSJames Feist } 950b943aaefSJames Feist 95183ff9ab6SJames Feist // doubles 9525f2caaefSJames Feist for (const auto& pairs : doubles) 95383ff9ab6SJames Feist { 9545f2caaefSJames Feist if (!pairs.second) 95583ff9ab6SJames Feist { 9565f2caaefSJames Feist continue; 95783ff9ab6SJames Feist } 9585f2caaefSJames Feist BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second; 9595f2caaefSJames Feist output[pairs.first] = *(pairs.second); 9605f2caaefSJames Feist } 96183ff9ab6SJames Feist } 96283ff9ab6SJames Feist 96383ff9ab6SJames Feist else if (type == "FanZones") 96483ff9ab6SJames Feist { 96583ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 96683ff9ab6SJames Feist 9675f2caaefSJames Feist std::optional<nlohmann::json> chassisContainer; 9685f2caaefSJames Feist std::optional<double> failSafePercent; 969d3ec07f8SJames Feist std::optional<double> minThermalOutput; 970b6baeaa4SJames Feist if (!redfish::json_util::readJson(it.value(), response->res, "Chassis", 9715f2caaefSJames Feist chassisContainer, "FailSafePercent", 972d3ec07f8SJames Feist failSafePercent, "MinThermalOutput", 973d3ec07f8SJames Feist minThermalOutput)) 97483ff9ab6SJames Feist { 9755f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 976b6baeaa4SJames Feist << it.value().dump(); 97783ff9ab6SJames Feist return CreatePIDRet::fail; 97883ff9ab6SJames Feist } 9795f2caaefSJames Feist 9805f2caaefSJames Feist if (chassisContainer) 98183ff9ab6SJames Feist { 9825f2caaefSJames Feist 9835f2caaefSJames Feist std::string chassisId; 9845f2caaefSJames Feist if (!redfish::json_util::readJson(*chassisContainer, response->res, 9855f2caaefSJames Feist "@odata.id", chassisId)) 9865f2caaefSJames Feist { 9875f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 9885f2caaefSJames Feist << chassisContainer->dump(); 98983ff9ab6SJames Feist return CreatePIDRet::fail; 99083ff9ab6SJames Feist } 99183ff9ab6SJames Feist 992717794d5SAppaRao Puli // /redfish/v1/chassis/chassis_name/ 9935f2caaefSJames Feist if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis)) 99483ff9ab6SJames Feist { 9955f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << chassisId; 9965f2caaefSJames Feist messages::invalidObject(response->res, chassisId); 99783ff9ab6SJames Feist return CreatePIDRet::fail; 99883ff9ab6SJames Feist } 99983ff9ab6SJames Feist } 1000d3ec07f8SJames Feist if (minThermalOutput) 100183ff9ab6SJames Feist { 1002d3ec07f8SJames Feist output["MinThermalOutput"] = *minThermalOutput; 10035f2caaefSJames Feist } 10045f2caaefSJames Feist if (failSafePercent) 100583ff9ab6SJames Feist { 10065f2caaefSJames Feist output["FailSafePercent"] = *failSafePercent; 10075f2caaefSJames Feist } 10085f2caaefSJames Feist } 10095f2caaefSJames Feist else if (type == "StepwiseControllers") 10105f2caaefSJames Feist { 10115f2caaefSJames Feist output["Type"] = std::string("Stepwise"); 10125f2caaefSJames Feist 10135f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 10145f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> steps; 10155f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 10165f2caaefSJames Feist std::optional<double> positiveHysteresis; 10175f2caaefSJames Feist std::optional<double> negativeHysteresis; 1018c33a90ecSJames Feist std::optional<std::string> direction; // upper clipping curve vs lower 10195f2caaefSJames Feist if (!redfish::json_util::readJson( 1020b6baeaa4SJames Feist it.value(), response->res, "Zones", zones, "Steps", steps, 1021b6baeaa4SJames Feist "Inputs", inputs, "PositiveHysteresis", positiveHysteresis, 1022c33a90ecSJames Feist "NegativeHysteresis", negativeHysteresis, "Direction", 1023c33a90ecSJames Feist direction)) 10245f2caaefSJames Feist { 10255f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 1026b6baeaa4SJames Feist << it.value().dump(); 102783ff9ab6SJames Feist return CreatePIDRet::fail; 102883ff9ab6SJames Feist } 10295f2caaefSJames Feist 10305f2caaefSJames Feist if (zones) 103183ff9ab6SJames Feist { 1032b6baeaa4SJames Feist std::vector<std::string> zonesStrs; 1033b6baeaa4SJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStrs)) 10345f2caaefSJames Feist { 10355f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 103683ff9ab6SJames Feist return CreatePIDRet::fail; 103783ff9ab6SJames Feist } 1038b6baeaa4SJames Feist if (chassis.empty() && 1039b6baeaa4SJames Feist !findChassis(managedObj, zonesStrs[0], chassis)) 1040b6baeaa4SJames Feist { 1041b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 1042b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 1043b6baeaa4SJames Feist return CreatePIDRet::fail; 1044b6baeaa4SJames Feist } 1045b6baeaa4SJames Feist output["Zones"] = std::move(zonesStrs); 10465f2caaefSJames Feist } 10475f2caaefSJames Feist if (steps) 10485f2caaefSJames Feist { 10495f2caaefSJames Feist std::vector<double> readings; 10505f2caaefSJames Feist std::vector<double> outputs; 10515f2caaefSJames Feist for (auto& step : *steps) 10525f2caaefSJames Feist { 10535f2caaefSJames Feist double target; 1054b01bf299SEd Tanous double output; 10555f2caaefSJames Feist 10565f2caaefSJames Feist if (!redfish::json_util::readJson(step, response->res, "Target", 1057b01bf299SEd Tanous target, "Output", output)) 10585f2caaefSJames Feist { 10595f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 1060b6baeaa4SJames Feist << ", Illegal Property " 1061b6baeaa4SJames Feist << it.value().dump(); 10625f2caaefSJames Feist return CreatePIDRet::fail; 10635f2caaefSJames Feist } 10645f2caaefSJames Feist readings.emplace_back(target); 1065b01bf299SEd Tanous outputs.emplace_back(output); 10665f2caaefSJames Feist } 10675f2caaefSJames Feist output["Reading"] = std::move(readings); 10685f2caaefSJames Feist output["Output"] = std::move(outputs); 10695f2caaefSJames Feist } 10705f2caaefSJames Feist if (inputs) 10715f2caaefSJames Feist { 10725f2caaefSJames Feist for (std::string& value : *inputs) 10735f2caaefSJames Feist { 10745f2caaefSJames Feist boost::replace_all(value, "_", " "); 10755f2caaefSJames Feist } 10765f2caaefSJames Feist output["Inputs"] = std::move(*inputs); 10775f2caaefSJames Feist } 10785f2caaefSJames Feist if (negativeHysteresis) 10795f2caaefSJames Feist { 10805f2caaefSJames Feist output["NegativeHysteresis"] = *negativeHysteresis; 10815f2caaefSJames Feist } 10825f2caaefSJames Feist if (positiveHysteresis) 10835f2caaefSJames Feist { 10845f2caaefSJames Feist output["PositiveHysteresis"] = *positiveHysteresis; 108583ff9ab6SJames Feist } 1086c33a90ecSJames Feist if (direction) 1087c33a90ecSJames Feist { 1088c33a90ecSJames Feist constexpr const std::array<const char*, 2> allowedDirections = { 1089c33a90ecSJames Feist "Ceiling", "Floor"}; 1090c33a90ecSJames Feist if (std::find(allowedDirections.begin(), allowedDirections.end(), 1091c33a90ecSJames Feist *direction) == allowedDirections.end()) 1092c33a90ecSJames Feist { 1093c33a90ecSJames Feist messages::propertyValueTypeError(response->res, "Direction", 1094c33a90ecSJames Feist *direction); 1095c33a90ecSJames Feist return CreatePIDRet::fail; 1096c33a90ecSJames Feist } 1097c33a90ecSJames Feist output["Class"] = *direction; 1098c33a90ecSJames Feist } 109983ff9ab6SJames Feist } 110083ff9ab6SJames Feist else 110183ff9ab6SJames Feist { 11025f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type; 110335a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 110483ff9ab6SJames Feist return CreatePIDRet::fail; 110583ff9ab6SJames Feist } 110683ff9ab6SJames Feist return CreatePIDRet::patch; 110783ff9ab6SJames Feist } 110873df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues> 110973df0db0SJames Feist { 111083ff9ab6SJames Feist 111173df0db0SJames Feist GetPIDValues(const std::shared_ptr<AsyncResp>& asyncResp) : 111273df0db0SJames Feist asyncResp(asyncResp) 111373df0db0SJames Feist 11141214b7e7SGunnar Mills {} 11159c310685SBorawski.Lukasz 111673df0db0SJames Feist void run() 11175b4aa86bSJames Feist { 111873df0db0SJames Feist std::shared_ptr<GetPIDValues> self = shared_from_this(); 111973df0db0SJames Feist 112073df0db0SJames Feist // get all configurations 11215b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 112273df0db0SJames Feist [self](const boost::system::error_code ec, 11235b4aa86bSJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 11245b4aa86bSJames Feist if (ec) 11255b4aa86bSJames Feist { 11265b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 112773df0db0SJames Feist messages::internalError(self->asyncResp->res); 112873df0db0SJames Feist return; 112973df0db0SJames Feist } 113073df0db0SJames Feist self->subtree = subtree; 113173df0db0SJames Feist }, 113273df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 113373df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 113473df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 113573df0db0SJames Feist std::array<const char*, 4>{ 113673df0db0SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 113773df0db0SJames Feist objectManagerIface, stepwiseConfigurationIface}); 113873df0db0SJames Feist 113973df0db0SJames Feist // at the same time get the selected profile 114073df0db0SJames Feist crow::connections::systemBus->async_method_call( 114173df0db0SJames Feist [self](const boost::system::error_code ec, 114273df0db0SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 114373df0db0SJames Feist if (ec || subtree.empty()) 114473df0db0SJames Feist { 114573df0db0SJames Feist return; 114673df0db0SJames Feist } 114773df0db0SJames Feist if (subtree[0].second.size() != 1) 114873df0db0SJames Feist { 114973df0db0SJames Feist // invalid mapper response, should never happen 115073df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Mapper Error"; 115173df0db0SJames Feist messages::internalError(self->asyncResp->res); 11525b4aa86bSJames Feist return; 11535b4aa86bSJames Feist } 11545b4aa86bSJames Feist 115573df0db0SJames Feist const std::string& path = subtree[0].first; 115673df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 115773df0db0SJames Feist crow::connections::systemBus->async_method_call( 115873df0db0SJames Feist [path, owner, self]( 115973df0db0SJames Feist const boost::system::error_code ec, 116073df0db0SJames Feist const boost::container::flat_map< 116173df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 116273df0db0SJames Feist std::string>>& resp) { 116373df0db0SJames Feist if (ec) 116473df0db0SJames Feist { 116573df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Can't get " 116673df0db0SJames Feist "thermalModeIface " 116773df0db0SJames Feist << path; 116873df0db0SJames Feist messages::internalError(self->asyncResp->res); 116973df0db0SJames Feist return; 117073df0db0SJames Feist } 1171271584abSEd Tanous const std::string* current = nullptr; 1172271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 117373df0db0SJames Feist for (auto& [key, value] : resp) 117473df0db0SJames Feist { 117573df0db0SJames Feist if (key == "Current") 117673df0db0SJames Feist { 117773df0db0SJames Feist current = std::get_if<std::string>(&value); 117873df0db0SJames Feist if (current == nullptr) 117973df0db0SJames Feist { 118073df0db0SJames Feist BMCWEB_LOG_ERROR 118173df0db0SJames Feist << "GetPIDValues: thermal mode " 118273df0db0SJames Feist "iface invalid " 118373df0db0SJames Feist << path; 118473df0db0SJames Feist messages::internalError( 118573df0db0SJames Feist self->asyncResp->res); 118673df0db0SJames Feist return; 118773df0db0SJames Feist } 118873df0db0SJames Feist } 118973df0db0SJames Feist if (key == "Supported") 119073df0db0SJames Feist { 119173df0db0SJames Feist supported = 119273df0db0SJames Feist std::get_if<std::vector<std::string>>( 119373df0db0SJames Feist &value); 119473df0db0SJames Feist if (supported == nullptr) 119573df0db0SJames Feist { 119673df0db0SJames Feist BMCWEB_LOG_ERROR 119773df0db0SJames Feist << "GetPIDValues: thermal mode " 119873df0db0SJames Feist "iface invalid" 119973df0db0SJames Feist << path; 120073df0db0SJames Feist messages::internalError( 120173df0db0SJames Feist self->asyncResp->res); 120273df0db0SJames Feist return; 120373df0db0SJames Feist } 120473df0db0SJames Feist } 120573df0db0SJames Feist } 120673df0db0SJames Feist if (current == nullptr || supported == nullptr) 120773df0db0SJames Feist { 120873df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: thermal mode " 120973df0db0SJames Feist "iface invalid " 121073df0db0SJames Feist << path; 121173df0db0SJames Feist messages::internalError(self->asyncResp->res); 121273df0db0SJames Feist return; 121373df0db0SJames Feist } 121473df0db0SJames Feist self->currentProfile = *current; 121573df0db0SJames Feist self->supportedProfiles = *supported; 121673df0db0SJames Feist }, 121773df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 121873df0db0SJames Feist thermalModeIface); 121973df0db0SJames Feist }, 122073df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 122173df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 122273df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 122373df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 122473df0db0SJames Feist } 122573df0db0SJames Feist 122673df0db0SJames Feist ~GetPIDValues() 122773df0db0SJames Feist { 122873df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 122973df0db0SJames Feist { 123073df0db0SJames Feist return; 123173df0db0SJames Feist } 12325b4aa86bSJames Feist // create map of <connection, path to objMgr>> 123373df0db0SJames Feist boost::container::flat_map<std::string, std::string> objectMgrPaths; 12346bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 12355b4aa86bSJames Feist for (const auto& pathGroup : subtree) 12365b4aa86bSJames Feist { 12375b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 12385b4aa86bSJames Feist { 12396bce33bcSJames Feist auto findConnection = 12406bce33bcSJames Feist calledConnections.find(connectionGroup.first); 12416bce33bcSJames Feist if (findConnection != calledConnections.end()) 12426bce33bcSJames Feist { 12436bce33bcSJames Feist break; 12446bce33bcSJames Feist } 124573df0db0SJames Feist for (const std::string& interface : connectionGroup.second) 12465b4aa86bSJames Feist { 12475b4aa86bSJames Feist if (interface == objectManagerIface) 12485b4aa86bSJames Feist { 124973df0db0SJames Feist objectMgrPaths[connectionGroup.first] = pathGroup.first; 12505b4aa86bSJames Feist } 12515b4aa86bSJames Feist // this list is alphabetical, so we 12525b4aa86bSJames Feist // should have found the objMgr by now 12535b4aa86bSJames Feist if (interface == pidConfigurationIface || 1254b7a08d04SJames Feist interface == pidZoneConfigurationIface || 1255b7a08d04SJames Feist interface == stepwiseConfigurationIface) 12565b4aa86bSJames Feist { 12575b4aa86bSJames Feist auto findObjMgr = 12585b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 12595b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 12605b4aa86bSJames Feist { 12615b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 12625b4aa86bSJames Feist << "Has no Object Manager"; 12635b4aa86bSJames Feist continue; 12645b4aa86bSJames Feist } 12656bce33bcSJames Feist 12666bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 12676bce33bcSJames Feist 126873df0db0SJames Feist asyncPopulatePid(findObjMgr->first, findObjMgr->second, 126973df0db0SJames Feist currentProfile, supportedProfiles, 127073df0db0SJames Feist asyncResp); 12715b4aa86bSJames Feist break; 12725b4aa86bSJames Feist } 12735b4aa86bSJames Feist } 12745b4aa86bSJames Feist } 12755b4aa86bSJames Feist } 127673df0db0SJames Feist } 127773df0db0SJames Feist 127873df0db0SJames Feist std::vector<std::string> supportedProfiles; 127973df0db0SJames Feist std::string currentProfile; 128073df0db0SJames Feist crow::openbmc_mapper::GetSubTreeType subtree; 128173df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 128273df0db0SJames Feist }; 128373df0db0SJames Feist 128473df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues> 128573df0db0SJames Feist { 128673df0db0SJames Feist 1287271584abSEd Tanous SetPIDValues(const std::shared_ptr<AsyncResp>& asyncRespIn, 128873df0db0SJames Feist nlohmann::json& data) : 1289271584abSEd Tanous asyncResp(asyncRespIn) 129073df0db0SJames Feist { 129173df0db0SJames Feist 129273df0db0SJames Feist std::optional<nlohmann::json> pidControllers; 129373df0db0SJames Feist std::optional<nlohmann::json> fanControllers; 129473df0db0SJames Feist std::optional<nlohmann::json> fanZones; 129573df0db0SJames Feist std::optional<nlohmann::json> stepwiseControllers; 129673df0db0SJames Feist 129773df0db0SJames Feist if (!redfish::json_util::readJson( 129873df0db0SJames Feist data, asyncResp->res, "PidControllers", pidControllers, 129973df0db0SJames Feist "FanControllers", fanControllers, "FanZones", fanZones, 130073df0db0SJames Feist "StepwiseControllers", stepwiseControllers, "Profile", profile)) 130173df0db0SJames Feist { 130273df0db0SJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 130373df0db0SJames Feist << data.dump(); 130473df0db0SJames Feist return; 130573df0db0SJames Feist } 130673df0db0SJames Feist configuration.emplace_back("PidControllers", std::move(pidControllers)); 130773df0db0SJames Feist configuration.emplace_back("FanControllers", std::move(fanControllers)); 130873df0db0SJames Feist configuration.emplace_back("FanZones", std::move(fanZones)); 130973df0db0SJames Feist configuration.emplace_back("StepwiseControllers", 131073df0db0SJames Feist std::move(stepwiseControllers)); 131173df0db0SJames Feist } 131273df0db0SJames Feist void run() 131373df0db0SJames Feist { 131473df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 131573df0db0SJames Feist { 131673df0db0SJames Feist return; 131773df0db0SJames Feist } 131873df0db0SJames Feist 131973df0db0SJames Feist std::shared_ptr<SetPIDValues> self = shared_from_this(); 132073df0db0SJames Feist 132173df0db0SJames Feist // todo(james): might make sense to do a mapper call here if this 132273df0db0SJames Feist // interface gets more traction 132373df0db0SJames Feist crow::connections::systemBus->async_method_call( 132473df0db0SJames Feist [self](const boost::system::error_code ec, 1325271584abSEd Tanous dbus::utility::ManagedObjectType& mObj) { 132673df0db0SJames Feist if (ec) 132773df0db0SJames Feist { 132873df0db0SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 132973df0db0SJames Feist messages::internalError(self->asyncResp->res); 133073df0db0SJames Feist return; 133173df0db0SJames Feist } 1332e69d9de2SJames Feist const std::array<const char*, 3> configurations = { 1333e69d9de2SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 1334e69d9de2SJames Feist stepwiseConfigurationIface}; 1335e69d9de2SJames Feist 133614b0b8d5SJames Feist for (const auto& [path, object] : mObj) 1337e69d9de2SJames Feist { 133814b0b8d5SJames Feist for (const auto& [interface, _] : object) 1339e69d9de2SJames Feist { 1340e69d9de2SJames Feist if (std::find(configurations.begin(), 1341e69d9de2SJames Feist configurations.end(), 1342e69d9de2SJames Feist interface) != configurations.end()) 1343e69d9de2SJames Feist { 134414b0b8d5SJames Feist self->objectCount++; 1345e69d9de2SJames Feist break; 1346e69d9de2SJames Feist } 1347e69d9de2SJames Feist } 1348e69d9de2SJames Feist } 1349271584abSEd Tanous self->managedObj = std::move(mObj); 135073df0db0SJames Feist }, 135173df0db0SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 135273df0db0SJames Feist "GetManagedObjects"); 135373df0db0SJames Feist 135473df0db0SJames Feist // at the same time get the profile information 135573df0db0SJames Feist crow::connections::systemBus->async_method_call( 135673df0db0SJames Feist [self](const boost::system::error_code ec, 135773df0db0SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 135873df0db0SJames Feist if (ec || subtree.empty()) 135973df0db0SJames Feist { 136073df0db0SJames Feist return; 136173df0db0SJames Feist } 136273df0db0SJames Feist if (subtree[0].second.empty()) 136373df0db0SJames Feist { 136473df0db0SJames Feist // invalid mapper response, should never happen 136573df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Mapper Error"; 136673df0db0SJames Feist messages::internalError(self->asyncResp->res); 136773df0db0SJames Feist return; 136873df0db0SJames Feist } 136973df0db0SJames Feist 137073df0db0SJames Feist const std::string& path = subtree[0].first; 137173df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 137273df0db0SJames Feist crow::connections::systemBus->async_method_call( 137373df0db0SJames Feist [self, path, owner]( 137473df0db0SJames Feist const boost::system::error_code ec, 137573df0db0SJames Feist const boost::container::flat_map< 137673df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 1377271584abSEd Tanous std::string>>& r) { 137873df0db0SJames Feist if (ec) 137973df0db0SJames Feist { 138073df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Can't get " 138173df0db0SJames Feist "thermalModeIface " 138273df0db0SJames Feist << path; 138373df0db0SJames Feist messages::internalError(self->asyncResp->res); 138473df0db0SJames Feist return; 138573df0db0SJames Feist } 1386271584abSEd Tanous const std::string* current = nullptr; 1387271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 1388271584abSEd Tanous for (auto& [key, value] : r) 138973df0db0SJames Feist { 139073df0db0SJames Feist if (key == "Current") 139173df0db0SJames Feist { 139273df0db0SJames Feist current = std::get_if<std::string>(&value); 139373df0db0SJames Feist if (current == nullptr) 139473df0db0SJames Feist { 139573df0db0SJames Feist BMCWEB_LOG_ERROR 139673df0db0SJames Feist << "SetPIDValues: thermal mode " 139773df0db0SJames Feist "iface invalid " 139873df0db0SJames Feist << path; 139973df0db0SJames Feist messages::internalError( 140073df0db0SJames Feist self->asyncResp->res); 140173df0db0SJames Feist return; 140273df0db0SJames Feist } 140373df0db0SJames Feist } 140473df0db0SJames Feist if (key == "Supported") 140573df0db0SJames Feist { 140673df0db0SJames Feist supported = 140773df0db0SJames Feist std::get_if<std::vector<std::string>>( 140873df0db0SJames Feist &value); 140973df0db0SJames Feist if (supported == nullptr) 141073df0db0SJames Feist { 141173df0db0SJames Feist BMCWEB_LOG_ERROR 141273df0db0SJames Feist << "SetPIDValues: thermal mode " 141373df0db0SJames Feist "iface invalid" 141473df0db0SJames Feist << path; 141573df0db0SJames Feist messages::internalError( 141673df0db0SJames Feist self->asyncResp->res); 141773df0db0SJames Feist return; 141873df0db0SJames Feist } 141973df0db0SJames Feist } 142073df0db0SJames Feist } 142173df0db0SJames Feist if (current == nullptr || supported == nullptr) 142273df0db0SJames Feist { 142373df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: thermal mode " 142473df0db0SJames Feist "iface invalid " 142573df0db0SJames Feist << path; 142673df0db0SJames Feist messages::internalError(self->asyncResp->res); 142773df0db0SJames Feist return; 142873df0db0SJames Feist } 142973df0db0SJames Feist self->currentProfile = *current; 143073df0db0SJames Feist self->supportedProfiles = *supported; 143173df0db0SJames Feist self->profileConnection = owner; 143273df0db0SJames Feist self->profilePath = path; 143373df0db0SJames Feist }, 143473df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 143573df0db0SJames Feist thermalModeIface); 14365b4aa86bSJames Feist }, 14375b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 14385b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 14395b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 144073df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 144173df0db0SJames Feist } 144273df0db0SJames Feist ~SetPIDValues() 144373df0db0SJames Feist { 144473df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 144573df0db0SJames Feist { 144673df0db0SJames Feist return; 14475b4aa86bSJames Feist } 14485b4aa86bSJames Feist 144973df0db0SJames Feist std::shared_ptr<AsyncResp> response = asyncResp; 145073df0db0SJames Feist 145173df0db0SJames Feist if (profile) 145273df0db0SJames Feist { 145373df0db0SJames Feist if (std::find(supportedProfiles.begin(), supportedProfiles.end(), 145473df0db0SJames Feist *profile) == supportedProfiles.end()) 145573df0db0SJames Feist { 145673df0db0SJames Feist messages::actionParameterUnknown(response->res, "Profile", 145773df0db0SJames Feist *profile); 145873df0db0SJames Feist return; 145973df0db0SJames Feist } 146073df0db0SJames Feist currentProfile = *profile; 146173df0db0SJames Feist crow::connections::systemBus->async_method_call( 146273df0db0SJames Feist [response](const boost::system::error_code ec) { 146373df0db0SJames Feist if (ec) 146473df0db0SJames Feist { 146573df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching profile" << ec; 146673df0db0SJames Feist messages::internalError(response->res); 146773df0db0SJames Feist } 146873df0db0SJames Feist }, 146973df0db0SJames Feist profileConnection, profilePath, 147073df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", thermalModeIface, 147173df0db0SJames Feist "Current", std::variant<std::string>(*profile)); 147273df0db0SJames Feist } 147373df0db0SJames Feist 147473df0db0SJames Feist for (auto& containerPair : configuration) 147573df0db0SJames Feist { 147673df0db0SJames Feist auto& container = containerPair.second; 147773df0db0SJames Feist if (!container) 147873df0db0SJames Feist { 147973df0db0SJames Feist continue; 148073df0db0SJames Feist } 14816ee7f774SJames Feist BMCWEB_LOG_DEBUG << *container; 14826ee7f774SJames Feist 148373df0db0SJames Feist std::string& type = containerPair.first; 148473df0db0SJames Feist 148573df0db0SJames Feist for (nlohmann::json::iterator it = container->begin(); 148673df0db0SJames Feist it != container->end(); it++) 148773df0db0SJames Feist { 148873df0db0SJames Feist const auto& name = it.key(); 14896ee7f774SJames Feist BMCWEB_LOG_DEBUG << "looking for " << name; 14906ee7f774SJames Feist 149173df0db0SJames Feist auto pathItr = 149273df0db0SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 149373df0db0SJames Feist [&name](const auto& obj) { 149473df0db0SJames Feist return boost::algorithm::ends_with( 149573df0db0SJames Feist obj.first.str, "/" + name); 149673df0db0SJames Feist }); 149773df0db0SJames Feist boost::container::flat_map<std::string, 149873df0db0SJames Feist dbus::utility::DbusVariantType> 149973df0db0SJames Feist output; 150073df0db0SJames Feist 150173df0db0SJames Feist output.reserve(16); // The pid interface length 150273df0db0SJames Feist 150373df0db0SJames Feist // determines if we're patching entity-manager or 150473df0db0SJames Feist // creating a new object 150573df0db0SJames Feist bool createNewObject = (pathItr == managedObj.end()); 15066ee7f774SJames Feist BMCWEB_LOG_DEBUG << "Found = " << !createNewObject; 15076ee7f774SJames Feist 150873df0db0SJames Feist std::string iface; 150973df0db0SJames Feist if (type == "PidControllers" || type == "FanControllers") 151073df0db0SJames Feist { 151173df0db0SJames Feist iface = pidConfigurationIface; 151273df0db0SJames Feist if (!createNewObject && 151373df0db0SJames Feist pathItr->second.find(pidConfigurationIface) == 151473df0db0SJames Feist pathItr->second.end()) 151573df0db0SJames Feist { 151673df0db0SJames Feist createNewObject = true; 151773df0db0SJames Feist } 151873df0db0SJames Feist } 151973df0db0SJames Feist else if (type == "FanZones") 152073df0db0SJames Feist { 152173df0db0SJames Feist iface = pidZoneConfigurationIface; 152273df0db0SJames Feist if (!createNewObject && 152373df0db0SJames Feist pathItr->second.find(pidZoneConfigurationIface) == 152473df0db0SJames Feist pathItr->second.end()) 152573df0db0SJames Feist { 152673df0db0SJames Feist 152773df0db0SJames Feist createNewObject = true; 152873df0db0SJames Feist } 152973df0db0SJames Feist } 153073df0db0SJames Feist else if (type == "StepwiseControllers") 153173df0db0SJames Feist { 153273df0db0SJames Feist iface = stepwiseConfigurationIface; 153373df0db0SJames Feist if (!createNewObject && 153473df0db0SJames Feist pathItr->second.find(stepwiseConfigurationIface) == 153573df0db0SJames Feist pathItr->second.end()) 153673df0db0SJames Feist { 153773df0db0SJames Feist createNewObject = true; 153873df0db0SJames Feist } 153973df0db0SJames Feist } 15406ee7f774SJames Feist 15416ee7f774SJames Feist if (createNewObject && it.value() == nullptr) 15426ee7f774SJames Feist { 15434e0453b1SGunnar Mills // can't delete a non-existent object 15446ee7f774SJames Feist messages::invalidObject(response->res, name); 15456ee7f774SJames Feist continue; 15466ee7f774SJames Feist } 15476ee7f774SJames Feist 15486ee7f774SJames Feist std::string path; 15496ee7f774SJames Feist if (pathItr != managedObj.end()) 15506ee7f774SJames Feist { 15516ee7f774SJames Feist path = pathItr->first.str; 15526ee7f774SJames Feist } 15536ee7f774SJames Feist 155473df0db0SJames Feist BMCWEB_LOG_DEBUG << "Create new = " << createNewObject << "\n"; 1555e69d9de2SJames Feist 1556e69d9de2SJames Feist // arbitrary limit to avoid attacks 1557e69d9de2SJames Feist constexpr const size_t controllerLimit = 500; 155814b0b8d5SJames Feist if (createNewObject && objectCount >= controllerLimit) 1559e69d9de2SJames Feist { 1560e69d9de2SJames Feist messages::resourceExhaustion(response->res, type); 1561e69d9de2SJames Feist continue; 1562e69d9de2SJames Feist } 1563e69d9de2SJames Feist 156473df0db0SJames Feist output["Name"] = boost::replace_all_copy(name, "_", " "); 156573df0db0SJames Feist 156673df0db0SJames Feist std::string chassis; 156773df0db0SJames Feist CreatePIDRet ret = createPidInterface( 15686ee7f774SJames Feist response, type, it, path, managedObj, createNewObject, 15696ee7f774SJames Feist output, chassis, currentProfile); 157073df0db0SJames Feist if (ret == CreatePIDRet::fail) 157173df0db0SJames Feist { 157273df0db0SJames Feist return; 157373df0db0SJames Feist } 157473df0db0SJames Feist else if (ret == CreatePIDRet::del) 157573df0db0SJames Feist { 157673df0db0SJames Feist continue; 157773df0db0SJames Feist } 157873df0db0SJames Feist 157973df0db0SJames Feist if (!createNewObject) 158073df0db0SJames Feist { 158173df0db0SJames Feist for (const auto& property : output) 158273df0db0SJames Feist { 158373df0db0SJames Feist crow::connections::systemBus->async_method_call( 158473df0db0SJames Feist [response, 158573df0db0SJames Feist propertyName{std::string(property.first)}]( 158673df0db0SJames Feist const boost::system::error_code ec) { 158773df0db0SJames Feist if (ec) 158873df0db0SJames Feist { 158973df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching " 159073df0db0SJames Feist << propertyName << ": " 159173df0db0SJames Feist << ec; 159273df0db0SJames Feist messages::internalError(response->res); 159373df0db0SJames Feist return; 159473df0db0SJames Feist } 159573df0db0SJames Feist messages::success(response->res); 159673df0db0SJames Feist }, 15976ee7f774SJames Feist "xyz.openbmc_project.EntityManager", path, 159873df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", iface, 159973df0db0SJames Feist property.first, property.second); 160073df0db0SJames Feist } 160173df0db0SJames Feist } 160273df0db0SJames Feist else 160373df0db0SJames Feist { 160473df0db0SJames Feist if (chassis.empty()) 160573df0db0SJames Feist { 160673df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config"; 160773df0db0SJames Feist messages::invalidObject(response->res, name); 160873df0db0SJames Feist return; 160973df0db0SJames Feist } 161073df0db0SJames Feist 161173df0db0SJames Feist bool foundChassis = false; 161273df0db0SJames Feist for (const auto& obj : managedObj) 161373df0db0SJames Feist { 161473df0db0SJames Feist if (boost::algorithm::ends_with(obj.first.str, chassis)) 161573df0db0SJames Feist { 161673df0db0SJames Feist chassis = obj.first.str; 161773df0db0SJames Feist foundChassis = true; 161873df0db0SJames Feist break; 161973df0db0SJames Feist } 162073df0db0SJames Feist } 162173df0db0SJames Feist if (!foundChassis) 162273df0db0SJames Feist { 162373df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to find chassis on dbus"; 162473df0db0SJames Feist messages::resourceMissingAtURI( 162573df0db0SJames Feist response->res, "/redfish/v1/Chassis/" + chassis); 162673df0db0SJames Feist return; 162773df0db0SJames Feist } 162873df0db0SJames Feist 162973df0db0SJames Feist crow::connections::systemBus->async_method_call( 163073df0db0SJames Feist [response](const boost::system::error_code ec) { 163173df0db0SJames Feist if (ec) 163273df0db0SJames Feist { 163373df0db0SJames Feist BMCWEB_LOG_ERROR << "Error Adding Pid Object " 163473df0db0SJames Feist << ec; 163573df0db0SJames Feist messages::internalError(response->res); 163673df0db0SJames Feist return; 163773df0db0SJames Feist } 163873df0db0SJames Feist messages::success(response->res); 163973df0db0SJames Feist }, 164073df0db0SJames Feist "xyz.openbmc_project.EntityManager", chassis, 164173df0db0SJames Feist "xyz.openbmc_project.AddObject", "AddObject", output); 164273df0db0SJames Feist } 164373df0db0SJames Feist } 164473df0db0SJames Feist } 164573df0db0SJames Feist } 164673df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 164773df0db0SJames Feist std::vector<std::pair<std::string, std::optional<nlohmann::json>>> 164873df0db0SJames Feist configuration; 164973df0db0SJames Feist std::optional<std::string> profile; 165073df0db0SJames Feist dbus::utility::ManagedObjectType managedObj; 165173df0db0SJames Feist std::vector<std::string> supportedProfiles; 165273df0db0SJames Feist std::string currentProfile; 165373df0db0SJames Feist std::string profileConnection; 165473df0db0SJames Feist std::string profilePath; 165514b0b8d5SJames Feist size_t objectCount = 0; 165673df0db0SJames Feist }; 165773df0db0SJames Feist 165873df0db0SJames Feist class Manager : public Node 165973df0db0SJames Feist { 166073df0db0SJames Feist public: 166173df0db0SJames Feist Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") 166273df0db0SJames Feist { 166373df0db0SJames Feist uuid = app.template getMiddleware<crow::persistent_data::Middleware>() 166473df0db0SJames Feist .systemUuid; 166573df0db0SJames Feist entityPrivileges = { 166673df0db0SJames Feist {boost::beast::http::verb::get, {{"Login"}}}, 166773df0db0SJames Feist {boost::beast::http::verb::head, {{"Login"}}}, 166873df0db0SJames Feist {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 166973df0db0SJames Feist {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 167073df0db0SJames Feist {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 167173df0db0SJames Feist {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 167273df0db0SJames Feist } 167373df0db0SJames Feist 167473df0db0SJames Feist private: 167555c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 16761abe55efSEd Tanous const std::vector<std::string>& params) override 16771abe55efSEd Tanous { 16780f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc"; 16794bf2b033SGunnar Mills res.jsonValue["@odata.type"] = "#Manager.v1_9_0.Manager"; 16800f74e643SEd Tanous res.jsonValue["Id"] = "bmc"; 16810f74e643SEd Tanous res.jsonValue["Name"] = "OpenBmc Manager"; 16820f74e643SEd Tanous res.jsonValue["Description"] = "Baseboard Management Controller"; 16830f74e643SEd Tanous res.jsonValue["PowerState"] = "On"; 1684029573d4SEd Tanous res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}}; 16850f74e643SEd Tanous res.jsonValue["ManagerType"] = "BMC"; 16863602e232SEd Tanous res.jsonValue["UUID"] = systemd_utils::getUuid(); 16873602e232SEd Tanous res.jsonValue["ServiceEntryPointUUID"] = uuid; 16880f74e643SEd Tanous res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model 16890f74e643SEd Tanous 16900f74e643SEd Tanous res.jsonValue["LogServices"] = { 16910f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}}; 16920f74e643SEd Tanous 16930f74e643SEd Tanous res.jsonValue["NetworkProtocol"] = { 16940f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}}; 16950f74e643SEd Tanous 16960f74e643SEd Tanous res.jsonValue["EthernetInterfaces"] = { 16970f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 1698107077deSPrzemyslaw Czarnowski 1699107077deSPrzemyslaw Czarnowski #ifdef BMCWEB_ENABLE_VM_NBDPROXY 1700107077deSPrzemyslaw Czarnowski res.jsonValue["VirtualMedia"] = { 1701107077deSPrzemyslaw Czarnowski {"@odata.id", "/redfish/v1/Managers/bmc/VirtualMedia"}}; 1702107077deSPrzemyslaw Czarnowski #endif // BMCWEB_ENABLE_VM_NBDPROXY 1703107077deSPrzemyslaw Czarnowski 17040f74e643SEd Tanous // default oem data 17050f74e643SEd Tanous nlohmann::json& oem = res.jsonValue["Oem"]; 17060f74e643SEd Tanous nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 17070f74e643SEd Tanous oem["@odata.type"] = "#OemManager.Oem"; 17080f74e643SEd Tanous oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 17090f74e643SEd Tanous oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 17100f74e643SEd Tanous oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 1711cfcd5f6bSMarri Devender Rao oemOpenbmc["Certificates"] = { 1712cfcd5f6bSMarri Devender Rao {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates"}}; 17130f74e643SEd Tanous 17142a5c4407SGunnar Mills // Manager.Reset (an action) can be many values, OpenBMC only supports 17152a5c4407SGunnar Mills // BMC reboot. 17162a5c4407SGunnar Mills nlohmann::json& managerReset = 17170f74e643SEd Tanous res.jsonValue["Actions"]["#Manager.Reset"]; 17182a5c4407SGunnar Mills managerReset["target"] = 1719ed5befbdSJennifer Lee "/redfish/v1/Managers/bmc/Actions/Manager.Reset"; 17201cb1a9e6SAppaRao Puli managerReset["@Redfish.ActionInfo"] = 17211cb1a9e6SAppaRao Puli "/redfish/v1/Managers/bmc/ResetActionInfo"; 1722ca537928SJennifer Lee 17233e40fc74SGunnar Mills // ResetToDefaults (Factory Reset) has values like 17243e40fc74SGunnar Mills // PreserveNetworkAndUsers and PreserveNetwork that aren't supported 17253e40fc74SGunnar Mills // on OpenBMC 17263e40fc74SGunnar Mills nlohmann::json& resetToDefaults = 17273e40fc74SGunnar Mills res.jsonValue["Actions"]["#Manager.ResetToDefaults"]; 17283e40fc74SGunnar Mills resetToDefaults["target"] = 17293e40fc74SGunnar Mills "/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults"; 17303e40fc74SGunnar Mills resetToDefaults["ResetType@Redfish.AllowableValues"] = {"ResetAll"}; 17313e40fc74SGunnar Mills 1732cb92c03bSAndrew Geissler res.jsonValue["DateTime"] = crow::utility::dateTimeNow(); 1733474bfad5SSantosh Puranik 1734f8c3e6f0SKuiying Wang // Fill in SerialConsole info 1735474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ServiceEnabled"] = true; 1736f8c3e6f0SKuiying Wang res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 1737474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {"IPMI", 1738474bfad5SSantosh Puranik "SSH"}; 1739ef47bb18SSantosh Puranik #ifdef BMCWEB_ENABLE_KVM 1740f8c3e6f0SKuiying Wang // Fill in GraphicalConsole info 1741ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 1742704fae6cSJae Hyun Yoo res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; 1743ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = {"KVMIP"}; 1744ef47bb18SSantosh Puranik #endif // BMCWEB_ENABLE_KVM 1745474bfad5SSantosh Puranik 1746603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers@odata.count"] = 1; 1747603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers"] = { 1748603a6640SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system"}}}; 174926f03899SShawn McCarney 1750ed5befbdSJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17515b4aa86bSJames Feist 1752b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 1753b49ac873SJames Feist health->isManagersHealth = true; 1754b49ac873SJames Feist health->populate(); 1755b49ac873SJames Feist 1756e90c5052SAndrew Geissler fw_util::getActiveFwVersion(asyncResp, fw_util::bmcPurpose, 1757*72d566d9SGunnar Mills "FirmwareVersion", true); 17580f6b00bdSJames Feist 17594bf2b033SGunnar Mills getLastResetTime(asyncResp); 17604bf2b033SGunnar Mills 176173df0db0SJames Feist auto pids = std::make_shared<GetPIDValues>(asyncResp); 176273df0db0SJames Feist pids->run(); 1763c5d03ff4SJennifer Lee 1764c5d03ff4SJennifer Lee getMainChassisId(asyncResp, [](const std::string& chassisId, 1765c5d03ff4SJennifer Lee const std::shared_ptr<AsyncResp> aRsp) { 1766c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] = 1; 1767c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis"] = { 1768c5d03ff4SJennifer Lee {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 17692c0feb00SJason M. Bills aRsp->res.jsonValue["Links"]["ManagerInChassis"] = { 17702c0feb00SJason M. Bills {"@odata.id", "/redfish/v1/Chassis/" + chassisId}}; 1771c5d03ff4SJennifer Lee }); 17720f6b00bdSJames Feist 17730f6b00bdSJames Feist static bool started = false; 17740f6b00bdSJames Feist 17750f6b00bdSJames Feist if (!started) 17760f6b00bdSJames Feist { 17770f6b00bdSJames Feist crow::connections::systemBus->async_method_call( 17780f6b00bdSJames Feist [asyncResp](const boost::system::error_code ec, 17790f6b00bdSJames Feist const std::variant<double>& resp) { 17800f6b00bdSJames Feist if (ec) 17810f6b00bdSJames Feist { 17820f6b00bdSJames Feist BMCWEB_LOG_ERROR << "Error while getting progress"; 17830f6b00bdSJames Feist messages::internalError(asyncResp->res); 17840f6b00bdSJames Feist return; 17850f6b00bdSJames Feist } 17860f6b00bdSJames Feist const double* val = std::get_if<double>(&resp); 17870f6b00bdSJames Feist if (val == nullptr) 17880f6b00bdSJames Feist { 17890f6b00bdSJames Feist BMCWEB_LOG_ERROR 17900f6b00bdSJames Feist << "Invalid response while getting progress"; 17910f6b00bdSJames Feist messages::internalError(asyncResp->res); 17920f6b00bdSJames Feist return; 17930f6b00bdSJames Feist } 17940f6b00bdSJames Feist if (*val < 1.0) 17950f6b00bdSJames Feist { 17960f6b00bdSJames Feist asyncResp->res.jsonValue["Status"]["State"] = 17970f6b00bdSJames Feist "Starting"; 17980f6b00bdSJames Feist started = true; 17990f6b00bdSJames Feist } 18000f6b00bdSJames Feist }, 18010f6b00bdSJames Feist "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 18020f6b00bdSJames Feist "org.freedesktop.DBus.Properties", "Get", 18030f6b00bdSJames Feist "org.freedesktop.systemd1.Manager", "Progress"); 18040f6b00bdSJames Feist } 180583ff9ab6SJames Feist } 18065b4aa86bSJames Feist 18075b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 18085b4aa86bSJames Feist const std::vector<std::string>& params) override 18095b4aa86bSJames Feist { 18100627a2c7SEd Tanous std::optional<nlohmann::json> oem; 1811af5d6058SSantosh Puranik std::optional<std::string> datetime; 181241352c24SSantosh Puranik std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 18130627a2c7SEd Tanous 181441352c24SSantosh Puranik if (!json_util::readJson(req, response->res, "Oem", oem, "DateTime", 181541352c24SSantosh Puranik datetime)) 181683ff9ab6SJames Feist { 181783ff9ab6SJames Feist return; 181883ff9ab6SJames Feist } 18190627a2c7SEd Tanous 18200627a2c7SEd Tanous if (oem) 182183ff9ab6SJames Feist { 18225f2caaefSJames Feist std::optional<nlohmann::json> openbmc; 182343b761d0SEd Tanous if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc)) 182483ff9ab6SJames Feist { 182543b761d0SEd Tanous BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 182643b761d0SEd Tanous << oem->dump(); 182783ff9ab6SJames Feist return; 182883ff9ab6SJames Feist } 18295f2caaefSJames Feist if (openbmc) 183083ff9ab6SJames Feist { 18315f2caaefSJames Feist std::optional<nlohmann::json> fan; 183243b761d0SEd Tanous if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan)) 183383ff9ab6SJames Feist { 18345f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 18355f2caaefSJames Feist << ", Illegal Property " 18365f2caaefSJames Feist << openbmc->dump(); 183783ff9ab6SJames Feist return; 183883ff9ab6SJames Feist } 18395f2caaefSJames Feist if (fan) 184083ff9ab6SJames Feist { 184173df0db0SJames Feist auto pid = std::make_shared<SetPIDValues>(response, *fan); 184273df0db0SJames Feist pid->run(); 184383ff9ab6SJames Feist } 184483ff9ab6SJames Feist } 184583ff9ab6SJames Feist } 1846af5d6058SSantosh Puranik if (datetime) 1847af5d6058SSantosh Puranik { 1848af5d6058SSantosh Puranik setDateTime(response, std::move(*datetime)); 1849af5d6058SSantosh Puranik } 1850af5d6058SSantosh Puranik } 1851af5d6058SSantosh Puranik 18524bf2b033SGunnar Mills void getLastResetTime(std::shared_ptr<AsyncResp> aResp) 18534bf2b033SGunnar Mills { 18544bf2b033SGunnar Mills BMCWEB_LOG_DEBUG << "Getting Manager Last Reset Time"; 18554bf2b033SGunnar Mills 18564bf2b033SGunnar Mills crow::connections::systemBus->async_method_call( 18574bf2b033SGunnar Mills [aResp](const boost::system::error_code ec, 18584bf2b033SGunnar Mills std::variant<uint64_t>& lastResetTime) { 18594bf2b033SGunnar Mills if (ec) 18604bf2b033SGunnar Mills { 18614bf2b033SGunnar Mills BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 18624bf2b033SGunnar Mills return; 18634bf2b033SGunnar Mills } 18644bf2b033SGunnar Mills 18654bf2b033SGunnar Mills const uint64_t* lastResetTimePtr = 18664bf2b033SGunnar Mills std::get_if<uint64_t>(&lastResetTime); 18674bf2b033SGunnar Mills 18684bf2b033SGunnar Mills if (!lastResetTimePtr) 18694bf2b033SGunnar Mills { 18704bf2b033SGunnar Mills messages::internalError(aResp->res); 18714bf2b033SGunnar Mills return; 18724bf2b033SGunnar Mills } 18734bf2b033SGunnar Mills // LastRebootTime is epoch time, in milliseconds 18744bf2b033SGunnar Mills // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19 18754bf2b033SGunnar Mills time_t lastResetTimeStamp = 18764bf2b033SGunnar Mills static_cast<time_t>(*lastResetTimePtr / 1000); 18774bf2b033SGunnar Mills 18784bf2b033SGunnar Mills // Convert to ISO 8601 standard 18794bf2b033SGunnar Mills aResp->res.jsonValue["LastResetTime"] = 18804bf2b033SGunnar Mills crow::utility::getDateTime(lastResetTimeStamp); 18814bf2b033SGunnar Mills }, 18824bf2b033SGunnar Mills "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0", 18834bf2b033SGunnar Mills "org.freedesktop.DBus.Properties", "Get", 18844bf2b033SGunnar Mills "xyz.openbmc_project.State.BMC", "LastRebootTime"); 18854bf2b033SGunnar Mills } 18864bf2b033SGunnar Mills 1887af5d6058SSantosh Puranik void setDateTime(std::shared_ptr<AsyncResp> aResp, 1888af5d6058SSantosh Puranik std::string datetime) const 1889af5d6058SSantosh Puranik { 1890af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Set date time: " << datetime; 1891af5d6058SSantosh Puranik 1892af5d6058SSantosh Puranik std::stringstream stream(datetime); 1893af5d6058SSantosh Puranik // Convert from ISO 8601 to boost local_time 1894af5d6058SSantosh Puranik // (BMC only has time in UTC) 1895af5d6058SSantosh Puranik boost::posix_time::ptime posixTime; 1896af5d6058SSantosh Puranik boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); 1897af5d6058SSantosh Puranik // Facet gets deleted with the stringsteam 1898af5d6058SSantosh Puranik auto ifc = std::make_unique<boost::local_time::local_time_input_facet>( 1899af5d6058SSantosh Puranik "%Y-%m-%d %H:%M:%S%F %ZP"); 1900af5d6058SSantosh Puranik stream.imbue(std::locale(stream.getloc(), ifc.release())); 1901af5d6058SSantosh Puranik 1902af5d6058SSantosh Puranik boost::local_time::local_date_time ldt( 1903af5d6058SSantosh Puranik boost::local_time::not_a_date_time); 1904af5d6058SSantosh Puranik 1905af5d6058SSantosh Puranik if (stream >> ldt) 1906af5d6058SSantosh Puranik { 1907af5d6058SSantosh Puranik posixTime = ldt.utc_time(); 1908af5d6058SSantosh Puranik boost::posix_time::time_duration dur = posixTime - epoch; 1909af5d6058SSantosh Puranik uint64_t durMicroSecs = 1910af5d6058SSantosh Puranik static_cast<uint64_t>(dur.total_microseconds()); 1911af5d6058SSantosh Puranik crow::connections::systemBus->async_method_call( 1912af5d6058SSantosh Puranik [aResp{std::move(aResp)}, datetime{std::move(datetime)}]( 1913af5d6058SSantosh Puranik const boost::system::error_code ec) { 1914af5d6058SSantosh Puranik if (ec) 1915af5d6058SSantosh Puranik { 1916af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Failed to set elapsed time. " 1917af5d6058SSantosh Puranik "DBUS response error " 1918af5d6058SSantosh Puranik << ec; 1919af5d6058SSantosh Puranik messages::internalError(aResp->res); 1920af5d6058SSantosh Puranik return; 1921af5d6058SSantosh Puranik } 1922af5d6058SSantosh Puranik aResp->res.jsonValue["DateTime"] = datetime; 1923af5d6058SSantosh Puranik }, 1924af5d6058SSantosh Puranik "xyz.openbmc_project.Time.Manager", 1925af5d6058SSantosh Puranik "/xyz/openbmc_project/time/bmc", 1926af5d6058SSantosh Puranik "org.freedesktop.DBus.Properties", "Set", 1927af5d6058SSantosh Puranik "xyz.openbmc_project.Time.EpochTime", "Elapsed", 1928af5d6058SSantosh Puranik std::variant<uint64_t>(durMicroSecs)); 1929af5d6058SSantosh Puranik } 1930af5d6058SSantosh Puranik else 1931af5d6058SSantosh Puranik { 1932af5d6058SSantosh Puranik messages::propertyValueFormatError(aResp->res, datetime, 1933af5d6058SSantosh Puranik "DateTime"); 1934af5d6058SSantosh Puranik return; 1935af5d6058SSantosh Puranik } 193683ff9ab6SJames Feist } 19379c310685SBorawski.Lukasz 19380f74e643SEd Tanous std::string uuid; 19399c310685SBorawski.Lukasz }; 19409c310685SBorawski.Lukasz 19411abe55efSEd Tanous class ManagerCollection : public Node 19421abe55efSEd Tanous { 19439c310685SBorawski.Lukasz public: 19441abe55efSEd Tanous ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") 19451abe55efSEd Tanous { 1946a434f2bdSEd Tanous entityPrivileges = { 1947a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 1948e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1949e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1950e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1951e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1952e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 19539c310685SBorawski.Lukasz } 19549c310685SBorawski.Lukasz 19559c310685SBorawski.Lukasz private: 195655c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 19571abe55efSEd Tanous const std::vector<std::string>& params) override 19581abe55efSEd Tanous { 195983ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 196083ff9ab6SJames Feist // because it has a duplicate entry for members 196155c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 196255c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 196355c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 196455c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 196555c7b7a2SEd Tanous res.jsonValue["Members"] = { 19665b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 19679c310685SBorawski.Lukasz res.end(); 19689c310685SBorawski.Lukasz } 19699c310685SBorawski.Lukasz }; 19709c310685SBorawski.Lukasz } // namespace redfish 1971