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 284bfefa74SGunnar Mills #include <cstdint> 291214b7e7SGunnar Mills #include <memory> 301214b7e7SGunnar Mills #include <sstream> 31abf2add6SEd Tanous #include <variant> 325b4aa86bSJames Feist 331abe55efSEd Tanous namespace redfish 341abe55efSEd Tanous { 35ed5befbdSJennifer Lee 36ed5befbdSJennifer Lee /** 372a5c4407SGunnar Mills * Function reboots the BMC. 382a5c4407SGunnar Mills * 392a5c4407SGunnar Mills * @param[in] asyncResp - Shared pointer for completing asynchronous calls 40ed5befbdSJennifer Lee */ 41*23a21a1cSEd Tanous inline void doBMCGracefulRestart(std::shared_ptr<AsyncResp> asyncResp) 42ed5befbdSJennifer Lee { 43ed5befbdSJennifer Lee const char* processName = "xyz.openbmc_project.State.BMC"; 44ed5befbdSJennifer Lee const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 45ed5befbdSJennifer Lee const char* interfaceName = "xyz.openbmc_project.State.BMC"; 46ed5befbdSJennifer Lee const std::string& propertyValue = 47ed5befbdSJennifer Lee "xyz.openbmc_project.State.BMC.Transition.Reboot"; 48ed5befbdSJennifer Lee const char* destProperty = "RequestedBMCTransition"; 49ed5befbdSJennifer Lee 50ed5befbdSJennifer Lee // Create the D-Bus variant for D-Bus call. 51ed5befbdSJennifer Lee VariantType dbusPropertyValue(propertyValue); 52ed5befbdSJennifer Lee 53ed5befbdSJennifer Lee crow::connections::systemBus->async_method_call( 54ed5befbdSJennifer Lee [asyncResp](const boost::system::error_code ec) { 55ed5befbdSJennifer Lee // Use "Set" method to set the property value. 56ed5befbdSJennifer Lee if (ec) 57ed5befbdSJennifer Lee { 582a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec; 59ed5befbdSJennifer Lee messages::internalError(asyncResp->res); 60ed5befbdSJennifer Lee return; 61ed5befbdSJennifer Lee } 62ed5befbdSJennifer Lee 63ed5befbdSJennifer Lee messages::success(asyncResp->res); 64ed5befbdSJennifer Lee }, 65ed5befbdSJennifer Lee processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 66ed5befbdSJennifer Lee interfaceName, destProperty, dbusPropertyValue); 67ed5befbdSJennifer Lee } 682a5c4407SGunnar Mills 692a5c4407SGunnar Mills /** 702a5c4407SGunnar Mills * ManagerResetAction class supports the POST method for the Reset (reboot) 712a5c4407SGunnar Mills * action. 722a5c4407SGunnar Mills */ 732a5c4407SGunnar Mills class ManagerResetAction : public Node 742a5c4407SGunnar Mills { 752a5c4407SGunnar Mills public: 7652cc112dSEd Tanous ManagerResetAction(App& app) : 772a5c4407SGunnar Mills Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/") 782a5c4407SGunnar Mills { 792a5c4407SGunnar Mills entityPrivileges = { 802a5c4407SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 812a5c4407SGunnar Mills } 822a5c4407SGunnar Mills 832a5c4407SGunnar Mills private: 842a5c4407SGunnar Mills /** 852a5c4407SGunnar Mills * Function handles POST method request. 862a5c4407SGunnar Mills * Analyzes POST body before sending Reset (Reboot) request data to D-Bus. 872a5c4407SGunnar Mills * OpenBMC only supports ResetType "GracefulRestart". 882a5c4407SGunnar Mills */ 892a5c4407SGunnar Mills void doPost(crow::Response& res, const crow::Request& req, 902a5c4407SGunnar Mills const std::vector<std::string>& params) override 912a5c4407SGunnar Mills { 922a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Post Manager Reset."; 932a5c4407SGunnar Mills 942a5c4407SGunnar Mills std::string resetType; 952a5c4407SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 962a5c4407SGunnar Mills 972a5c4407SGunnar Mills if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 982a5c4407SGunnar Mills { 992a5c4407SGunnar Mills return; 1002a5c4407SGunnar Mills } 1012a5c4407SGunnar Mills 1022a5c4407SGunnar Mills if (resetType != "GracefulRestart") 1032a5c4407SGunnar Mills { 1042a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 1052a5c4407SGunnar Mills << resetType; 1062a5c4407SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 1072a5c4407SGunnar Mills "ResetType"); 1082a5c4407SGunnar Mills 1092a5c4407SGunnar Mills return; 1102a5c4407SGunnar Mills } 1112a5c4407SGunnar Mills doBMCGracefulRestart(asyncResp); 1122a5c4407SGunnar Mills } 113ed5befbdSJennifer Lee }; 114ed5befbdSJennifer Lee 1153e40fc74SGunnar Mills /** 1163e40fc74SGunnar Mills * ManagerResetToDefaultsAction class supports POST method for factory reset 1173e40fc74SGunnar Mills * action. 1183e40fc74SGunnar Mills */ 1193e40fc74SGunnar Mills class ManagerResetToDefaultsAction : public Node 1203e40fc74SGunnar Mills { 1213e40fc74SGunnar Mills public: 12252cc112dSEd Tanous ManagerResetToDefaultsAction(App& app) : 1233e40fc74SGunnar Mills Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults/") 1243e40fc74SGunnar Mills { 1253e40fc74SGunnar Mills entityPrivileges = { 1263e40fc74SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 1273e40fc74SGunnar Mills } 1283e40fc74SGunnar Mills 1293e40fc74SGunnar Mills private: 1303e40fc74SGunnar Mills /** 1313e40fc74SGunnar Mills * Function handles ResetToDefaults POST method request. 1323e40fc74SGunnar Mills * 1333e40fc74SGunnar Mills * Analyzes POST body message and factory resets BMC by calling 1343e40fc74SGunnar Mills * BMC code updater factory reset followed by a BMC reboot. 1353e40fc74SGunnar Mills * 1363e40fc74SGunnar Mills * BMC code updater factory reset wipes the whole BMC read-write 1373e40fc74SGunnar Mills * filesystem which includes things like the network settings. 1383e40fc74SGunnar Mills * 1393e40fc74SGunnar Mills * OpenBMC only supports ResetToDefaultsType "ResetAll". 1403e40fc74SGunnar Mills */ 1413e40fc74SGunnar Mills void doPost(crow::Response& res, const crow::Request& req, 1423e40fc74SGunnar Mills const std::vector<std::string>& params) override 1433e40fc74SGunnar Mills { 1443e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Post ResetToDefaults."; 1453e40fc74SGunnar Mills 1463e40fc74SGunnar Mills std::string resetType; 1473e40fc74SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 1483e40fc74SGunnar Mills 1493e40fc74SGunnar Mills if (!json_util::readJson(req, asyncResp->res, "ResetToDefaultsType", 1503e40fc74SGunnar Mills resetType)) 1513e40fc74SGunnar Mills { 1523e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Missing property ResetToDefaultsType."; 1533e40fc74SGunnar Mills 1543e40fc74SGunnar Mills messages::actionParameterMissing(asyncResp->res, "ResetToDefaults", 1553e40fc74SGunnar Mills "ResetToDefaultsType"); 1563e40fc74SGunnar Mills return; 1573e40fc74SGunnar Mills } 1583e40fc74SGunnar Mills 1593e40fc74SGunnar Mills if (resetType != "ResetAll") 1603e40fc74SGunnar Mills { 1613e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid property value for " 1623e40fc74SGunnar Mills "ResetToDefaultsType: " 1633e40fc74SGunnar Mills << resetType; 1643e40fc74SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 1653e40fc74SGunnar Mills "ResetToDefaultsType"); 1663e40fc74SGunnar Mills return; 1673e40fc74SGunnar Mills } 1683e40fc74SGunnar Mills 1693e40fc74SGunnar Mills crow::connections::systemBus->async_method_call( 1703e40fc74SGunnar Mills [asyncResp](const boost::system::error_code ec) { 1713e40fc74SGunnar Mills if (ec) 1723e40fc74SGunnar Mills { 1733e40fc74SGunnar Mills BMCWEB_LOG_DEBUG << "Failed to ResetToDefaults: " << ec; 1743e40fc74SGunnar Mills messages::internalError(asyncResp->res); 1753e40fc74SGunnar Mills return; 1763e40fc74SGunnar Mills } 1773e40fc74SGunnar Mills // Factory Reset doesn't actually happen until a reboot 1783e40fc74SGunnar Mills // Can't erase what the BMC is running on 1793e40fc74SGunnar Mills doBMCGracefulRestart(asyncResp); 1803e40fc74SGunnar Mills }, 1813e40fc74SGunnar Mills "xyz.openbmc_project.Software.BMC.Updater", 1823e40fc74SGunnar Mills "/xyz/openbmc_project/software", 1833e40fc74SGunnar Mills "xyz.openbmc_project.Common.FactoryReset", "Reset"); 1843e40fc74SGunnar Mills } 1853e40fc74SGunnar Mills }; 1863e40fc74SGunnar Mills 1871cb1a9e6SAppaRao Puli /** 1881cb1a9e6SAppaRao Puli * ManagerResetActionInfo derived class for delivering Manager 1891cb1a9e6SAppaRao Puli * ResetType AllowableValues using ResetInfo schema. 1901cb1a9e6SAppaRao Puli */ 1911cb1a9e6SAppaRao Puli class ManagerResetActionInfo : public Node 1921cb1a9e6SAppaRao Puli { 1931cb1a9e6SAppaRao Puli public: 1941cb1a9e6SAppaRao Puli /* 1951cb1a9e6SAppaRao Puli * Default Constructor 1961cb1a9e6SAppaRao Puli */ 19752cc112dSEd Tanous ManagerResetActionInfo(App& app) : 1981cb1a9e6SAppaRao Puli Node(app, "/redfish/v1/Managers/bmc/ResetActionInfo/") 1991cb1a9e6SAppaRao Puli { 2001cb1a9e6SAppaRao Puli entityPrivileges = { 2011cb1a9e6SAppaRao Puli {boost::beast::http::verb::get, {{"Login"}}}, 2021cb1a9e6SAppaRao Puli {boost::beast::http::verb::head, {{"Login"}}}, 2031cb1a9e6SAppaRao Puli {boost::beast::http::verb::patch, {{"ConfigureComponents"}}}, 2041cb1a9e6SAppaRao Puli {boost::beast::http::verb::put, {{"ConfigureComponents"}}}, 2051cb1a9e6SAppaRao Puli {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}}, 2061cb1a9e6SAppaRao Puli {boost::beast::http::verb::post, {{"ConfigureComponents"}}}}; 2071cb1a9e6SAppaRao Puli } 2081cb1a9e6SAppaRao Puli 2091cb1a9e6SAppaRao Puli private: 2101cb1a9e6SAppaRao Puli /** 2111cb1a9e6SAppaRao Puli * Functions triggers appropriate requests on DBus 2121cb1a9e6SAppaRao Puli */ 2131cb1a9e6SAppaRao Puli void doGet(crow::Response& res, const crow::Request& req, 2141cb1a9e6SAppaRao Puli const std::vector<std::string>& params) override 2151cb1a9e6SAppaRao Puli { 2161cb1a9e6SAppaRao Puli res.jsonValue = { 2171cb1a9e6SAppaRao Puli {"@odata.type", "#ActionInfo.v1_1_2.ActionInfo"}, 2181cb1a9e6SAppaRao Puli {"@odata.id", "/redfish/v1/Managers/bmc/ResetActionInfo"}, 2191cb1a9e6SAppaRao Puli {"Name", "Reset Action Info"}, 2201cb1a9e6SAppaRao Puli {"Id", "ResetActionInfo"}, 2211cb1a9e6SAppaRao Puli {"Parameters", 2221cb1a9e6SAppaRao Puli {{{"Name", "ResetType"}, 2231cb1a9e6SAppaRao Puli {"Required", true}, 2241cb1a9e6SAppaRao Puli {"DataType", "String"}, 2251cb1a9e6SAppaRao Puli {"AllowableValues", {"GracefulRestart"}}}}}}; 2261cb1a9e6SAppaRao Puli res.end(); 2271cb1a9e6SAppaRao Puli } 2281cb1a9e6SAppaRao Puli }; 2291cb1a9e6SAppaRao Puli 2305b4aa86bSJames Feist static constexpr const char* objectManagerIface = 2315b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 2325b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 2335b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 2345b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 2355b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 236b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface = 237b7a08d04SJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 23873df0db0SJames Feist static constexpr const char* thermalModeIface = 23973df0db0SJames Feist "xyz.openbmc_project.Control.ThermalMode"; 2409c310685SBorawski.Lukasz 241*23a21a1cSEd Tanous inline void asyncPopulatePid(const std::string& connection, 2425b4aa86bSJames Feist const std::string& path, 24373df0db0SJames Feist const std::string& currentProfile, 24473df0db0SJames Feist const std::vector<std::string>& supportedProfiles, 2455b4aa86bSJames Feist std::shared_ptr<AsyncResp> asyncResp) 2465b4aa86bSJames Feist { 2475b4aa86bSJames Feist 2485b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 24973df0db0SJames Feist [asyncResp, currentProfile, supportedProfiles]( 25073df0db0SJames Feist const boost::system::error_code ec, 2515b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 2525b4aa86bSJames Feist if (ec) 2535b4aa86bSJames Feist { 2545b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 2555b4aa86bSJames Feist asyncResp->res.jsonValue.clear(); 256f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2575b4aa86bSJames Feist return; 2585b4aa86bSJames Feist } 2595b4aa86bSJames Feist nlohmann::json& configRoot = 2605b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 2615b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 2625b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 2635b4aa86bSJames Feist fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" 2645b4aa86bSJames Feist "Fan/FanControllers"; 2655b4aa86bSJames Feist 2665b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 2675b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 2685b4aa86bSJames Feist pids["@odata.id"] = 2695b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; 2705b4aa86bSJames Feist 271b7a08d04SJames Feist nlohmann::json& stepwise = configRoot["StepwiseControllers"]; 272b7a08d04SJames Feist stepwise["@odata.type"] = "#OemManager.StepwiseControllers"; 273b7a08d04SJames Feist stepwise["@odata.id"] = 274b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers"; 275b7a08d04SJames Feist 2765b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 2775b4aa86bSJames Feist zones["@odata.id"] = 2785b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; 2795b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 2805b4aa86bSJames Feist configRoot["@odata.id"] = 2815b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; 2825b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 28373df0db0SJames Feist configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles; 28473df0db0SJames Feist 28573df0db0SJames Feist if (!currentProfile.empty()) 28673df0db0SJames Feist { 28773df0db0SJames Feist configRoot["Profile"] = currentProfile; 28873df0db0SJames Feist } 28973df0db0SJames Feist BMCWEB_LOG_ERROR << "profile = " << currentProfile << " !"; 2905b4aa86bSJames Feist 2915b4aa86bSJames Feist for (const auto& pathPair : managedObj) 2925b4aa86bSJames Feist { 2935b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 2945b4aa86bSJames Feist { 2955b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 296b7a08d04SJames Feist intfPair.first != pidZoneConfigurationIface && 297b7a08d04SJames Feist intfPair.first != stepwiseConfigurationIface) 2985b4aa86bSJames Feist { 2995b4aa86bSJames Feist continue; 3005b4aa86bSJames Feist } 3015b4aa86bSJames Feist auto findName = intfPair.second.find("Name"); 3025b4aa86bSJames Feist if (findName == intfPair.second.end()) 3035b4aa86bSJames Feist { 3045b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Field missing Name"; 305a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 3065b4aa86bSJames Feist return; 3075b4aa86bSJames Feist } 30873df0db0SJames Feist 3095b4aa86bSJames Feist const std::string* namePtr = 310abf2add6SEd Tanous std::get_if<std::string>(&findName->second); 3115b4aa86bSJames Feist if (namePtr == nullptr) 3125b4aa86bSJames Feist { 3135b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Name Field illegal"; 314b7a08d04SJames Feist messages::internalError(asyncResp->res); 3155b4aa86bSJames Feist return; 3165b4aa86bSJames Feist } 3175b4aa86bSJames Feist std::string name = *namePtr; 3185b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 31973df0db0SJames Feist 32073df0db0SJames Feist auto findProfiles = intfPair.second.find("Profiles"); 32173df0db0SJames Feist if (findProfiles != intfPair.second.end()) 32273df0db0SJames Feist { 32373df0db0SJames Feist const std::vector<std::string>* profiles = 32473df0db0SJames Feist std::get_if<std::vector<std::string>>( 32573df0db0SJames Feist &findProfiles->second); 32673df0db0SJames Feist if (profiles == nullptr) 32773df0db0SJames Feist { 32873df0db0SJames Feist BMCWEB_LOG_ERROR << "Pid Profiles Field illegal"; 32973df0db0SJames Feist messages::internalError(asyncResp->res); 33073df0db0SJames Feist return; 33173df0db0SJames Feist } 33273df0db0SJames Feist if (std::find(profiles->begin(), profiles->end(), 33373df0db0SJames Feist currentProfile) == profiles->end()) 33473df0db0SJames Feist { 33573df0db0SJames Feist BMCWEB_LOG_INFO 33673df0db0SJames Feist << name << " not supported in current profile"; 33773df0db0SJames Feist continue; 33873df0db0SJames Feist } 33973df0db0SJames Feist } 340b7a08d04SJames Feist nlohmann::json* config = nullptr; 341c33a90ecSJames Feist 342c33a90ecSJames Feist const std::string* classPtr = nullptr; 343c33a90ecSJames Feist auto findClass = intfPair.second.find("Class"); 344c33a90ecSJames Feist if (findClass != intfPair.second.end()) 345c33a90ecSJames Feist { 346c33a90ecSJames Feist classPtr = std::get_if<std::string>(&findClass->second); 347c33a90ecSJames Feist } 348c33a90ecSJames Feist 3495b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 3505b4aa86bSJames Feist { 3515b4aa86bSJames Feist std::string chassis; 3525b4aa86bSJames Feist if (!dbus::utility::getNthStringFromPath( 3535b4aa86bSJames Feist pathPair.first.str, 5, chassis)) 3545b4aa86bSJames Feist { 3555b4aa86bSJames Feist chassis = "#IllegalValue"; 3565b4aa86bSJames Feist } 3575b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 3585b4aa86bSJames Feist zone["Chassis"] = { 3595b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; 3605b4aa86bSJames Feist zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" 3615b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 3625b4aa86bSJames Feist name; 3635b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 364b7a08d04SJames Feist config = &zone; 3655b4aa86bSJames Feist } 3665b4aa86bSJames Feist 367b7a08d04SJames Feist else if (intfPair.first == stepwiseConfigurationIface) 3685b4aa86bSJames Feist { 369c33a90ecSJames Feist if (classPtr == nullptr) 370c33a90ecSJames Feist { 371c33a90ecSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 372c33a90ecSJames Feist messages::internalError(asyncResp->res); 373c33a90ecSJames Feist return; 374c33a90ecSJames Feist } 375c33a90ecSJames Feist 376b7a08d04SJames Feist nlohmann::json& controller = stepwise[name]; 377b7a08d04SJames Feist config = &controller; 3785b4aa86bSJames Feist 379b7a08d04SJames Feist controller["@odata.id"] = 380b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/" 381b7a08d04SJames Feist "OpenBmc/Fan/StepwiseControllers/" + 382271584abSEd Tanous name; 383b7a08d04SJames Feist controller["@odata.type"] = 384b7a08d04SJames Feist "#OemManager.StepwiseController"; 385b7a08d04SJames Feist 386c33a90ecSJames Feist controller["Direction"] = *classPtr; 3875b4aa86bSJames Feist } 3885b4aa86bSJames Feist 3895b4aa86bSJames Feist // pid and fans are off the same configuration 390b7a08d04SJames Feist else if (intfPair.first == pidConfigurationIface) 3915b4aa86bSJames Feist { 392c33a90ecSJames Feist 3935b4aa86bSJames Feist if (classPtr == nullptr) 3945b4aa86bSJames Feist { 3955b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 396a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 3975b4aa86bSJames Feist return; 3985b4aa86bSJames Feist } 3995b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 4005b4aa86bSJames Feist nlohmann::json& element = 4015b4aa86bSJames Feist isFan ? fans[name] : pids[name]; 402b7a08d04SJames Feist config = &element; 4035b4aa86bSJames Feist if (isFan) 4045b4aa86bSJames Feist { 4055b4aa86bSJames Feist element["@odata.id"] = 4065b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 4075b4aa86bSJames Feist "OpenBmc/Fan/FanControllers/" + 408271584abSEd Tanous name; 4095b4aa86bSJames Feist element["@odata.type"] = 4105b4aa86bSJames Feist "#OemManager.FanController"; 4115b4aa86bSJames Feist } 4125b4aa86bSJames Feist else 4135b4aa86bSJames Feist { 4145b4aa86bSJames Feist element["@odata.id"] = 4155b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 4165b4aa86bSJames Feist "OpenBmc/Fan/PidControllers/" + 417271584abSEd Tanous name; 4185b4aa86bSJames Feist element["@odata.type"] = 4195b4aa86bSJames Feist "#OemManager.PidController"; 4205b4aa86bSJames Feist } 421b7a08d04SJames Feist } 422b7a08d04SJames Feist else 423b7a08d04SJames Feist { 424b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Unexpected configuration"; 425b7a08d04SJames Feist messages::internalError(asyncResp->res); 426b7a08d04SJames Feist return; 427b7a08d04SJames Feist } 428b7a08d04SJames Feist 429b7a08d04SJames Feist // used for making maps out of 2 vectors 430b7a08d04SJames Feist const std::vector<double>* keys = nullptr; 431b7a08d04SJames Feist const std::vector<double>* values = nullptr; 432b7a08d04SJames Feist 433b7a08d04SJames Feist for (const auto& propertyPair : intfPair.second) 434b7a08d04SJames Feist { 435b7a08d04SJames Feist if (propertyPair.first == "Type" || 436b7a08d04SJames Feist propertyPair.first == "Class" || 437b7a08d04SJames Feist propertyPair.first == "Name") 438b7a08d04SJames Feist { 439b7a08d04SJames Feist continue; 440b7a08d04SJames Feist } 441b7a08d04SJames Feist 442b7a08d04SJames Feist // zones 443b7a08d04SJames Feist if (intfPair.first == pidZoneConfigurationIface) 444b7a08d04SJames Feist { 445b7a08d04SJames Feist const double* ptr = 446abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 447b7a08d04SJames Feist if (ptr == nullptr) 448b7a08d04SJames Feist { 449b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 450b7a08d04SJames Feist << propertyPair.first; 451b7a08d04SJames Feist messages::internalError(asyncResp->res); 452b7a08d04SJames Feist return; 453b7a08d04SJames Feist } 454b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 455b7a08d04SJames Feist } 456b7a08d04SJames Feist 457b7a08d04SJames Feist if (intfPair.first == stepwiseConfigurationIface) 458b7a08d04SJames Feist { 459b7a08d04SJames Feist if (propertyPair.first == "Reading" || 460b7a08d04SJames Feist propertyPair.first == "Output") 461b7a08d04SJames Feist { 462b7a08d04SJames Feist const std::vector<double>* ptr = 463abf2add6SEd Tanous std::get_if<std::vector<double>>( 464b7a08d04SJames Feist &propertyPair.second); 465b7a08d04SJames Feist 466b7a08d04SJames Feist if (ptr == nullptr) 467b7a08d04SJames Feist { 468b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 469b7a08d04SJames Feist << propertyPair.first; 470b7a08d04SJames Feist messages::internalError(asyncResp->res); 471b7a08d04SJames Feist return; 472b7a08d04SJames Feist } 473b7a08d04SJames Feist 474b7a08d04SJames Feist if (propertyPair.first == "Reading") 475b7a08d04SJames Feist { 476b7a08d04SJames Feist keys = ptr; 477b7a08d04SJames Feist } 478b7a08d04SJames Feist else 479b7a08d04SJames Feist { 480b7a08d04SJames Feist values = ptr; 481b7a08d04SJames Feist } 482b7a08d04SJames Feist if (keys && values) 483b7a08d04SJames Feist { 484b7a08d04SJames Feist if (keys->size() != values->size()) 485b7a08d04SJames Feist { 486b7a08d04SJames Feist BMCWEB_LOG_ERROR 487b7a08d04SJames Feist << "Reading and Output size don't " 488b7a08d04SJames Feist "match "; 489b7a08d04SJames Feist messages::internalError(asyncResp->res); 490b7a08d04SJames Feist return; 491b7a08d04SJames Feist } 492b7a08d04SJames Feist nlohmann::json& steps = (*config)["Steps"]; 493b7a08d04SJames Feist steps = nlohmann::json::array(); 494b7a08d04SJames Feist for (size_t ii = 0; ii < keys->size(); ii++) 495b7a08d04SJames Feist { 496b7a08d04SJames Feist steps.push_back( 497b7a08d04SJames Feist {{"Target", (*keys)[ii]}, 498b7a08d04SJames Feist {"Output", (*values)[ii]}}); 499b7a08d04SJames Feist } 500b7a08d04SJames Feist } 501b7a08d04SJames Feist } 502b7a08d04SJames Feist if (propertyPair.first == "NegativeHysteresis" || 503b7a08d04SJames Feist propertyPair.first == "PositiveHysteresis") 504b7a08d04SJames Feist { 505b7a08d04SJames Feist const double* ptr = 506abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 507b7a08d04SJames Feist if (ptr == nullptr) 508b7a08d04SJames Feist { 509b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 510b7a08d04SJames Feist << propertyPair.first; 511b7a08d04SJames Feist messages::internalError(asyncResp->res); 512b7a08d04SJames Feist return; 513b7a08d04SJames Feist } 514b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 515b7a08d04SJames Feist } 516b7a08d04SJames Feist } 517b7a08d04SJames Feist 518b7a08d04SJames Feist // pid and fans are off the same configuration 519b7a08d04SJames Feist if (intfPair.first == pidConfigurationIface || 520b7a08d04SJames Feist intfPair.first == stepwiseConfigurationIface) 521b7a08d04SJames Feist { 5225b4aa86bSJames Feist 5235b4aa86bSJames Feist if (propertyPair.first == "Zones") 5245b4aa86bSJames Feist { 5255b4aa86bSJames Feist const std::vector<std::string>* inputs = 526abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 5271b6b96c5SEd Tanous &propertyPair.second); 5285b4aa86bSJames Feist 5295b4aa86bSJames Feist if (inputs == nullptr) 5305b4aa86bSJames Feist { 5315b4aa86bSJames Feist BMCWEB_LOG_ERROR 5325b4aa86bSJames Feist << "Zones Pid Field Illegal"; 533a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 5345b4aa86bSJames Feist return; 5355b4aa86bSJames Feist } 536b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 5375b4aa86bSJames Feist data = nlohmann::json::array(); 5385b4aa86bSJames Feist for (std::string itemCopy : *inputs) 5395b4aa86bSJames Feist { 5405b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 5415b4aa86bSJames Feist data.push_back( 5425b4aa86bSJames Feist {{"@odata.id", 5435b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 5445b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 5455b4aa86bSJames Feist itemCopy}}); 5465b4aa86bSJames Feist } 5475b4aa86bSJames Feist } 5485b4aa86bSJames Feist // todo(james): may never happen, but this 5495b4aa86bSJames Feist // assumes configuration data referenced in the 5505b4aa86bSJames Feist // PID config is provided by the same daemon, we 5515b4aa86bSJames Feist // could add another loop to cover all cases, 5525b4aa86bSJames Feist // but I'm okay kicking this can down the road a 5535b4aa86bSJames Feist // bit 5545b4aa86bSJames Feist 5555b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 5565b4aa86bSJames Feist propertyPair.first == "Outputs") 5575b4aa86bSJames Feist { 558b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 5595b4aa86bSJames Feist const std::vector<std::string>* inputs = 560abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 5611b6b96c5SEd Tanous &propertyPair.second); 5625b4aa86bSJames Feist 5635b4aa86bSJames Feist if (inputs == nullptr) 5645b4aa86bSJames Feist { 5655b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 5665b4aa86bSJames Feist << propertyPair.first; 567f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5685b4aa86bSJames Feist return; 5695b4aa86bSJames Feist } 5705b4aa86bSJames Feist data = *inputs; 571b943aaefSJames Feist } 572b943aaefSJames Feist else if (propertyPair.first == "SetPointOffset") 573b943aaefSJames Feist { 574b943aaefSJames Feist const std::string* ptr = 575b943aaefSJames Feist std::get_if<std::string>( 576b943aaefSJames Feist &propertyPair.second); 577b943aaefSJames Feist 578b943aaefSJames Feist if (ptr == nullptr) 579b943aaefSJames Feist { 580b943aaefSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 581b943aaefSJames Feist << propertyPair.first; 582b943aaefSJames Feist messages::internalError(asyncResp->res); 583b943aaefSJames Feist return; 584b943aaefSJames Feist } 585b943aaefSJames Feist // translate from dbus to redfish 586b943aaefSJames Feist if (*ptr == "WarningHigh") 587b943aaefSJames Feist { 588b943aaefSJames Feist (*config)["SetPointOffset"] = 589b943aaefSJames Feist "UpperThresholdNonCritical"; 590b943aaefSJames Feist } 591b943aaefSJames Feist else if (*ptr == "WarningLow") 592b943aaefSJames Feist { 593b943aaefSJames Feist (*config)["SetPointOffset"] = 594b943aaefSJames Feist "LowerThresholdNonCritical"; 595b943aaefSJames Feist } 596b943aaefSJames Feist else if (*ptr == "CriticalHigh") 597b943aaefSJames Feist { 598b943aaefSJames Feist (*config)["SetPointOffset"] = 599b943aaefSJames Feist "UpperThresholdCritical"; 600b943aaefSJames Feist } 601b943aaefSJames Feist else if (*ptr == "CriticalLow") 602b943aaefSJames Feist { 603b943aaefSJames Feist (*config)["SetPointOffset"] = 604b943aaefSJames Feist "LowerThresholdCritical"; 605b943aaefSJames Feist } 606b943aaefSJames Feist else 607b943aaefSJames Feist { 608b943aaefSJames Feist BMCWEB_LOG_ERROR << "Value Illegal " 609b943aaefSJames Feist << *ptr; 610b943aaefSJames Feist messages::internalError(asyncResp->res); 611b943aaefSJames Feist return; 612b943aaefSJames Feist } 613b943aaefSJames Feist } 614b943aaefSJames Feist // doubles 6155b4aa86bSJames Feist else if (propertyPair.first == 6165b4aa86bSJames Feist "FFGainCoefficient" || 6175b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 6185b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 6195b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 6205b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 621aad1a257SJames Feist propertyPair.first == 622aad1a257SJames Feist "PositiveHysteresis" || 623aad1a257SJames Feist propertyPair.first == 624aad1a257SJames Feist "NegativeHysteresis" || 6255b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 6265b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 6275b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 6287625cb81SJames Feist propertyPair.first == "SetPoint" || 6295b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 6305b4aa86bSJames Feist propertyPair.first == "SlewPos") 6315b4aa86bSJames Feist { 6325b4aa86bSJames Feist const double* ptr = 633abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 6345b4aa86bSJames Feist if (ptr == nullptr) 6355b4aa86bSJames Feist { 6365b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 6375b4aa86bSJames Feist << propertyPair.first; 638f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6395b4aa86bSJames Feist return; 6405b4aa86bSJames Feist } 641b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 6425b4aa86bSJames Feist } 6435b4aa86bSJames Feist } 6445b4aa86bSJames Feist } 6455b4aa86bSJames Feist } 6465b4aa86bSJames Feist } 6475b4aa86bSJames Feist }, 6485b4aa86bSJames Feist connection, path, objectManagerIface, "GetManagedObjects"); 6495b4aa86bSJames Feist } 650ca537928SJennifer Lee 65183ff9ab6SJames Feist enum class CreatePIDRet 65283ff9ab6SJames Feist { 65383ff9ab6SJames Feist fail, 65483ff9ab6SJames Feist del, 65583ff9ab6SJames Feist patch 65683ff9ab6SJames Feist }; 65783ff9ab6SJames Feist 658*23a21a1cSEd Tanous inline bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response, 6595f2caaefSJames Feist std::vector<nlohmann::json>& config, 6605f2caaefSJames Feist std::vector<std::string>& zones) 6615f2caaefSJames Feist { 662b6baeaa4SJames Feist if (config.empty()) 663b6baeaa4SJames Feist { 664b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Empty Zones"; 665b6baeaa4SJames Feist messages::propertyValueFormatError(response->res, 666b6baeaa4SJames Feist nlohmann::json::array(), "Zones"); 667b6baeaa4SJames Feist return false; 668b6baeaa4SJames Feist } 6695f2caaefSJames Feist for (auto& odata : config) 6705f2caaefSJames Feist { 6715f2caaefSJames Feist std::string path; 6725f2caaefSJames Feist if (!redfish::json_util::readJson(odata, response->res, "@odata.id", 6735f2caaefSJames Feist path)) 6745f2caaefSJames Feist { 6755f2caaefSJames Feist return false; 6765f2caaefSJames Feist } 6775f2caaefSJames Feist std::string input; 67861adbda3SJames Feist 67961adbda3SJames Feist // 8 below comes from 68061adbda3SJames Feist // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left 68161adbda3SJames Feist // 0 1 2 3 4 5 6 7 8 68261adbda3SJames Feist if (!dbus::utility::getNthStringFromPath(path, 8, input)) 6835f2caaefSJames Feist { 6845f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << path; 6855f2caaefSJames Feist BMCWEB_LOG_ERROR << "Illegal Type Zones"; 6865f2caaefSJames Feist messages::propertyValueFormatError(response->res, odata.dump(), 6875f2caaefSJames Feist "Zones"); 6885f2caaefSJames Feist return false; 6895f2caaefSJames Feist } 6905f2caaefSJames Feist boost::replace_all(input, "_", " "); 6915f2caaefSJames Feist zones.emplace_back(std::move(input)); 6925f2caaefSJames Feist } 6935f2caaefSJames Feist return true; 6945f2caaefSJames Feist } 6955f2caaefSJames Feist 696*23a21a1cSEd Tanous inline const dbus::utility::ManagedItem* 69773df0db0SJames Feist findChassis(const dbus::utility::ManagedObjectType& managedObj, 698b6baeaa4SJames Feist const std::string& value, std::string& chassis) 699b6baeaa4SJames Feist { 700b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n"; 701b6baeaa4SJames Feist 702b6baeaa4SJames Feist std::string escaped = boost::replace_all_copy(value, " ", "_"); 703b6baeaa4SJames Feist escaped = "/" + escaped; 704b6baeaa4SJames Feist auto it = std::find_if( 705b6baeaa4SJames Feist managedObj.begin(), managedObj.end(), [&escaped](const auto& obj) { 706b6baeaa4SJames Feist if (boost::algorithm::ends_with(obj.first.str, escaped)) 707b6baeaa4SJames Feist { 708b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Matched " << obj.first.str << "\n"; 709b6baeaa4SJames Feist return true; 710b6baeaa4SJames Feist } 711b6baeaa4SJames Feist return false; 712b6baeaa4SJames Feist }); 713b6baeaa4SJames Feist 714b6baeaa4SJames Feist if (it == managedObj.end()) 715b6baeaa4SJames Feist { 71673df0db0SJames Feist return nullptr; 717b6baeaa4SJames Feist } 718b6baeaa4SJames Feist // 5 comes from <chassis-name> being the 5th element 719b6baeaa4SJames Feist // /xyz/openbmc_project/inventory/system/chassis/<chassis-name> 72073df0db0SJames Feist if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis)) 72173df0db0SJames Feist { 72273df0db0SJames Feist return &(*it); 72373df0db0SJames Feist } 72473df0db0SJames Feist 72573df0db0SJames Feist return nullptr; 726b6baeaa4SJames Feist } 727b6baeaa4SJames Feist 728*23a21a1cSEd Tanous inline CreatePIDRet createPidInterface( 72983ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 730b6baeaa4SJames Feist nlohmann::json::iterator it, const std::string& path, 73183ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 73283ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 73383ff9ab6SJames Feist output, 73473df0db0SJames Feist std::string& chassis, const std::string& profile) 73583ff9ab6SJames Feist { 73683ff9ab6SJames Feist 7375f2caaefSJames Feist // common deleter 738b6baeaa4SJames Feist if (it.value() == nullptr) 7395f2caaefSJames Feist { 7405f2caaefSJames Feist std::string iface; 7415f2caaefSJames Feist if (type == "PidControllers" || type == "FanControllers") 7425f2caaefSJames Feist { 7435f2caaefSJames Feist iface = pidConfigurationIface; 7445f2caaefSJames Feist } 7455f2caaefSJames Feist else if (type == "FanZones") 7465f2caaefSJames Feist { 7475f2caaefSJames Feist iface = pidZoneConfigurationIface; 7485f2caaefSJames Feist } 7495f2caaefSJames Feist else if (type == "StepwiseControllers") 7505f2caaefSJames Feist { 7515f2caaefSJames Feist iface = stepwiseConfigurationIface; 7525f2caaefSJames Feist } 7535f2caaefSJames Feist else 7545f2caaefSJames Feist { 7555f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " 7565f2caaefSJames Feist << type; 7575f2caaefSJames Feist messages::propertyUnknown(response->res, type); 7585f2caaefSJames Feist return CreatePIDRet::fail; 7595f2caaefSJames Feist } 7606ee7f774SJames Feist 7616ee7f774SJames Feist BMCWEB_LOG_DEBUG << "del " << path << " " << iface << "\n"; 7625f2caaefSJames Feist // delete interface 7635f2caaefSJames Feist crow::connections::systemBus->async_method_call( 7645f2caaefSJames Feist [response, path](const boost::system::error_code ec) { 7655f2caaefSJames Feist if (ec) 7665f2caaefSJames Feist { 7675f2caaefSJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec; 7685f2caaefSJames Feist messages::internalError(response->res); 769b6baeaa4SJames Feist return; 7705f2caaefSJames Feist } 771b6baeaa4SJames Feist messages::success(response->res); 7725f2caaefSJames Feist }, 7735f2caaefSJames Feist "xyz.openbmc_project.EntityManager", path, iface, "Delete"); 7745f2caaefSJames Feist return CreatePIDRet::del; 7755f2caaefSJames Feist } 7765f2caaefSJames Feist 77773df0db0SJames Feist const dbus::utility::ManagedItem* managedItem = nullptr; 778b6baeaa4SJames Feist if (!createNewObject) 779b6baeaa4SJames Feist { 780b6baeaa4SJames Feist // if we aren't creating a new object, we should be able to find it on 781b6baeaa4SJames Feist // d-bus 78273df0db0SJames Feist managedItem = findChassis(managedObj, it.key(), chassis); 78373df0db0SJames Feist if (managedItem == nullptr) 784b6baeaa4SJames Feist { 785b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 786b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 787b6baeaa4SJames Feist return CreatePIDRet::fail; 788b6baeaa4SJames Feist } 789b6baeaa4SJames Feist } 790b6baeaa4SJames Feist 79173df0db0SJames Feist if (profile.size() && 79273df0db0SJames Feist (type == "PidControllers" || type == "FanControllers" || 79373df0db0SJames Feist type == "StepwiseControllers")) 79473df0db0SJames Feist { 79573df0db0SJames Feist if (managedItem == nullptr) 79673df0db0SJames Feist { 79773df0db0SJames Feist output["Profiles"] = std::vector<std::string>{profile}; 79873df0db0SJames Feist } 79973df0db0SJames Feist else 80073df0db0SJames Feist { 80173df0db0SJames Feist std::string interface; 80273df0db0SJames Feist if (type == "StepwiseControllers") 80373df0db0SJames Feist { 80473df0db0SJames Feist interface = stepwiseConfigurationIface; 80573df0db0SJames Feist } 80673df0db0SJames Feist else 80773df0db0SJames Feist { 80873df0db0SJames Feist interface = pidConfigurationIface; 80973df0db0SJames Feist } 81073df0db0SJames Feist auto findConfig = managedItem->second.find(interface); 81173df0db0SJames Feist if (findConfig == managedItem->second.end()) 81273df0db0SJames Feist { 81373df0db0SJames Feist BMCWEB_LOG_ERROR 81473df0db0SJames Feist << "Failed to find interface in managed object"; 81573df0db0SJames Feist messages::internalError(response->res); 81673df0db0SJames Feist return CreatePIDRet::fail; 81773df0db0SJames Feist } 81873df0db0SJames Feist auto findProfiles = findConfig->second.find("Profiles"); 81973df0db0SJames Feist if (findProfiles != findConfig->second.end()) 82073df0db0SJames Feist { 82173df0db0SJames Feist const std::vector<std::string>* curProfiles = 82273df0db0SJames Feist std::get_if<std::vector<std::string>>( 82373df0db0SJames Feist &(findProfiles->second)); 82473df0db0SJames Feist if (curProfiles == nullptr) 82573df0db0SJames Feist { 82673df0db0SJames Feist BMCWEB_LOG_ERROR << "Illegal profiles in managed object"; 82773df0db0SJames Feist messages::internalError(response->res); 82873df0db0SJames Feist return CreatePIDRet::fail; 82973df0db0SJames Feist } 83073df0db0SJames Feist if (std::find(curProfiles->begin(), curProfiles->end(), 83173df0db0SJames Feist profile) == curProfiles->end()) 83273df0db0SJames Feist { 83373df0db0SJames Feist std::vector<std::string> newProfiles = *curProfiles; 83473df0db0SJames Feist newProfiles.push_back(profile); 83573df0db0SJames Feist output["Profiles"] = newProfiles; 83673df0db0SJames Feist } 83773df0db0SJames Feist } 83873df0db0SJames Feist } 83973df0db0SJames Feist } 84073df0db0SJames Feist 84183ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 84283ff9ab6SJames Feist { 84383ff9ab6SJames Feist if (createNewObject) 84483ff9ab6SJames Feist { 84583ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 84683ff9ab6SJames Feist : std::string("fan"); 84783ff9ab6SJames Feist output["Type"] = std::string("Pid"); 84883ff9ab6SJames Feist } 8495f2caaefSJames Feist 8505f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 8515f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 8525f2caaefSJames Feist std::optional<std::vector<std::string>> outputs; 8535f2caaefSJames Feist std::map<std::string, std::optional<double>> doubles; 854b943aaefSJames Feist std::optional<std::string> setpointOffset; 8555f2caaefSJames Feist if (!redfish::json_util::readJson( 856b6baeaa4SJames Feist it.value(), response->res, "Inputs", inputs, "Outputs", outputs, 8575f2caaefSJames Feist "Zones", zones, "FFGainCoefficient", 8585f2caaefSJames Feist doubles["FFGainCoefficient"], "FFOffCoefficient", 8595f2caaefSJames Feist doubles["FFOffCoefficient"], "ICoefficient", 8605f2caaefSJames Feist doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], 8615f2caaefSJames Feist "ILimitMin", doubles["ILimitMin"], "OutLimitMax", 8625f2caaefSJames Feist doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], 8635f2caaefSJames Feist "PCoefficient", doubles["PCoefficient"], "SetPoint", 864b943aaefSJames Feist doubles["SetPoint"], "SetPointOffset", setpointOffset, 865b943aaefSJames Feist "SlewNeg", doubles["SlewNeg"], "SlewPos", doubles["SlewPos"], 866b943aaefSJames Feist "PositiveHysteresis", doubles["PositiveHysteresis"], 867b943aaefSJames Feist "NegativeHysteresis", doubles["NegativeHysteresis"])) 86883ff9ab6SJames Feist { 8695f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 870b6baeaa4SJames Feist << it.value().dump(); 8715f2caaefSJames Feist return CreatePIDRet::fail; 87283ff9ab6SJames Feist } 8735f2caaefSJames Feist if (zones) 8745f2caaefSJames Feist { 8755f2caaefSJames Feist std::vector<std::string> zonesStr; 8765f2caaefSJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStr)) 8775f2caaefSJames Feist { 8785f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 8795f2caaefSJames Feist return CreatePIDRet::fail; 8805f2caaefSJames Feist } 881b6baeaa4SJames Feist if (chassis.empty() && 882b6baeaa4SJames Feist !findChassis(managedObj, zonesStr[0], chassis)) 883b6baeaa4SJames Feist { 884b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 885b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 886b6baeaa4SJames Feist return CreatePIDRet::fail; 887b6baeaa4SJames Feist } 888b6baeaa4SJames Feist 8895f2caaefSJames Feist output["Zones"] = std::move(zonesStr); 8905f2caaefSJames Feist } 8915f2caaefSJames Feist if (inputs || outputs) 8925f2caaefSJames Feist { 8935f2caaefSJames Feist std::array<std::optional<std::vector<std::string>>*, 2> containers = 8945f2caaefSJames Feist {&inputs, &outputs}; 8955f2caaefSJames Feist size_t index = 0; 8965f2caaefSJames Feist for (const auto& containerPtr : containers) 8975f2caaefSJames Feist { 8985f2caaefSJames Feist std::optional<std::vector<std::string>>& container = 8995f2caaefSJames Feist *containerPtr; 9005f2caaefSJames Feist if (!container) 9015f2caaefSJames Feist { 9025f2caaefSJames Feist index++; 9035f2caaefSJames Feist continue; 90483ff9ab6SJames Feist } 90583ff9ab6SJames Feist 9065f2caaefSJames Feist for (std::string& value : *container) 90783ff9ab6SJames Feist { 9085f2caaefSJames Feist boost::replace_all(value, "_", " "); 90983ff9ab6SJames Feist } 9105f2caaefSJames Feist std::string key; 9115f2caaefSJames Feist if (index == 0) 9125f2caaefSJames Feist { 9135f2caaefSJames Feist key = "Inputs"; 9145f2caaefSJames Feist } 9155f2caaefSJames Feist else 9165f2caaefSJames Feist { 9175f2caaefSJames Feist key = "Outputs"; 9185f2caaefSJames Feist } 9195f2caaefSJames Feist output[key] = *container; 9205f2caaefSJames Feist index++; 9215f2caaefSJames Feist } 92283ff9ab6SJames Feist } 92383ff9ab6SJames Feist 924b943aaefSJames Feist if (setpointOffset) 925b943aaefSJames Feist { 926b943aaefSJames Feist // translate between redfish and dbus names 927b943aaefSJames Feist if (*setpointOffset == "UpperThresholdNonCritical") 928b943aaefSJames Feist { 929b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningLow"); 930b943aaefSJames Feist } 931b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdNonCritical") 932b943aaefSJames Feist { 933b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningHigh"); 934b943aaefSJames Feist } 935b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdCritical") 936b943aaefSJames Feist { 937b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalLow"); 938b943aaefSJames Feist } 939b943aaefSJames Feist else if (*setpointOffset == "UpperThresholdCritical") 940b943aaefSJames Feist { 941b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalHigh"); 942b943aaefSJames Feist } 943b943aaefSJames Feist else 944b943aaefSJames Feist { 945b943aaefSJames Feist BMCWEB_LOG_ERROR << "Invalid setpointoffset " 946b943aaefSJames Feist << *setpointOffset; 947b943aaefSJames Feist messages::invalidObject(response->res, it.key()); 948b943aaefSJames Feist return CreatePIDRet::fail; 949b943aaefSJames Feist } 950b943aaefSJames Feist } 951b943aaefSJames Feist 95283ff9ab6SJames Feist // doubles 9535f2caaefSJames Feist for (const auto& pairs : doubles) 95483ff9ab6SJames Feist { 9555f2caaefSJames Feist if (!pairs.second) 95683ff9ab6SJames Feist { 9575f2caaefSJames Feist continue; 95883ff9ab6SJames Feist } 9595f2caaefSJames Feist BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second; 9605f2caaefSJames Feist output[pairs.first] = *(pairs.second); 9615f2caaefSJames Feist } 96283ff9ab6SJames Feist } 96383ff9ab6SJames Feist 96483ff9ab6SJames Feist else if (type == "FanZones") 96583ff9ab6SJames Feist { 96683ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 96783ff9ab6SJames Feist 9685f2caaefSJames Feist std::optional<nlohmann::json> chassisContainer; 9695f2caaefSJames Feist std::optional<double> failSafePercent; 970d3ec07f8SJames Feist std::optional<double> minThermalOutput; 971b6baeaa4SJames Feist if (!redfish::json_util::readJson(it.value(), response->res, "Chassis", 9725f2caaefSJames Feist chassisContainer, "FailSafePercent", 973d3ec07f8SJames Feist failSafePercent, "MinThermalOutput", 974d3ec07f8SJames Feist minThermalOutput)) 97583ff9ab6SJames Feist { 9765f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 977b6baeaa4SJames Feist << it.value().dump(); 97883ff9ab6SJames Feist return CreatePIDRet::fail; 97983ff9ab6SJames Feist } 9805f2caaefSJames Feist 9815f2caaefSJames Feist if (chassisContainer) 98283ff9ab6SJames Feist { 9835f2caaefSJames Feist 9845f2caaefSJames Feist std::string chassisId; 9855f2caaefSJames Feist if (!redfish::json_util::readJson(*chassisContainer, response->res, 9865f2caaefSJames Feist "@odata.id", chassisId)) 9875f2caaefSJames Feist { 9885f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 9895f2caaefSJames Feist << chassisContainer->dump(); 99083ff9ab6SJames Feist return CreatePIDRet::fail; 99183ff9ab6SJames Feist } 99283ff9ab6SJames Feist 993717794d5SAppaRao Puli // /redfish/v1/chassis/chassis_name/ 9945f2caaefSJames Feist if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis)) 99583ff9ab6SJames Feist { 9965f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << chassisId; 9975f2caaefSJames Feist messages::invalidObject(response->res, chassisId); 99883ff9ab6SJames Feist return CreatePIDRet::fail; 99983ff9ab6SJames Feist } 100083ff9ab6SJames Feist } 1001d3ec07f8SJames Feist if (minThermalOutput) 100283ff9ab6SJames Feist { 1003d3ec07f8SJames Feist output["MinThermalOutput"] = *minThermalOutput; 10045f2caaefSJames Feist } 10055f2caaefSJames Feist if (failSafePercent) 100683ff9ab6SJames Feist { 10075f2caaefSJames Feist output["FailSafePercent"] = *failSafePercent; 10085f2caaefSJames Feist } 10095f2caaefSJames Feist } 10105f2caaefSJames Feist else if (type == "StepwiseControllers") 10115f2caaefSJames Feist { 10125f2caaefSJames Feist output["Type"] = std::string("Stepwise"); 10135f2caaefSJames Feist 10145f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 10155f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> steps; 10165f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 10175f2caaefSJames Feist std::optional<double> positiveHysteresis; 10185f2caaefSJames Feist std::optional<double> negativeHysteresis; 1019c33a90ecSJames Feist std::optional<std::string> direction; // upper clipping curve vs lower 10205f2caaefSJames Feist if (!redfish::json_util::readJson( 1021b6baeaa4SJames Feist it.value(), response->res, "Zones", zones, "Steps", steps, 1022b6baeaa4SJames Feist "Inputs", inputs, "PositiveHysteresis", positiveHysteresis, 1023c33a90ecSJames Feist "NegativeHysteresis", negativeHysteresis, "Direction", 1024c33a90ecSJames Feist direction)) 10255f2caaefSJames Feist { 10265f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 1027b6baeaa4SJames Feist << it.value().dump(); 102883ff9ab6SJames Feist return CreatePIDRet::fail; 102983ff9ab6SJames Feist } 10305f2caaefSJames Feist 10315f2caaefSJames Feist if (zones) 103283ff9ab6SJames Feist { 1033b6baeaa4SJames Feist std::vector<std::string> zonesStrs; 1034b6baeaa4SJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStrs)) 10355f2caaefSJames Feist { 10365f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 103783ff9ab6SJames Feist return CreatePIDRet::fail; 103883ff9ab6SJames Feist } 1039b6baeaa4SJames Feist if (chassis.empty() && 1040b6baeaa4SJames Feist !findChassis(managedObj, zonesStrs[0], chassis)) 1041b6baeaa4SJames Feist { 1042b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 1043b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 1044b6baeaa4SJames Feist return CreatePIDRet::fail; 1045b6baeaa4SJames Feist } 1046b6baeaa4SJames Feist output["Zones"] = std::move(zonesStrs); 10475f2caaefSJames Feist } 10485f2caaefSJames Feist if (steps) 10495f2caaefSJames Feist { 10505f2caaefSJames Feist std::vector<double> readings; 10515f2caaefSJames Feist std::vector<double> outputs; 10525f2caaefSJames Feist for (auto& step : *steps) 10535f2caaefSJames Feist { 10545f2caaefSJames Feist double target; 1055*23a21a1cSEd Tanous double out; 10565f2caaefSJames Feist 10575f2caaefSJames Feist if (!redfish::json_util::readJson(step, response->res, "Target", 1058*23a21a1cSEd Tanous target, "Output", out)) 10595f2caaefSJames Feist { 10605f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 1061b6baeaa4SJames Feist << ", Illegal Property " 1062b6baeaa4SJames Feist << it.value().dump(); 10635f2caaefSJames Feist return CreatePIDRet::fail; 10645f2caaefSJames Feist } 10655f2caaefSJames Feist readings.emplace_back(target); 1066*23a21a1cSEd Tanous outputs.emplace_back(out); 10675f2caaefSJames Feist } 10685f2caaefSJames Feist output["Reading"] = std::move(readings); 10695f2caaefSJames Feist output["Output"] = std::move(outputs); 10705f2caaefSJames Feist } 10715f2caaefSJames Feist if (inputs) 10725f2caaefSJames Feist { 10735f2caaefSJames Feist for (std::string& value : *inputs) 10745f2caaefSJames Feist { 10755f2caaefSJames Feist boost::replace_all(value, "_", " "); 10765f2caaefSJames Feist } 10775f2caaefSJames Feist output["Inputs"] = std::move(*inputs); 10785f2caaefSJames Feist } 10795f2caaefSJames Feist if (negativeHysteresis) 10805f2caaefSJames Feist { 10815f2caaefSJames Feist output["NegativeHysteresis"] = *negativeHysteresis; 10825f2caaefSJames Feist } 10835f2caaefSJames Feist if (positiveHysteresis) 10845f2caaefSJames Feist { 10855f2caaefSJames Feist output["PositiveHysteresis"] = *positiveHysteresis; 108683ff9ab6SJames Feist } 1087c33a90ecSJames Feist if (direction) 1088c33a90ecSJames Feist { 1089c33a90ecSJames Feist constexpr const std::array<const char*, 2> allowedDirections = { 1090c33a90ecSJames Feist "Ceiling", "Floor"}; 1091c33a90ecSJames Feist if (std::find(allowedDirections.begin(), allowedDirections.end(), 1092c33a90ecSJames Feist *direction) == allowedDirections.end()) 1093c33a90ecSJames Feist { 1094c33a90ecSJames Feist messages::propertyValueTypeError(response->res, "Direction", 1095c33a90ecSJames Feist *direction); 1096c33a90ecSJames Feist return CreatePIDRet::fail; 1097c33a90ecSJames Feist } 1098c33a90ecSJames Feist output["Class"] = *direction; 1099c33a90ecSJames Feist } 110083ff9ab6SJames Feist } 110183ff9ab6SJames Feist else 110283ff9ab6SJames Feist { 11035f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type; 110435a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 110583ff9ab6SJames Feist return CreatePIDRet::fail; 110683ff9ab6SJames Feist } 110783ff9ab6SJames Feist return CreatePIDRet::patch; 110883ff9ab6SJames Feist } 110973df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues> 111073df0db0SJames Feist { 111183ff9ab6SJames Feist 1112*23a21a1cSEd Tanous GetPIDValues(const std::shared_ptr<AsyncResp>& asyncRespIn) : 1113*23a21a1cSEd Tanous asyncResp(asyncRespIn) 111473df0db0SJames Feist 11151214b7e7SGunnar Mills {} 11169c310685SBorawski.Lukasz 111773df0db0SJames Feist void run() 11185b4aa86bSJames Feist { 111973df0db0SJames Feist std::shared_ptr<GetPIDValues> self = shared_from_this(); 112073df0db0SJames Feist 112173df0db0SJames Feist // get all configurations 11225b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 112373df0db0SJames Feist [self](const boost::system::error_code ec, 1124*23a21a1cSEd Tanous const crow::openbmc_mapper::GetSubTreeType& subtreeLocal) { 11255b4aa86bSJames Feist if (ec) 11265b4aa86bSJames Feist { 11275b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 112873df0db0SJames Feist messages::internalError(self->asyncResp->res); 112973df0db0SJames Feist return; 113073df0db0SJames Feist } 1131*23a21a1cSEd Tanous self->subtree = subtreeLocal; 113273df0db0SJames Feist }, 113373df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 113473df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 113573df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 113673df0db0SJames Feist std::array<const char*, 4>{ 113773df0db0SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 113873df0db0SJames Feist objectManagerIface, stepwiseConfigurationIface}); 113973df0db0SJames Feist 114073df0db0SJames Feist // at the same time get the selected profile 114173df0db0SJames Feist crow::connections::systemBus->async_method_call( 114273df0db0SJames Feist [self](const boost::system::error_code ec, 1143*23a21a1cSEd Tanous const crow::openbmc_mapper::GetSubTreeType& subtreeLocal) { 1144*23a21a1cSEd Tanous if (ec || subtreeLocal.empty()) 114573df0db0SJames Feist { 114673df0db0SJames Feist return; 114773df0db0SJames Feist } 1148*23a21a1cSEd Tanous if (subtreeLocal[0].second.size() != 1) 114973df0db0SJames Feist { 115073df0db0SJames Feist // invalid mapper response, should never happen 115173df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Mapper Error"; 115273df0db0SJames Feist messages::internalError(self->asyncResp->res); 11535b4aa86bSJames Feist return; 11545b4aa86bSJames Feist } 11555b4aa86bSJames Feist 1156*23a21a1cSEd Tanous const std::string& path = subtreeLocal[0].first; 1157*23a21a1cSEd Tanous const std::string& owner = subtreeLocal[0].second[0].first; 115873df0db0SJames Feist crow::connections::systemBus->async_method_call( 115973df0db0SJames Feist [path, owner, self]( 1160*23a21a1cSEd Tanous const boost::system::error_code ec2, 116173df0db0SJames Feist const boost::container::flat_map< 116273df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 116373df0db0SJames Feist std::string>>& resp) { 1164*23a21a1cSEd Tanous if (ec2) 116573df0db0SJames Feist { 116673df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Can't get " 116773df0db0SJames Feist "thermalModeIface " 116873df0db0SJames Feist << path; 116973df0db0SJames Feist messages::internalError(self->asyncResp->res); 117073df0db0SJames Feist return; 117173df0db0SJames Feist } 1172271584abSEd Tanous const std::string* current = nullptr; 1173271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 117473df0db0SJames Feist for (auto& [key, value] : resp) 117573df0db0SJames Feist { 117673df0db0SJames Feist if (key == "Current") 117773df0db0SJames Feist { 117873df0db0SJames Feist current = std::get_if<std::string>(&value); 117973df0db0SJames Feist if (current == nullptr) 118073df0db0SJames Feist { 118173df0db0SJames Feist BMCWEB_LOG_ERROR 118273df0db0SJames Feist << "GetPIDValues: thermal mode " 118373df0db0SJames Feist "iface invalid " 118473df0db0SJames Feist << path; 118573df0db0SJames Feist messages::internalError( 118673df0db0SJames Feist self->asyncResp->res); 118773df0db0SJames Feist return; 118873df0db0SJames Feist } 118973df0db0SJames Feist } 119073df0db0SJames Feist if (key == "Supported") 119173df0db0SJames Feist { 119273df0db0SJames Feist supported = 119373df0db0SJames Feist std::get_if<std::vector<std::string>>( 119473df0db0SJames Feist &value); 119573df0db0SJames Feist if (supported == nullptr) 119673df0db0SJames Feist { 119773df0db0SJames Feist BMCWEB_LOG_ERROR 119873df0db0SJames Feist << "GetPIDValues: thermal mode " 119973df0db0SJames Feist "iface invalid" 120073df0db0SJames Feist << path; 120173df0db0SJames Feist messages::internalError( 120273df0db0SJames Feist self->asyncResp->res); 120373df0db0SJames Feist return; 120473df0db0SJames Feist } 120573df0db0SJames Feist } 120673df0db0SJames Feist } 120773df0db0SJames Feist if (current == nullptr || supported == nullptr) 120873df0db0SJames Feist { 120973df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: thermal mode " 121073df0db0SJames Feist "iface invalid " 121173df0db0SJames Feist << path; 121273df0db0SJames Feist messages::internalError(self->asyncResp->res); 121373df0db0SJames Feist return; 121473df0db0SJames Feist } 121573df0db0SJames Feist self->currentProfile = *current; 121673df0db0SJames Feist self->supportedProfiles = *supported; 121773df0db0SJames Feist }, 121873df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 121973df0db0SJames Feist thermalModeIface); 122073df0db0SJames Feist }, 122173df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 122273df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 122373df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 122473df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 122573df0db0SJames Feist } 122673df0db0SJames Feist 122773df0db0SJames Feist ~GetPIDValues() 122873df0db0SJames Feist { 122973df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 123073df0db0SJames Feist { 123173df0db0SJames Feist return; 123273df0db0SJames Feist } 12335b4aa86bSJames Feist // create map of <connection, path to objMgr>> 123473df0db0SJames Feist boost::container::flat_map<std::string, std::string> objectMgrPaths; 12356bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 12365b4aa86bSJames Feist for (const auto& pathGroup : subtree) 12375b4aa86bSJames Feist { 12385b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 12395b4aa86bSJames Feist { 12406bce33bcSJames Feist auto findConnection = 12416bce33bcSJames Feist calledConnections.find(connectionGroup.first); 12426bce33bcSJames Feist if (findConnection != calledConnections.end()) 12436bce33bcSJames Feist { 12446bce33bcSJames Feist break; 12456bce33bcSJames Feist } 124673df0db0SJames Feist for (const std::string& interface : connectionGroup.second) 12475b4aa86bSJames Feist { 12485b4aa86bSJames Feist if (interface == objectManagerIface) 12495b4aa86bSJames Feist { 125073df0db0SJames Feist objectMgrPaths[connectionGroup.first] = pathGroup.first; 12515b4aa86bSJames Feist } 12525b4aa86bSJames Feist // this list is alphabetical, so we 12535b4aa86bSJames Feist // should have found the objMgr by now 12545b4aa86bSJames Feist if (interface == pidConfigurationIface || 1255b7a08d04SJames Feist interface == pidZoneConfigurationIface || 1256b7a08d04SJames Feist interface == stepwiseConfigurationIface) 12575b4aa86bSJames Feist { 12585b4aa86bSJames Feist auto findObjMgr = 12595b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 12605b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 12615b4aa86bSJames Feist { 12625b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 12635b4aa86bSJames Feist << "Has no Object Manager"; 12645b4aa86bSJames Feist continue; 12655b4aa86bSJames Feist } 12666bce33bcSJames Feist 12676bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 12686bce33bcSJames Feist 126973df0db0SJames Feist asyncPopulatePid(findObjMgr->first, findObjMgr->second, 127073df0db0SJames Feist currentProfile, supportedProfiles, 127173df0db0SJames Feist asyncResp); 12725b4aa86bSJames Feist break; 12735b4aa86bSJames Feist } 12745b4aa86bSJames Feist } 12755b4aa86bSJames Feist } 12765b4aa86bSJames Feist } 127773df0db0SJames Feist } 127873df0db0SJames Feist 127973df0db0SJames Feist std::vector<std::string> supportedProfiles; 128073df0db0SJames Feist std::string currentProfile; 128173df0db0SJames Feist crow::openbmc_mapper::GetSubTreeType subtree; 128273df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 128373df0db0SJames Feist }; 128473df0db0SJames Feist 128573df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues> 128673df0db0SJames Feist { 128773df0db0SJames Feist 1288271584abSEd Tanous SetPIDValues(const std::shared_ptr<AsyncResp>& asyncRespIn, 128973df0db0SJames Feist nlohmann::json& data) : 1290271584abSEd Tanous asyncResp(asyncRespIn) 129173df0db0SJames Feist { 129273df0db0SJames Feist 129373df0db0SJames Feist std::optional<nlohmann::json> pidControllers; 129473df0db0SJames Feist std::optional<nlohmann::json> fanControllers; 129573df0db0SJames Feist std::optional<nlohmann::json> fanZones; 129673df0db0SJames Feist std::optional<nlohmann::json> stepwiseControllers; 129773df0db0SJames Feist 129873df0db0SJames Feist if (!redfish::json_util::readJson( 129973df0db0SJames Feist data, asyncResp->res, "PidControllers", pidControllers, 130073df0db0SJames Feist "FanControllers", fanControllers, "FanZones", fanZones, 130173df0db0SJames Feist "StepwiseControllers", stepwiseControllers, "Profile", profile)) 130273df0db0SJames Feist { 130373df0db0SJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 130473df0db0SJames Feist << data.dump(); 130573df0db0SJames Feist return; 130673df0db0SJames Feist } 130773df0db0SJames Feist configuration.emplace_back("PidControllers", std::move(pidControllers)); 130873df0db0SJames Feist configuration.emplace_back("FanControllers", std::move(fanControllers)); 130973df0db0SJames Feist configuration.emplace_back("FanZones", std::move(fanZones)); 131073df0db0SJames Feist configuration.emplace_back("StepwiseControllers", 131173df0db0SJames Feist std::move(stepwiseControllers)); 131273df0db0SJames Feist } 131373df0db0SJames Feist void run() 131473df0db0SJames Feist { 131573df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 131673df0db0SJames Feist { 131773df0db0SJames Feist return; 131873df0db0SJames Feist } 131973df0db0SJames Feist 132073df0db0SJames Feist std::shared_ptr<SetPIDValues> self = shared_from_this(); 132173df0db0SJames Feist 132273df0db0SJames Feist // todo(james): might make sense to do a mapper call here if this 132373df0db0SJames Feist // interface gets more traction 132473df0db0SJames Feist crow::connections::systemBus->async_method_call( 132573df0db0SJames Feist [self](const boost::system::error_code ec, 1326271584abSEd Tanous dbus::utility::ManagedObjectType& mObj) { 132773df0db0SJames Feist if (ec) 132873df0db0SJames Feist { 132973df0db0SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 133073df0db0SJames Feist messages::internalError(self->asyncResp->res); 133173df0db0SJames Feist return; 133273df0db0SJames Feist } 1333e69d9de2SJames Feist const std::array<const char*, 3> configurations = { 1334e69d9de2SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 1335e69d9de2SJames Feist stepwiseConfigurationIface}; 1336e69d9de2SJames Feist 133714b0b8d5SJames Feist for (const auto& [path, object] : mObj) 1338e69d9de2SJames Feist { 133914b0b8d5SJames Feist for (const auto& [interface, _] : object) 1340e69d9de2SJames Feist { 1341e69d9de2SJames Feist if (std::find(configurations.begin(), 1342e69d9de2SJames Feist configurations.end(), 1343e69d9de2SJames Feist interface) != configurations.end()) 1344e69d9de2SJames Feist { 134514b0b8d5SJames Feist self->objectCount++; 1346e69d9de2SJames Feist break; 1347e69d9de2SJames Feist } 1348e69d9de2SJames Feist } 1349e69d9de2SJames Feist } 1350271584abSEd Tanous self->managedObj = std::move(mObj); 135173df0db0SJames Feist }, 135273df0db0SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 135373df0db0SJames Feist "GetManagedObjects"); 135473df0db0SJames Feist 135573df0db0SJames Feist // at the same time get the profile information 135673df0db0SJames Feist crow::connections::systemBus->async_method_call( 135773df0db0SJames Feist [self](const boost::system::error_code ec, 135873df0db0SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 135973df0db0SJames Feist if (ec || subtree.empty()) 136073df0db0SJames Feist { 136173df0db0SJames Feist return; 136273df0db0SJames Feist } 136373df0db0SJames Feist if (subtree[0].second.empty()) 136473df0db0SJames Feist { 136573df0db0SJames Feist // invalid mapper response, should never happen 136673df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Mapper Error"; 136773df0db0SJames Feist messages::internalError(self->asyncResp->res); 136873df0db0SJames Feist return; 136973df0db0SJames Feist } 137073df0db0SJames Feist 137173df0db0SJames Feist const std::string& path = subtree[0].first; 137273df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 137373df0db0SJames Feist crow::connections::systemBus->async_method_call( 137473df0db0SJames Feist [self, path, owner]( 137573df0db0SJames Feist const boost::system::error_code ec, 137673df0db0SJames Feist const boost::container::flat_map< 137773df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 1378271584abSEd Tanous std::string>>& r) { 137973df0db0SJames Feist if (ec) 138073df0db0SJames Feist { 138173df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Can't get " 138273df0db0SJames Feist "thermalModeIface " 138373df0db0SJames Feist << path; 138473df0db0SJames Feist messages::internalError(self->asyncResp->res); 138573df0db0SJames Feist return; 138673df0db0SJames Feist } 1387271584abSEd Tanous const std::string* current = nullptr; 1388271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 1389271584abSEd Tanous for (auto& [key, value] : r) 139073df0db0SJames Feist { 139173df0db0SJames Feist if (key == "Current") 139273df0db0SJames Feist { 139373df0db0SJames Feist current = std::get_if<std::string>(&value); 139473df0db0SJames Feist if (current == nullptr) 139573df0db0SJames Feist { 139673df0db0SJames Feist BMCWEB_LOG_ERROR 139773df0db0SJames Feist << "SetPIDValues: thermal mode " 139873df0db0SJames Feist "iface invalid " 139973df0db0SJames Feist << path; 140073df0db0SJames Feist messages::internalError( 140173df0db0SJames Feist self->asyncResp->res); 140273df0db0SJames Feist return; 140373df0db0SJames Feist } 140473df0db0SJames Feist } 140573df0db0SJames Feist if (key == "Supported") 140673df0db0SJames Feist { 140773df0db0SJames Feist supported = 140873df0db0SJames Feist std::get_if<std::vector<std::string>>( 140973df0db0SJames Feist &value); 141073df0db0SJames Feist if (supported == nullptr) 141173df0db0SJames Feist { 141273df0db0SJames Feist BMCWEB_LOG_ERROR 141373df0db0SJames Feist << "SetPIDValues: thermal mode " 141473df0db0SJames Feist "iface invalid" 141573df0db0SJames Feist << path; 141673df0db0SJames Feist messages::internalError( 141773df0db0SJames Feist self->asyncResp->res); 141873df0db0SJames Feist return; 141973df0db0SJames Feist } 142073df0db0SJames Feist } 142173df0db0SJames Feist } 142273df0db0SJames Feist if (current == nullptr || supported == nullptr) 142373df0db0SJames Feist { 142473df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: thermal mode " 142573df0db0SJames Feist "iface invalid " 142673df0db0SJames Feist << path; 142773df0db0SJames Feist messages::internalError(self->asyncResp->res); 142873df0db0SJames Feist return; 142973df0db0SJames Feist } 143073df0db0SJames Feist self->currentProfile = *current; 143173df0db0SJames Feist self->supportedProfiles = *supported; 143273df0db0SJames Feist self->profileConnection = owner; 143373df0db0SJames Feist self->profilePath = path; 143473df0db0SJames Feist }, 143573df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 143673df0db0SJames Feist thermalModeIface); 14375b4aa86bSJames Feist }, 14385b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 14395b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 14405b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 144173df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 144273df0db0SJames Feist } 144373df0db0SJames Feist ~SetPIDValues() 144473df0db0SJames Feist { 144573df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 144673df0db0SJames Feist { 144773df0db0SJames Feist return; 14485b4aa86bSJames Feist } 14495b4aa86bSJames Feist 145073df0db0SJames Feist std::shared_ptr<AsyncResp> response = asyncResp; 145173df0db0SJames Feist 145273df0db0SJames Feist if (profile) 145373df0db0SJames Feist { 145473df0db0SJames Feist if (std::find(supportedProfiles.begin(), supportedProfiles.end(), 145573df0db0SJames Feist *profile) == supportedProfiles.end()) 145673df0db0SJames Feist { 145773df0db0SJames Feist messages::actionParameterUnknown(response->res, "Profile", 145873df0db0SJames Feist *profile); 145973df0db0SJames Feist return; 146073df0db0SJames Feist } 146173df0db0SJames Feist currentProfile = *profile; 146273df0db0SJames Feist crow::connections::systemBus->async_method_call( 146373df0db0SJames Feist [response](const boost::system::error_code ec) { 146473df0db0SJames Feist if (ec) 146573df0db0SJames Feist { 146673df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching profile" << ec; 146773df0db0SJames Feist messages::internalError(response->res); 146873df0db0SJames Feist } 146973df0db0SJames Feist }, 147073df0db0SJames Feist profileConnection, profilePath, 147173df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", thermalModeIface, 147273df0db0SJames Feist "Current", std::variant<std::string>(*profile)); 147373df0db0SJames Feist } 147473df0db0SJames Feist 147573df0db0SJames Feist for (auto& containerPair : configuration) 147673df0db0SJames Feist { 147773df0db0SJames Feist auto& container = containerPair.second; 147873df0db0SJames Feist if (!container) 147973df0db0SJames Feist { 148073df0db0SJames Feist continue; 148173df0db0SJames Feist } 14826ee7f774SJames Feist BMCWEB_LOG_DEBUG << *container; 14836ee7f774SJames Feist 148473df0db0SJames Feist std::string& type = containerPair.first; 148573df0db0SJames Feist 148673df0db0SJames Feist for (nlohmann::json::iterator it = container->begin(); 148773df0db0SJames Feist it != container->end(); it++) 148873df0db0SJames Feist { 148973df0db0SJames Feist const auto& name = it.key(); 14906ee7f774SJames Feist BMCWEB_LOG_DEBUG << "looking for " << name; 14916ee7f774SJames Feist 149273df0db0SJames Feist auto pathItr = 149373df0db0SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 149473df0db0SJames Feist [&name](const auto& obj) { 149573df0db0SJames Feist return boost::algorithm::ends_with( 149673df0db0SJames Feist obj.first.str, "/" + name); 149773df0db0SJames Feist }); 149873df0db0SJames Feist boost::container::flat_map<std::string, 149973df0db0SJames Feist dbus::utility::DbusVariantType> 150073df0db0SJames Feist output; 150173df0db0SJames Feist 150273df0db0SJames Feist output.reserve(16); // The pid interface length 150373df0db0SJames Feist 150473df0db0SJames Feist // determines if we're patching entity-manager or 150573df0db0SJames Feist // creating a new object 150673df0db0SJames Feist bool createNewObject = (pathItr == managedObj.end()); 15076ee7f774SJames Feist BMCWEB_LOG_DEBUG << "Found = " << !createNewObject; 15086ee7f774SJames Feist 150973df0db0SJames Feist std::string iface; 151073df0db0SJames Feist if (type == "PidControllers" || type == "FanControllers") 151173df0db0SJames Feist { 151273df0db0SJames Feist iface = pidConfigurationIface; 151373df0db0SJames Feist if (!createNewObject && 151473df0db0SJames Feist pathItr->second.find(pidConfigurationIface) == 151573df0db0SJames Feist pathItr->second.end()) 151673df0db0SJames Feist { 151773df0db0SJames Feist createNewObject = true; 151873df0db0SJames Feist } 151973df0db0SJames Feist } 152073df0db0SJames Feist else if (type == "FanZones") 152173df0db0SJames Feist { 152273df0db0SJames Feist iface = pidZoneConfigurationIface; 152373df0db0SJames Feist if (!createNewObject && 152473df0db0SJames Feist pathItr->second.find(pidZoneConfigurationIface) == 152573df0db0SJames Feist pathItr->second.end()) 152673df0db0SJames Feist { 152773df0db0SJames Feist 152873df0db0SJames Feist createNewObject = true; 152973df0db0SJames Feist } 153073df0db0SJames Feist } 153173df0db0SJames Feist else if (type == "StepwiseControllers") 153273df0db0SJames Feist { 153373df0db0SJames Feist iface = stepwiseConfigurationIface; 153473df0db0SJames Feist if (!createNewObject && 153573df0db0SJames Feist pathItr->second.find(stepwiseConfigurationIface) == 153673df0db0SJames Feist pathItr->second.end()) 153773df0db0SJames Feist { 153873df0db0SJames Feist createNewObject = true; 153973df0db0SJames Feist } 154073df0db0SJames Feist } 15416ee7f774SJames Feist 15426ee7f774SJames Feist if (createNewObject && it.value() == nullptr) 15436ee7f774SJames Feist { 15444e0453b1SGunnar Mills // can't delete a non-existent object 15456ee7f774SJames Feist messages::invalidObject(response->res, name); 15466ee7f774SJames Feist continue; 15476ee7f774SJames Feist } 15486ee7f774SJames Feist 15496ee7f774SJames Feist std::string path; 15506ee7f774SJames Feist if (pathItr != managedObj.end()) 15516ee7f774SJames Feist { 15526ee7f774SJames Feist path = pathItr->first.str; 15536ee7f774SJames Feist } 15546ee7f774SJames Feist 155573df0db0SJames Feist BMCWEB_LOG_DEBUG << "Create new = " << createNewObject << "\n"; 1556e69d9de2SJames Feist 1557e69d9de2SJames Feist // arbitrary limit to avoid attacks 1558e69d9de2SJames Feist constexpr const size_t controllerLimit = 500; 155914b0b8d5SJames Feist if (createNewObject && objectCount >= controllerLimit) 1560e69d9de2SJames Feist { 1561e69d9de2SJames Feist messages::resourceExhaustion(response->res, type); 1562e69d9de2SJames Feist continue; 1563e69d9de2SJames Feist } 1564e69d9de2SJames Feist 156573df0db0SJames Feist output["Name"] = boost::replace_all_copy(name, "_", " "); 156673df0db0SJames Feist 156773df0db0SJames Feist std::string chassis; 156873df0db0SJames Feist CreatePIDRet ret = createPidInterface( 15696ee7f774SJames Feist response, type, it, path, managedObj, createNewObject, 15706ee7f774SJames Feist output, chassis, currentProfile); 157173df0db0SJames Feist if (ret == CreatePIDRet::fail) 157273df0db0SJames Feist { 157373df0db0SJames Feist return; 157473df0db0SJames Feist } 157573df0db0SJames Feist else if (ret == CreatePIDRet::del) 157673df0db0SJames Feist { 157773df0db0SJames Feist continue; 157873df0db0SJames Feist } 157973df0db0SJames Feist 158073df0db0SJames Feist if (!createNewObject) 158173df0db0SJames Feist { 158273df0db0SJames Feist for (const auto& property : output) 158373df0db0SJames Feist { 158473df0db0SJames Feist crow::connections::systemBus->async_method_call( 158573df0db0SJames Feist [response, 158673df0db0SJames Feist propertyName{std::string(property.first)}]( 158773df0db0SJames Feist const boost::system::error_code ec) { 158873df0db0SJames Feist if (ec) 158973df0db0SJames Feist { 159073df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching " 159173df0db0SJames Feist << propertyName << ": " 159273df0db0SJames Feist << ec; 159373df0db0SJames Feist messages::internalError(response->res); 159473df0db0SJames Feist return; 159573df0db0SJames Feist } 159673df0db0SJames Feist messages::success(response->res); 159773df0db0SJames Feist }, 15986ee7f774SJames Feist "xyz.openbmc_project.EntityManager", path, 159973df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", iface, 160073df0db0SJames Feist property.first, property.second); 160173df0db0SJames Feist } 160273df0db0SJames Feist } 160373df0db0SJames Feist else 160473df0db0SJames Feist { 160573df0db0SJames Feist if (chassis.empty()) 160673df0db0SJames Feist { 160773df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config"; 160873df0db0SJames Feist messages::invalidObject(response->res, name); 160973df0db0SJames Feist return; 161073df0db0SJames Feist } 161173df0db0SJames Feist 161273df0db0SJames Feist bool foundChassis = false; 161373df0db0SJames Feist for (const auto& obj : managedObj) 161473df0db0SJames Feist { 161573df0db0SJames Feist if (boost::algorithm::ends_with(obj.first.str, chassis)) 161673df0db0SJames Feist { 161773df0db0SJames Feist chassis = obj.first.str; 161873df0db0SJames Feist foundChassis = true; 161973df0db0SJames Feist break; 162073df0db0SJames Feist } 162173df0db0SJames Feist } 162273df0db0SJames Feist if (!foundChassis) 162373df0db0SJames Feist { 162473df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to find chassis on dbus"; 162573df0db0SJames Feist messages::resourceMissingAtURI( 162673df0db0SJames Feist response->res, "/redfish/v1/Chassis/" + chassis); 162773df0db0SJames Feist return; 162873df0db0SJames Feist } 162973df0db0SJames Feist 163073df0db0SJames Feist crow::connections::systemBus->async_method_call( 163173df0db0SJames Feist [response](const boost::system::error_code ec) { 163273df0db0SJames Feist if (ec) 163373df0db0SJames Feist { 163473df0db0SJames Feist BMCWEB_LOG_ERROR << "Error Adding Pid Object " 163573df0db0SJames Feist << ec; 163673df0db0SJames Feist messages::internalError(response->res); 163773df0db0SJames Feist return; 163873df0db0SJames Feist } 163973df0db0SJames Feist messages::success(response->res); 164073df0db0SJames Feist }, 164173df0db0SJames Feist "xyz.openbmc_project.EntityManager", chassis, 164273df0db0SJames Feist "xyz.openbmc_project.AddObject", "AddObject", output); 164373df0db0SJames Feist } 164473df0db0SJames Feist } 164573df0db0SJames Feist } 164673df0db0SJames Feist } 164773df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 164873df0db0SJames Feist std::vector<std::pair<std::string, std::optional<nlohmann::json>>> 164973df0db0SJames Feist configuration; 165073df0db0SJames Feist std::optional<std::string> profile; 165173df0db0SJames Feist dbus::utility::ManagedObjectType managedObj; 165273df0db0SJames Feist std::vector<std::string> supportedProfiles; 165373df0db0SJames Feist std::string currentProfile; 165473df0db0SJames Feist std::string profileConnection; 165573df0db0SJames Feist std::string profilePath; 165614b0b8d5SJames Feist size_t objectCount = 0; 165773df0db0SJames Feist }; 165873df0db0SJames Feist 165973df0db0SJames Feist class Manager : public Node 166073df0db0SJames Feist { 166173df0db0SJames Feist public: 166252cc112dSEd Tanous Manager(App& app) : Node(app, "/redfish/v1/Managers/bmc/") 166373df0db0SJames Feist { 166452cc112dSEd Tanous 166552cc112dSEd Tanous uuid = persistent_data::getConfig().systemUuid; 166673df0db0SJames Feist entityPrivileges = { 166773df0db0SJames Feist {boost::beast::http::verb::get, {{"Login"}}}, 166873df0db0SJames Feist {boost::beast::http::verb::head, {{"Login"}}}, 166973df0db0SJames Feist {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 167073df0db0SJames Feist {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 167173df0db0SJames Feist {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 167273df0db0SJames Feist {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 167373df0db0SJames Feist } 167473df0db0SJames Feist 167573df0db0SJames Feist private: 167655c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 16771abe55efSEd Tanous const std::vector<std::string>& params) override 16781abe55efSEd Tanous { 16790f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc"; 16804bf2b033SGunnar Mills res.jsonValue["@odata.type"] = "#Manager.v1_9_0.Manager"; 16810f74e643SEd Tanous res.jsonValue["Id"] = "bmc"; 16820f74e643SEd Tanous res.jsonValue["Name"] = "OpenBmc Manager"; 16830f74e643SEd Tanous res.jsonValue["Description"] = "Baseboard Management Controller"; 16840f74e643SEd Tanous res.jsonValue["PowerState"] = "On"; 1685029573d4SEd Tanous res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}}; 16860f74e643SEd Tanous res.jsonValue["ManagerType"] = "BMC"; 16873602e232SEd Tanous res.jsonValue["UUID"] = systemd_utils::getUuid(); 16883602e232SEd Tanous res.jsonValue["ServiceEntryPointUUID"] = uuid; 16890f74e643SEd Tanous res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model 16900f74e643SEd Tanous 16910f74e643SEd Tanous res.jsonValue["LogServices"] = { 16920f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}}; 16930f74e643SEd Tanous 16940f74e643SEd Tanous res.jsonValue["NetworkProtocol"] = { 16950f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}}; 16960f74e643SEd Tanous 16970f74e643SEd Tanous res.jsonValue["EthernetInterfaces"] = { 16980f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 1699107077deSPrzemyslaw Czarnowski 1700107077deSPrzemyslaw Czarnowski #ifdef BMCWEB_ENABLE_VM_NBDPROXY 1701107077deSPrzemyslaw Czarnowski res.jsonValue["VirtualMedia"] = { 1702107077deSPrzemyslaw Czarnowski {"@odata.id", "/redfish/v1/Managers/bmc/VirtualMedia"}}; 1703107077deSPrzemyslaw Czarnowski #endif // BMCWEB_ENABLE_VM_NBDPROXY 1704107077deSPrzemyslaw Czarnowski 17050f74e643SEd Tanous // default oem data 17060f74e643SEd Tanous nlohmann::json& oem = res.jsonValue["Oem"]; 17070f74e643SEd Tanous nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 17080f74e643SEd Tanous oem["@odata.type"] = "#OemManager.Oem"; 17090f74e643SEd Tanous oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 17100f74e643SEd Tanous oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 17110f74e643SEd Tanous oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 1712cfcd5f6bSMarri Devender Rao oemOpenbmc["Certificates"] = { 1713cfcd5f6bSMarri Devender Rao {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates"}}; 17140f74e643SEd Tanous 17152a5c4407SGunnar Mills // Manager.Reset (an action) can be many values, OpenBMC only supports 17162a5c4407SGunnar Mills // BMC reboot. 17172a5c4407SGunnar Mills nlohmann::json& managerReset = 17180f74e643SEd Tanous res.jsonValue["Actions"]["#Manager.Reset"]; 17192a5c4407SGunnar Mills managerReset["target"] = 1720ed5befbdSJennifer Lee "/redfish/v1/Managers/bmc/Actions/Manager.Reset"; 17211cb1a9e6SAppaRao Puli managerReset["@Redfish.ActionInfo"] = 17221cb1a9e6SAppaRao Puli "/redfish/v1/Managers/bmc/ResetActionInfo"; 1723ca537928SJennifer Lee 17243e40fc74SGunnar Mills // ResetToDefaults (Factory Reset) has values like 17253e40fc74SGunnar Mills // PreserveNetworkAndUsers and PreserveNetwork that aren't supported 17263e40fc74SGunnar Mills // on OpenBMC 17273e40fc74SGunnar Mills nlohmann::json& resetToDefaults = 17283e40fc74SGunnar Mills res.jsonValue["Actions"]["#Manager.ResetToDefaults"]; 17293e40fc74SGunnar Mills resetToDefaults["target"] = 17303e40fc74SGunnar Mills "/redfish/v1/Managers/bmc/Actions/Manager.ResetToDefaults"; 17313e40fc74SGunnar Mills resetToDefaults["ResetType@Redfish.AllowableValues"] = {"ResetAll"}; 17323e40fc74SGunnar Mills 1733cb92c03bSAndrew Geissler res.jsonValue["DateTime"] = crow::utility::dateTimeNow(); 1734474bfad5SSantosh Puranik 1735f8c3e6f0SKuiying Wang // Fill in SerialConsole info 1736474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ServiceEnabled"] = true; 1737f8c3e6f0SKuiying Wang res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 1738474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {"IPMI", 1739474bfad5SSantosh Puranik "SSH"}; 1740ef47bb18SSantosh Puranik #ifdef BMCWEB_ENABLE_KVM 1741f8c3e6f0SKuiying Wang // Fill in GraphicalConsole info 1742ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 1743704fae6cSJae Hyun Yoo res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; 1744ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = {"KVMIP"}; 1745ef47bb18SSantosh Puranik #endif // BMCWEB_ENABLE_KVM 1746474bfad5SSantosh Puranik 1747603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers@odata.count"] = 1; 1748603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers"] = { 1749603a6640SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system"}}}; 175026f03899SShawn McCarney 1751ed5befbdSJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 17525b4aa86bSJames Feist 1753b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 1754b49ac873SJames Feist health->isManagersHealth = true; 1755b49ac873SJames Feist health->populate(); 1756b49ac873SJames Feist 1757e90c5052SAndrew Geissler fw_util::getActiveFwVersion(asyncResp, fw_util::bmcPurpose, 175872d566d9SGunnar Mills "FirmwareVersion", true); 17590f6b00bdSJames Feist 17604bf2b033SGunnar Mills getLastResetTime(asyncResp); 17614bf2b033SGunnar Mills 176273df0db0SJames Feist auto pids = std::make_shared<GetPIDValues>(asyncResp); 176373df0db0SJames Feist pids->run(); 1764c5d03ff4SJennifer Lee 1765c5d03ff4SJennifer Lee getMainChassisId(asyncResp, [](const std::string& chassisId, 1766c5d03ff4SJennifer Lee const std::shared_ptr<AsyncResp> aRsp) { 1767c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] = 1; 1768c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis"] = { 1769c5d03ff4SJennifer Lee {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 17702c0feb00SJason M. Bills aRsp->res.jsonValue["Links"]["ManagerInChassis"] = { 17712c0feb00SJason M. Bills {"@odata.id", "/redfish/v1/Chassis/" + chassisId}}; 1772c5d03ff4SJennifer Lee }); 17730f6b00bdSJames Feist 17740f6b00bdSJames Feist static bool started = false; 17750f6b00bdSJames Feist 17760f6b00bdSJames Feist if (!started) 17770f6b00bdSJames Feist { 17780f6b00bdSJames Feist crow::connections::systemBus->async_method_call( 17790f6b00bdSJames Feist [asyncResp](const boost::system::error_code ec, 17800f6b00bdSJames Feist const std::variant<double>& resp) { 17810f6b00bdSJames Feist if (ec) 17820f6b00bdSJames Feist { 17830f6b00bdSJames Feist BMCWEB_LOG_ERROR << "Error while getting progress"; 17840f6b00bdSJames Feist messages::internalError(asyncResp->res); 17850f6b00bdSJames Feist return; 17860f6b00bdSJames Feist } 17870f6b00bdSJames Feist const double* val = std::get_if<double>(&resp); 17880f6b00bdSJames Feist if (val == nullptr) 17890f6b00bdSJames Feist { 17900f6b00bdSJames Feist BMCWEB_LOG_ERROR 17910f6b00bdSJames Feist << "Invalid response while getting progress"; 17920f6b00bdSJames Feist messages::internalError(asyncResp->res); 17930f6b00bdSJames Feist return; 17940f6b00bdSJames Feist } 17950f6b00bdSJames Feist if (*val < 1.0) 17960f6b00bdSJames Feist { 17970f6b00bdSJames Feist asyncResp->res.jsonValue["Status"]["State"] = 17980f6b00bdSJames Feist "Starting"; 17990f6b00bdSJames Feist started = true; 18000f6b00bdSJames Feist } 18010f6b00bdSJames Feist }, 18020f6b00bdSJames Feist "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 18030f6b00bdSJames Feist "org.freedesktop.DBus.Properties", "Get", 18040f6b00bdSJames Feist "org.freedesktop.systemd1.Manager", "Progress"); 18050f6b00bdSJames Feist } 180683ff9ab6SJames Feist } 18075b4aa86bSJames Feist 18085b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 18095b4aa86bSJames Feist const std::vector<std::string>& params) override 18105b4aa86bSJames Feist { 18110627a2c7SEd Tanous std::optional<nlohmann::json> oem; 18124bfefa74SGunnar Mills std::optional<nlohmann::json> links; 1813af5d6058SSantosh Puranik std::optional<std::string> datetime; 181441352c24SSantosh Puranik std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 18150627a2c7SEd Tanous 181641352c24SSantosh Puranik if (!json_util::readJson(req, response->res, "Oem", oem, "DateTime", 18174bfefa74SGunnar Mills datetime, "Links", links)) 181883ff9ab6SJames Feist { 181983ff9ab6SJames Feist return; 182083ff9ab6SJames Feist } 18210627a2c7SEd Tanous 18220627a2c7SEd Tanous if (oem) 182383ff9ab6SJames Feist { 18245f2caaefSJames Feist std::optional<nlohmann::json> openbmc; 182543b761d0SEd Tanous if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc)) 182683ff9ab6SJames Feist { 182743b761d0SEd Tanous BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 182843b761d0SEd Tanous << oem->dump(); 182983ff9ab6SJames Feist return; 183083ff9ab6SJames Feist } 18315f2caaefSJames Feist if (openbmc) 183283ff9ab6SJames Feist { 18335f2caaefSJames Feist std::optional<nlohmann::json> fan; 183443b761d0SEd Tanous if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan)) 183583ff9ab6SJames Feist { 18365f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 18375f2caaefSJames Feist << ", Illegal Property " 18385f2caaefSJames Feist << openbmc->dump(); 183983ff9ab6SJames Feist return; 184083ff9ab6SJames Feist } 18415f2caaefSJames Feist if (fan) 184283ff9ab6SJames Feist { 184373df0db0SJames Feist auto pid = std::make_shared<SetPIDValues>(response, *fan); 184473df0db0SJames Feist pid->run(); 184583ff9ab6SJames Feist } 184683ff9ab6SJames Feist } 184783ff9ab6SJames Feist } 18484bfefa74SGunnar Mills if (links) 18494bfefa74SGunnar Mills { 18504bfefa74SGunnar Mills std::optional<nlohmann::json> activeSoftwareImage; 18514bfefa74SGunnar Mills if (!redfish::json_util::readJson( 18524bfefa74SGunnar Mills *links, res, "ActiveSoftwareImage", activeSoftwareImage)) 18534bfefa74SGunnar Mills { 18544bfefa74SGunnar Mills return; 18554bfefa74SGunnar Mills } 18564bfefa74SGunnar Mills if (activeSoftwareImage) 18574bfefa74SGunnar Mills { 18584bfefa74SGunnar Mills std::optional<std::string> odataId; 18594bfefa74SGunnar Mills if (!json_util::readJson(*activeSoftwareImage, res, "@odata.id", 18604bfefa74SGunnar Mills odataId)) 18614bfefa74SGunnar Mills { 18624bfefa74SGunnar Mills return; 18634bfefa74SGunnar Mills } 18644bfefa74SGunnar Mills 18654bfefa74SGunnar Mills if (odataId) 18664bfefa74SGunnar Mills { 18674bfefa74SGunnar Mills setActiveFirmwareImage(response, std::move(*odataId)); 18684bfefa74SGunnar Mills } 18694bfefa74SGunnar Mills } 18704bfefa74SGunnar Mills } 1871af5d6058SSantosh Puranik if (datetime) 1872af5d6058SSantosh Puranik { 1873af5d6058SSantosh Puranik setDateTime(response, std::move(*datetime)); 1874af5d6058SSantosh Puranik } 1875af5d6058SSantosh Puranik } 1876af5d6058SSantosh Puranik 18774bf2b033SGunnar Mills void getLastResetTime(std::shared_ptr<AsyncResp> aResp) 18784bf2b033SGunnar Mills { 18794bf2b033SGunnar Mills BMCWEB_LOG_DEBUG << "Getting Manager Last Reset Time"; 18804bf2b033SGunnar Mills 18814bf2b033SGunnar Mills crow::connections::systemBus->async_method_call( 18824bf2b033SGunnar Mills [aResp](const boost::system::error_code ec, 18834bf2b033SGunnar Mills std::variant<uint64_t>& lastResetTime) { 18844bf2b033SGunnar Mills if (ec) 18854bf2b033SGunnar Mills { 18864bf2b033SGunnar Mills BMCWEB_LOG_DEBUG << "D-BUS response error " << ec; 18874bf2b033SGunnar Mills return; 18884bf2b033SGunnar Mills } 18894bf2b033SGunnar Mills 18904bf2b033SGunnar Mills const uint64_t* lastResetTimePtr = 18914bf2b033SGunnar Mills std::get_if<uint64_t>(&lastResetTime); 18924bf2b033SGunnar Mills 18934bf2b033SGunnar Mills if (!lastResetTimePtr) 18944bf2b033SGunnar Mills { 18954bf2b033SGunnar Mills messages::internalError(aResp->res); 18964bf2b033SGunnar Mills return; 18974bf2b033SGunnar Mills } 18984bf2b033SGunnar Mills // LastRebootTime is epoch time, in milliseconds 18994bf2b033SGunnar Mills // https://github.com/openbmc/phosphor-dbus-interfaces/blob/7f9a128eb9296e926422ddc312c148b625890bb6/xyz/openbmc_project/State/BMC.interface.yaml#L19 19004bf2b033SGunnar Mills time_t lastResetTimeStamp = 19014bf2b033SGunnar Mills static_cast<time_t>(*lastResetTimePtr / 1000); 19024bf2b033SGunnar Mills 19034bf2b033SGunnar Mills // Convert to ISO 8601 standard 19044bf2b033SGunnar Mills aResp->res.jsonValue["LastResetTime"] = 19054bf2b033SGunnar Mills crow::utility::getDateTime(lastResetTimeStamp); 19064bf2b033SGunnar Mills }, 19074bf2b033SGunnar Mills "xyz.openbmc_project.State.BMC", "/xyz/openbmc_project/state/bmc0", 19084bf2b033SGunnar Mills "org.freedesktop.DBus.Properties", "Get", 19094bf2b033SGunnar Mills "xyz.openbmc_project.State.BMC", "LastRebootTime"); 19104bf2b033SGunnar Mills } 19114bf2b033SGunnar Mills 19124bfefa74SGunnar Mills /** 19134bfefa74SGunnar Mills * @brief Set the running firmware image 19144bfefa74SGunnar Mills * 19154bfefa74SGunnar Mills * @param[i,o] aResp - Async response object 19164bfefa74SGunnar Mills * @param[i] runningFirmwareTarget - Image to make the running image 19174bfefa74SGunnar Mills * 19184bfefa74SGunnar Mills * @return void 19194bfefa74SGunnar Mills */ 19204bfefa74SGunnar Mills void setActiveFirmwareImage(std::shared_ptr<AsyncResp> aResp, 19214bfefa74SGunnar Mills const std::string&& runningFirmwareTarget) 19224bfefa74SGunnar Mills { 19234bfefa74SGunnar Mills // Get the Id from /redfish/v1/UpdateService/FirmwareInventory/<Id> 19244bfefa74SGunnar Mills std::string::size_type idPos = runningFirmwareTarget.rfind("/"); 19254bfefa74SGunnar Mills if (idPos == std::string::npos) 19264bfefa74SGunnar Mills { 19274bfefa74SGunnar Mills messages::propertyValueNotInList(aResp->res, runningFirmwareTarget, 19284bfefa74SGunnar Mills "@odata.id"); 19294bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "Can't parse firmware ID!"; 19304bfefa74SGunnar Mills return; 19314bfefa74SGunnar Mills } 19324bfefa74SGunnar Mills idPos++; 19334bfefa74SGunnar Mills if (idPos >= runningFirmwareTarget.size()) 19344bfefa74SGunnar Mills { 19354bfefa74SGunnar Mills messages::propertyValueNotInList(aResp->res, runningFirmwareTarget, 19364bfefa74SGunnar Mills "@odata.id"); 19374bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid firmware ID."; 19384bfefa74SGunnar Mills return; 19394bfefa74SGunnar Mills } 19404bfefa74SGunnar Mills std::string firmwareId = runningFirmwareTarget.substr(idPos); 19414bfefa74SGunnar Mills 19424bfefa74SGunnar Mills // Make sure the image is valid before setting priority 19434bfefa74SGunnar Mills crow::connections::systemBus->async_method_call( 19444bfefa74SGunnar Mills [aResp, firmwareId, 19454bfefa74SGunnar Mills runningFirmwareTarget](const boost::system::error_code ec, 19464bfefa74SGunnar Mills ManagedObjectType& subtree) { 19474bfefa74SGunnar Mills if (ec) 19484bfefa74SGunnar Mills { 19494bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "D-Bus response error getting objects."; 19504bfefa74SGunnar Mills messages::internalError(aResp->res); 19514bfefa74SGunnar Mills return; 19524bfefa74SGunnar Mills } 19534bfefa74SGunnar Mills 19544bfefa74SGunnar Mills if (subtree.size() == 0) 19554bfefa74SGunnar Mills { 19564bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "Can't find image!"; 19574bfefa74SGunnar Mills messages::internalError(aResp->res); 19584bfefa74SGunnar Mills return; 19594bfefa74SGunnar Mills } 19604bfefa74SGunnar Mills 19614bfefa74SGunnar Mills bool foundImage = false; 19624bfefa74SGunnar Mills for (auto& object : subtree) 19634bfefa74SGunnar Mills { 19644bfefa74SGunnar Mills const std::string& path = 19654bfefa74SGunnar Mills static_cast<const std::string&>(object.first); 19664bfefa74SGunnar Mills std::size_t idPos2 = path.rfind("/"); 19674bfefa74SGunnar Mills 19684bfefa74SGunnar Mills if (idPos2 == std::string::npos) 19694bfefa74SGunnar Mills { 19704bfefa74SGunnar Mills continue; 19714bfefa74SGunnar Mills } 19724bfefa74SGunnar Mills 19734bfefa74SGunnar Mills idPos2++; 19744bfefa74SGunnar Mills if (idPos2 >= path.size()) 19754bfefa74SGunnar Mills { 19764bfefa74SGunnar Mills continue; 19774bfefa74SGunnar Mills } 19784bfefa74SGunnar Mills 19794bfefa74SGunnar Mills if (path.substr(idPos2) == firmwareId) 19804bfefa74SGunnar Mills { 19814bfefa74SGunnar Mills foundImage = true; 19824bfefa74SGunnar Mills break; 19834bfefa74SGunnar Mills } 19844bfefa74SGunnar Mills } 19854bfefa74SGunnar Mills 19864bfefa74SGunnar Mills if (!foundImage) 19874bfefa74SGunnar Mills { 19884bfefa74SGunnar Mills messages::propertyValueNotInList( 19894bfefa74SGunnar Mills aResp->res, runningFirmwareTarget, "@odata.id"); 19904bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid firmware ID."; 19914bfefa74SGunnar Mills return; 19924bfefa74SGunnar Mills } 19934bfefa74SGunnar Mills 19944bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "Setting firmware version " + firmwareId + 19954bfefa74SGunnar Mills " to priority 0."; 19964bfefa74SGunnar Mills 19974bfefa74SGunnar Mills // Only support Immediate 19984bfefa74SGunnar Mills // An addition could be a Redfish Setting like 19994bfefa74SGunnar Mills // ActiveSoftwareImageApplyTime and support OnReset 20004bfefa74SGunnar Mills crow::connections::systemBus->async_method_call( 20014bfefa74SGunnar Mills [aResp](const boost::system::error_code ec) { 20024bfefa74SGunnar Mills if (ec) 20034bfefa74SGunnar Mills { 20044bfefa74SGunnar Mills BMCWEB_LOG_DEBUG << "D-Bus response error setting."; 20054bfefa74SGunnar Mills messages::internalError(aResp->res); 20064bfefa74SGunnar Mills return; 20074bfefa74SGunnar Mills } 20084bfefa74SGunnar Mills doBMCGracefulRestart(aResp); 20094bfefa74SGunnar Mills }, 20104bfefa74SGunnar Mills 20114bfefa74SGunnar Mills "xyz.openbmc_project.Software.BMC.Updater", 20124bfefa74SGunnar Mills "/xyz/openbmc_project/software/" + firmwareId, 20134bfefa74SGunnar Mills "org.freedesktop.DBus.Properties", "Set", 20144bfefa74SGunnar Mills "xyz.openbmc_project.Software.RedundancyPriority", 20154bfefa74SGunnar Mills "Priority", std::variant<uint8_t>(static_cast<uint8_t>(0))); 20164bfefa74SGunnar Mills }, 20174bfefa74SGunnar Mills "xyz.openbmc_project.Software.BMC.Updater", 20184bfefa74SGunnar Mills "/xyz/openbmc_project/software", 20194bfefa74SGunnar Mills "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 20204bfefa74SGunnar Mills } 20214bfefa74SGunnar Mills 2022af5d6058SSantosh Puranik void setDateTime(std::shared_ptr<AsyncResp> aResp, 2023af5d6058SSantosh Puranik std::string datetime) const 2024af5d6058SSantosh Puranik { 2025af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Set date time: " << datetime; 2026af5d6058SSantosh Puranik 2027af5d6058SSantosh Puranik std::stringstream stream(datetime); 2028af5d6058SSantosh Puranik // Convert from ISO 8601 to boost local_time 2029af5d6058SSantosh Puranik // (BMC only has time in UTC) 2030af5d6058SSantosh Puranik boost::posix_time::ptime posixTime; 2031af5d6058SSantosh Puranik boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); 2032af5d6058SSantosh Puranik // Facet gets deleted with the stringsteam 2033af5d6058SSantosh Puranik auto ifc = std::make_unique<boost::local_time::local_time_input_facet>( 2034af5d6058SSantosh Puranik "%Y-%m-%d %H:%M:%S%F %ZP"); 2035af5d6058SSantosh Puranik stream.imbue(std::locale(stream.getloc(), ifc.release())); 2036af5d6058SSantosh Puranik 2037af5d6058SSantosh Puranik boost::local_time::local_date_time ldt( 2038af5d6058SSantosh Puranik boost::local_time::not_a_date_time); 2039af5d6058SSantosh Puranik 2040af5d6058SSantosh Puranik if (stream >> ldt) 2041af5d6058SSantosh Puranik { 2042af5d6058SSantosh Puranik posixTime = ldt.utc_time(); 2043af5d6058SSantosh Puranik boost::posix_time::time_duration dur = posixTime - epoch; 2044af5d6058SSantosh Puranik uint64_t durMicroSecs = 2045af5d6058SSantosh Puranik static_cast<uint64_t>(dur.total_microseconds()); 2046af5d6058SSantosh Puranik crow::connections::systemBus->async_method_call( 2047af5d6058SSantosh Puranik [aResp{std::move(aResp)}, datetime{std::move(datetime)}]( 2048af5d6058SSantosh Puranik const boost::system::error_code ec) { 2049af5d6058SSantosh Puranik if (ec) 2050af5d6058SSantosh Puranik { 2051af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Failed to set elapsed time. " 2052af5d6058SSantosh Puranik "DBUS response error " 2053af5d6058SSantosh Puranik << ec; 2054af5d6058SSantosh Puranik messages::internalError(aResp->res); 2055af5d6058SSantosh Puranik return; 2056af5d6058SSantosh Puranik } 2057af5d6058SSantosh Puranik aResp->res.jsonValue["DateTime"] = datetime; 2058af5d6058SSantosh Puranik }, 2059af5d6058SSantosh Puranik "xyz.openbmc_project.Time.Manager", 2060af5d6058SSantosh Puranik "/xyz/openbmc_project/time/bmc", 2061af5d6058SSantosh Puranik "org.freedesktop.DBus.Properties", "Set", 2062af5d6058SSantosh Puranik "xyz.openbmc_project.Time.EpochTime", "Elapsed", 2063af5d6058SSantosh Puranik std::variant<uint64_t>(durMicroSecs)); 2064af5d6058SSantosh Puranik } 2065af5d6058SSantosh Puranik else 2066af5d6058SSantosh Puranik { 2067af5d6058SSantosh Puranik messages::propertyValueFormatError(aResp->res, datetime, 2068af5d6058SSantosh Puranik "DateTime"); 2069af5d6058SSantosh Puranik return; 2070af5d6058SSantosh Puranik } 207183ff9ab6SJames Feist } 20729c310685SBorawski.Lukasz 20730f74e643SEd Tanous std::string uuid; 20749c310685SBorawski.Lukasz }; 20759c310685SBorawski.Lukasz 20761abe55efSEd Tanous class ManagerCollection : public Node 20771abe55efSEd Tanous { 20789c310685SBorawski.Lukasz public: 207952cc112dSEd Tanous ManagerCollection(App& app) : Node(app, "/redfish/v1/Managers/") 20801abe55efSEd Tanous { 2081a434f2bdSEd Tanous entityPrivileges = { 2082a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 2083e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 2084e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 2085e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 2086e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 2087e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 20889c310685SBorawski.Lukasz } 20899c310685SBorawski.Lukasz 20909c310685SBorawski.Lukasz private: 209155c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 20921abe55efSEd Tanous const std::vector<std::string>& params) override 20931abe55efSEd Tanous { 209483ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 209583ff9ab6SJames Feist // because it has a duplicate entry for members 209655c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 209755c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 209855c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 209955c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 210055c7b7a2SEd Tanous res.jsonValue["Members"] = { 21015b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 21029c310685SBorawski.Lukasz res.end(); 21039c310685SBorawski.Lukasz } 21049c310685SBorawski.Lukasz }; 21059c310685SBorawski.Lukasz } // namespace redfish 2106