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 189c310685SBorawski.Lukasz #include "node.hpp" 199c310685SBorawski.Lukasz 205b4aa86bSJames Feist #include <boost/algorithm/string/replace.hpp> 215b4aa86bSJames Feist #include <dbus_utility.hpp> 225b4aa86bSJames Feist 231abe55efSEd Tanous namespace redfish 241abe55efSEd Tanous { 25*ed5befbdSJennifer Lee 26*ed5befbdSJennifer Lee /** 27*ed5befbdSJennifer Lee * ManagerActionsReset class supports handle POST method for Reset action. 28*ed5befbdSJennifer Lee * The class retrieves and sends data directly to dbus. 29*ed5befbdSJennifer Lee */ 30*ed5befbdSJennifer Lee class ManagerActionsReset : public Node 31*ed5befbdSJennifer Lee { 32*ed5befbdSJennifer Lee public: 33*ed5befbdSJennifer Lee ManagerActionsReset(CrowApp& app) : 34*ed5befbdSJennifer Lee Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/") 35*ed5befbdSJennifer Lee { 36*ed5befbdSJennifer Lee entityPrivileges = { 37*ed5befbdSJennifer Lee {boost::beast::http::verb::get, {{"Login"}}}, 38*ed5befbdSJennifer Lee {boost::beast::http::verb::head, {{"Login"}}}, 39*ed5befbdSJennifer Lee {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 40*ed5befbdSJennifer Lee {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 41*ed5befbdSJennifer Lee {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 42*ed5befbdSJennifer Lee {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 43*ed5befbdSJennifer Lee } 44*ed5befbdSJennifer Lee 45*ed5befbdSJennifer Lee private: 46*ed5befbdSJennifer Lee /** 47*ed5befbdSJennifer Lee * Function handles GET method request. 48*ed5befbdSJennifer Lee * ManagerActionReset supports for POST method, 49*ed5befbdSJennifer Lee * it is not required to retrieve more information in GET. 50*ed5befbdSJennifer Lee */ 51*ed5befbdSJennifer Lee void doGet(crow::Response& res, const crow::Request& req, 52*ed5befbdSJennifer Lee const std::vector<std::string>& params) override 53*ed5befbdSJennifer Lee { 54*ed5befbdSJennifer Lee res.jsonValue = Node::json; 55*ed5befbdSJennifer Lee res.end(); 56*ed5befbdSJennifer Lee } 57*ed5befbdSJennifer Lee 58*ed5befbdSJennifer Lee /** 59*ed5befbdSJennifer Lee * Function handles POST method request. 60*ed5befbdSJennifer Lee * Analyzes POST body message before sends Reset request data to dbus. 61*ed5befbdSJennifer Lee * OpenBMC allows for ResetType is GracefulRestart only. 62*ed5befbdSJennifer Lee */ 63*ed5befbdSJennifer Lee void doPost(crow::Response& res, const crow::Request& req, 64*ed5befbdSJennifer Lee const std::vector<std::string>& params) override 65*ed5befbdSJennifer Lee { 66*ed5befbdSJennifer Lee std::string resetType; 67*ed5befbdSJennifer Lee 68*ed5befbdSJennifer Lee if (!json_util::readJson(req, res, "ResetType", resetType)) 69*ed5befbdSJennifer Lee { 70*ed5befbdSJennifer Lee return; 71*ed5befbdSJennifer Lee } 72*ed5befbdSJennifer Lee 73*ed5befbdSJennifer Lee if (resetType != "GracefulRestart") 74*ed5befbdSJennifer Lee { 75*ed5befbdSJennifer Lee res.result(boost::beast::http::status::bad_request); 76*ed5befbdSJennifer Lee messages::actionParameterNotSupported(res, resetType, "ResetType"); 77*ed5befbdSJennifer Lee BMCWEB_LOG_ERROR << "Request incorrect action parameter: " 78*ed5befbdSJennifer Lee << resetType; 79*ed5befbdSJennifer Lee res.end(); 80*ed5befbdSJennifer Lee return; 81*ed5befbdSJennifer Lee } 82*ed5befbdSJennifer Lee doBMCGracefulRestart(res, req, params); 83*ed5befbdSJennifer Lee } 84*ed5befbdSJennifer Lee 85*ed5befbdSJennifer Lee /** 86*ed5befbdSJennifer Lee * Function transceives data with dbus directly. 87*ed5befbdSJennifer Lee * All BMC state properties will be retrieved before sending reset request. 88*ed5befbdSJennifer Lee */ 89*ed5befbdSJennifer Lee void doBMCGracefulRestart(crow::Response& res, const crow::Request& req, 90*ed5befbdSJennifer Lee const std::vector<std::string>& params) 91*ed5befbdSJennifer Lee { 92*ed5befbdSJennifer Lee const char* processName = "xyz.openbmc_project.State.BMC"; 93*ed5befbdSJennifer Lee const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 94*ed5befbdSJennifer Lee const char* interfaceName = "xyz.openbmc_project.State.BMC"; 95*ed5befbdSJennifer Lee const std::string& propertyValue = 96*ed5befbdSJennifer Lee "xyz.openbmc_project.State.BMC.Transition.Reboot"; 97*ed5befbdSJennifer Lee const char* destProperty = "RequestedBMCTransition"; 98*ed5befbdSJennifer Lee 99*ed5befbdSJennifer Lee // Create the D-Bus variant for D-Bus call. 100*ed5befbdSJennifer Lee VariantType dbusPropertyValue(propertyValue); 101*ed5befbdSJennifer Lee 102*ed5befbdSJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 103*ed5befbdSJennifer Lee 104*ed5befbdSJennifer Lee crow::connections::systemBus->async_method_call( 105*ed5befbdSJennifer Lee [asyncResp](const boost::system::error_code ec) { 106*ed5befbdSJennifer Lee // Use "Set" method to set the property value. 107*ed5befbdSJennifer Lee if (ec) 108*ed5befbdSJennifer Lee { 109*ed5befbdSJennifer Lee BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec; 110*ed5befbdSJennifer Lee messages::internalError(asyncResp->res); 111*ed5befbdSJennifer Lee return; 112*ed5befbdSJennifer Lee } 113*ed5befbdSJennifer Lee 114*ed5befbdSJennifer Lee messages::success(asyncResp->res); 115*ed5befbdSJennifer Lee }, 116*ed5befbdSJennifer Lee processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 117*ed5befbdSJennifer Lee interfaceName, destProperty, dbusPropertyValue); 118*ed5befbdSJennifer Lee } 119*ed5befbdSJennifer Lee }; 120*ed5befbdSJennifer Lee 1215b4aa86bSJames Feist static constexpr const char* objectManagerIface = 1225b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 1235b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 1245b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 1255b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 1265b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 1279c310685SBorawski.Lukasz 1285b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection, 1295b4aa86bSJames Feist const std::string& path, 1305b4aa86bSJames Feist std::shared_ptr<AsyncResp> asyncResp) 1315b4aa86bSJames Feist { 1325b4aa86bSJames Feist 1335b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 1345b4aa86bSJames Feist [asyncResp](const boost::system::error_code ec, 1355b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 1365b4aa86bSJames Feist if (ec) 1375b4aa86bSJames Feist { 1385b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 1395b4aa86bSJames Feist asyncResp->res.jsonValue.clear(); 140f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1415b4aa86bSJames Feist return; 1425b4aa86bSJames Feist } 1435b4aa86bSJames Feist nlohmann::json& configRoot = 1445b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 1455b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 1465b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 1475b4aa86bSJames Feist fans["@odata.context"] = 1485b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanControllers"; 1495b4aa86bSJames Feist fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" 1505b4aa86bSJames Feist "Fan/FanControllers"; 1515b4aa86bSJames Feist 1525b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 1535b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 1545b4aa86bSJames Feist pids["@odata.context"] = 1555b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.PidControllers"; 1565b4aa86bSJames Feist pids["@odata.id"] = 1575b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; 1585b4aa86bSJames Feist 1595b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 1605b4aa86bSJames Feist zones["@odata.id"] = 1615b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; 1625b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 1635b4aa86bSJames Feist zones["@odata.context"] = 1645b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanZones"; 1655b4aa86bSJames Feist configRoot["@odata.id"] = 1665b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; 1675b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 1685b4aa86bSJames Feist configRoot["@odata.context"] = 1695b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.Fan"; 1705b4aa86bSJames Feist 1715b4aa86bSJames Feist bool propertyError = false; 1725b4aa86bSJames Feist for (const auto& pathPair : managedObj) 1735b4aa86bSJames Feist { 1745b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 1755b4aa86bSJames Feist { 1765b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 1775b4aa86bSJames Feist intfPair.first != pidZoneConfigurationIface) 1785b4aa86bSJames Feist { 1795b4aa86bSJames Feist continue; 1805b4aa86bSJames Feist } 1815b4aa86bSJames Feist auto findName = intfPair.second.find("Name"); 1825b4aa86bSJames Feist if (findName == intfPair.second.end()) 1835b4aa86bSJames Feist { 1845b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Field missing Name"; 185f12894f8SJason M. Bills messages::internalError(asyncResp->res, "Name"); 1865b4aa86bSJames Feist return; 1875b4aa86bSJames Feist } 1885b4aa86bSJames Feist const std::string* namePtr = 1895b4aa86bSJames Feist mapbox::getPtr<const std::string>(findName->second); 1905b4aa86bSJames Feist if (namePtr == nullptr) 1915b4aa86bSJames Feist { 1925b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Name Field illegal"; 1935b4aa86bSJames Feist return; 1945b4aa86bSJames Feist } 1955b4aa86bSJames Feist 1965b4aa86bSJames Feist std::string name = *namePtr; 1975b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 1985b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 1995b4aa86bSJames Feist { 2005b4aa86bSJames Feist std::string chassis; 2015b4aa86bSJames Feist if (!dbus::utility::getNthStringFromPath( 2025b4aa86bSJames Feist pathPair.first.str, 5, chassis)) 2035b4aa86bSJames Feist { 2045b4aa86bSJames Feist chassis = "#IllegalValue"; 2055b4aa86bSJames Feist } 2065b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 2075b4aa86bSJames Feist zone["Chassis"] = { 2085b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; 2095b4aa86bSJames Feist zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" 2105b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 2115b4aa86bSJames Feist name; 2125b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 2135b4aa86bSJames Feist zone["@odata.context"] = 2145b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanZone"; 2155b4aa86bSJames Feist } 2165b4aa86bSJames Feist 2175b4aa86bSJames Feist for (const auto& propertyPair : intfPair.second) 2185b4aa86bSJames Feist { 2195b4aa86bSJames Feist if (propertyPair.first == "Type" || 2205b4aa86bSJames Feist propertyPair.first == "Class" || 2215b4aa86bSJames Feist propertyPair.first == "Name") 2225b4aa86bSJames Feist { 2235b4aa86bSJames Feist continue; 2245b4aa86bSJames Feist } 2255b4aa86bSJames Feist 2265b4aa86bSJames Feist // zones 2275b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 2285b4aa86bSJames Feist { 2295b4aa86bSJames Feist const double* ptr = mapbox::getPtr<const double>( 2305b4aa86bSJames Feist propertyPair.second); 2315b4aa86bSJames Feist if (ptr == nullptr) 2325b4aa86bSJames Feist { 2335b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 2345b4aa86bSJames Feist << propertyPair.first; 235f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2365b4aa86bSJames Feist return; 2375b4aa86bSJames Feist } 2385b4aa86bSJames Feist zones[name][propertyPair.first] = *ptr; 2395b4aa86bSJames Feist } 2405b4aa86bSJames Feist 2415b4aa86bSJames Feist // pid and fans are off the same configuration 2425b4aa86bSJames Feist if (intfPair.first == pidConfigurationIface) 2435b4aa86bSJames Feist { 2445b4aa86bSJames Feist const std::string* classPtr = nullptr; 2455b4aa86bSJames Feist auto findClass = intfPair.second.find("Class"); 2465b4aa86bSJames Feist if (findClass != intfPair.second.end()) 2475b4aa86bSJames Feist { 2485b4aa86bSJames Feist classPtr = mapbox::getPtr<const std::string>( 2495b4aa86bSJames Feist findClass->second); 2505b4aa86bSJames Feist } 2515b4aa86bSJames Feist if (classPtr == nullptr) 2525b4aa86bSJames Feist { 2535b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 254f12894f8SJason M. Bills messages::internalError(asyncResp->res, 255f12894f8SJason M. Bills "Class"); 2565b4aa86bSJames Feist return; 2575b4aa86bSJames Feist } 2585b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 2595b4aa86bSJames Feist nlohmann::json& element = 2605b4aa86bSJames Feist isFan ? fans[name] : pids[name]; 2615b4aa86bSJames Feist if (isFan) 2625b4aa86bSJames Feist { 2635b4aa86bSJames Feist element["@odata.id"] = 2645b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 2655b4aa86bSJames Feist "OpenBmc/Fan/FanControllers/" + 2665b4aa86bSJames Feist std::string(name); 2675b4aa86bSJames Feist element["@odata.type"] = 2685b4aa86bSJames Feist "#OemManager.FanController"; 2695b4aa86bSJames Feist 2705b4aa86bSJames Feist element["@odata.context"] = 2715b4aa86bSJames Feist "/redfish/v1/" 2725b4aa86bSJames Feist "$metadata#OemManager.FanController"; 2735b4aa86bSJames Feist } 2745b4aa86bSJames Feist else 2755b4aa86bSJames Feist { 2765b4aa86bSJames Feist element["@odata.id"] = 2775b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 2785b4aa86bSJames Feist "OpenBmc/Fan/PidControllers/" + 2795b4aa86bSJames Feist std::string(name); 2805b4aa86bSJames Feist element["@odata.type"] = 2815b4aa86bSJames Feist "#OemManager.PidController"; 2825b4aa86bSJames Feist element["@odata.context"] = 2835b4aa86bSJames Feist "/redfish/v1/$metadata" 2845b4aa86bSJames Feist "#OemManager.PidController"; 2855b4aa86bSJames Feist } 2865b4aa86bSJames Feist 2875b4aa86bSJames Feist if (propertyPair.first == "Zones") 2885b4aa86bSJames Feist { 2895b4aa86bSJames Feist const std::vector<std::string>* inputs = 2905b4aa86bSJames Feist mapbox::getPtr< 2915b4aa86bSJames Feist const std::vector<std::string>>( 2925b4aa86bSJames Feist propertyPair.second); 2935b4aa86bSJames Feist 2945b4aa86bSJames Feist if (inputs == nullptr) 2955b4aa86bSJames Feist { 2965b4aa86bSJames Feist BMCWEB_LOG_ERROR 2975b4aa86bSJames Feist << "Zones Pid Field Illegal"; 298f12894f8SJason M. Bills messages::internalError(asyncResp->res, 299f12894f8SJason M. Bills "Zones"); 3005b4aa86bSJames Feist return; 3015b4aa86bSJames Feist } 3025b4aa86bSJames Feist auto& data = element[propertyPair.first]; 3035b4aa86bSJames Feist data = nlohmann::json::array(); 3045b4aa86bSJames Feist for (std::string itemCopy : *inputs) 3055b4aa86bSJames Feist { 3065b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 3075b4aa86bSJames Feist data.push_back( 3085b4aa86bSJames Feist {{"@odata.id", 3095b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 3105b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 3115b4aa86bSJames Feist itemCopy}}); 3125b4aa86bSJames Feist } 3135b4aa86bSJames Feist } 3145b4aa86bSJames Feist // todo(james): may never happen, but this 3155b4aa86bSJames Feist // assumes configuration data referenced in the 3165b4aa86bSJames Feist // PID config is provided by the same daemon, we 3175b4aa86bSJames Feist // could add another loop to cover all cases, 3185b4aa86bSJames Feist // but I'm okay kicking this can down the road a 3195b4aa86bSJames Feist // bit 3205b4aa86bSJames Feist 3215b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 3225b4aa86bSJames Feist propertyPair.first == "Outputs") 3235b4aa86bSJames Feist { 3245b4aa86bSJames Feist auto& data = element[propertyPair.first]; 3255b4aa86bSJames Feist const std::vector<std::string>* inputs = 3265b4aa86bSJames Feist mapbox::getPtr< 3275b4aa86bSJames Feist const std::vector<std::string>>( 3285b4aa86bSJames Feist propertyPair.second); 3295b4aa86bSJames Feist 3305b4aa86bSJames Feist if (inputs == nullptr) 3315b4aa86bSJames Feist { 3325b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 3335b4aa86bSJames Feist << propertyPair.first; 334f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3355b4aa86bSJames Feist return; 3365b4aa86bSJames Feist } 3375b4aa86bSJames Feist data = *inputs; 3385b4aa86bSJames Feist } // doubles 3395b4aa86bSJames Feist else if (propertyPair.first == 3405b4aa86bSJames Feist "FFGainCoefficient" || 3415b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 3425b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 3435b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 3445b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 3455b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 3465b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 3475b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 3485b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 3495b4aa86bSJames Feist propertyPair.first == "SlewPos") 3505b4aa86bSJames Feist { 3515b4aa86bSJames Feist const double* ptr = 3525b4aa86bSJames Feist mapbox::getPtr<const double>( 3535b4aa86bSJames Feist propertyPair.second); 3545b4aa86bSJames Feist if (ptr == nullptr) 3555b4aa86bSJames Feist { 3565b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 3575b4aa86bSJames Feist << propertyPair.first; 358f12894f8SJason M. Bills messages::internalError(asyncResp->res); 3595b4aa86bSJames Feist return; 3605b4aa86bSJames Feist } 3615b4aa86bSJames Feist element[propertyPair.first] = *ptr; 3625b4aa86bSJames Feist } 3635b4aa86bSJames Feist } 3645b4aa86bSJames Feist } 3655b4aa86bSJames Feist } 3665b4aa86bSJames Feist } 3675b4aa86bSJames Feist }, 3685b4aa86bSJames Feist connection, path, objectManagerIface, "GetManagedObjects"); 3695b4aa86bSJames Feist } 370ca537928SJennifer Lee 37183ff9ab6SJames Feist enum class CreatePIDRet 37283ff9ab6SJames Feist { 37383ff9ab6SJames Feist fail, 37483ff9ab6SJames Feist del, 37583ff9ab6SJames Feist patch 37683ff9ab6SJames Feist }; 37783ff9ab6SJames Feist 37883ff9ab6SJames Feist static CreatePIDRet createPidInterface( 37983ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 38083ff9ab6SJames Feist const nlohmann::json& record, const std::string& path, 38183ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 38283ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 38383ff9ab6SJames Feist output, 38483ff9ab6SJames Feist std::string& chassis) 38583ff9ab6SJames Feist { 38683ff9ab6SJames Feist 38783ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 38883ff9ab6SJames Feist { 38983ff9ab6SJames Feist if (createNewObject) 39083ff9ab6SJames Feist { 39183ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 39283ff9ab6SJames Feist : std::string("fan"); 39383ff9ab6SJames Feist output["Type"] = std::string("Pid"); 39483ff9ab6SJames Feist } 39583ff9ab6SJames Feist else if (record == nullptr) 39683ff9ab6SJames Feist { 39783ff9ab6SJames Feist // delete interface 39883ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 39983ff9ab6SJames Feist [response, 40083ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 40183ff9ab6SJames Feist if (ec) 40283ff9ab6SJames Feist { 40383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 40483ff9ab6SJames Feist << ec; 40535a62c7cSJason M. Bills messages::internalError(response->res); 40683ff9ab6SJames Feist } 40783ff9ab6SJames Feist }, 40883ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 40983ff9ab6SJames Feist pidConfigurationIface, "Delete"); 41083ff9ab6SJames Feist return CreatePIDRet::del; 41183ff9ab6SJames Feist } 41283ff9ab6SJames Feist 41383ff9ab6SJames Feist for (auto& field : record.items()) 41483ff9ab6SJames Feist { 41583ff9ab6SJames Feist if (field.key() == "Zones") 41683ff9ab6SJames Feist { 41783ff9ab6SJames Feist if (!field.value().is_array()) 41883ff9ab6SJames Feist { 41983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 42035a62c7cSJason M. Bills messages::propertyValueFormatError( 42135a62c7cSJason M. Bills response->res, field.value(), field.key()); 42283ff9ab6SJames Feist return CreatePIDRet::fail; 42383ff9ab6SJames Feist } 42483ff9ab6SJames Feist std::vector<std::string> inputs; 42583ff9ab6SJames Feist for (const auto& odata : field.value().items()) 42683ff9ab6SJames Feist { 42783ff9ab6SJames Feist for (const auto& value : odata.value().items()) 42883ff9ab6SJames Feist { 42983ff9ab6SJames Feist const std::string* path = 43083ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 43183ff9ab6SJames Feist if (path == nullptr) 43283ff9ab6SJames Feist { 43383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 43483ff9ab6SJames Feist messages::propertyValueFormatError( 43535a62c7cSJason M. Bills response->res, field.value().dump(), 43635a62c7cSJason M. Bills field.key()); 43783ff9ab6SJames Feist return CreatePIDRet::fail; 43883ff9ab6SJames Feist } 43983ff9ab6SJames Feist std::string input; 44083ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*path, 4, 44183ff9ab6SJames Feist input)) 44283ff9ab6SJames Feist { 44383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *path; 44483ff9ab6SJames Feist messages::propertyValueFormatError( 44535a62c7cSJason M. Bills response->res, field.value().dump(), 44635a62c7cSJason M. Bills field.key()); 44783ff9ab6SJames Feist return CreatePIDRet::fail; 44883ff9ab6SJames Feist } 44983ff9ab6SJames Feist boost::replace_all(input, "_", " "); 45083ff9ab6SJames Feist inputs.emplace_back(std::move(input)); 45183ff9ab6SJames Feist } 45283ff9ab6SJames Feist } 45383ff9ab6SJames Feist output["Zones"] = std::move(inputs); 45483ff9ab6SJames Feist } 45583ff9ab6SJames Feist else if (field.key() == "Inputs" || field.key() == "Outputs") 45683ff9ab6SJames Feist { 45783ff9ab6SJames Feist if (!field.value().is_array()) 45883ff9ab6SJames Feist { 45983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 46035a62c7cSJason M. Bills messages::propertyValueFormatError( 46135a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 46283ff9ab6SJames Feist return CreatePIDRet::fail; 46383ff9ab6SJames Feist } 46483ff9ab6SJames Feist std::vector<std::string> inputs; 46583ff9ab6SJames Feist for (const auto& value : field.value().items()) 46683ff9ab6SJames Feist { 46783ff9ab6SJames Feist const std::string* sensor = 46883ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 46983ff9ab6SJames Feist 47083ff9ab6SJames Feist if (sensor == nullptr) 47183ff9ab6SJames Feist { 47283ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " 47383ff9ab6SJames Feist << field.value().dump(); 47483ff9ab6SJames Feist messages::propertyValueFormatError( 47535a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 47683ff9ab6SJames Feist return CreatePIDRet::fail; 47783ff9ab6SJames Feist } 47883ff9ab6SJames Feist 47983ff9ab6SJames Feist std::string input = 48083ff9ab6SJames Feist boost::replace_all_copy(*sensor, "_", " "); 48183ff9ab6SJames Feist inputs.push_back(std::move(input)); 48283ff9ab6SJames Feist // try to find the sensor in the 48383ff9ab6SJames Feist // configuration 48483ff9ab6SJames Feist if (chassis.empty()) 48583ff9ab6SJames Feist { 48683ff9ab6SJames Feist std::find_if( 48783ff9ab6SJames Feist managedObj.begin(), managedObj.end(), 48883ff9ab6SJames Feist [&chassis, sensor](const auto& obj) { 48983ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 49083ff9ab6SJames Feist *sensor)) 49183ff9ab6SJames Feist { 49283ff9ab6SJames Feist return dbus::utility::getNthStringFromPath( 49383ff9ab6SJames Feist obj.first.str, 5, chassis); 49483ff9ab6SJames Feist } 49583ff9ab6SJames Feist return false; 49683ff9ab6SJames Feist }); 49783ff9ab6SJames Feist } 49883ff9ab6SJames Feist } 49983ff9ab6SJames Feist output[field.key()] = inputs; 50083ff9ab6SJames Feist } 50183ff9ab6SJames Feist 50283ff9ab6SJames Feist // doubles 50383ff9ab6SJames Feist else if (field.key() == "FFGainCoefficient" || 50483ff9ab6SJames Feist field.key() == "FFOffCoefficient" || 50583ff9ab6SJames Feist field.key() == "ICoefficient" || 50683ff9ab6SJames Feist field.key() == "ILimitMax" || field.key() == "ILimitMin" || 50783ff9ab6SJames Feist field.key() == "OutLimitMax" || 50883ff9ab6SJames Feist field.key() == "OutLimitMin" || 50983ff9ab6SJames Feist field.key() == "PCoefficient" || 51083ff9ab6SJames Feist field.key() == "SetPoint" || field.key() == "SlewNeg" || 51183ff9ab6SJames Feist field.key() == "SlewPos") 51283ff9ab6SJames Feist { 51383ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 51483ff9ab6SJames Feist if (ptr == nullptr) 51583ff9ab6SJames Feist { 51683ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 51735a62c7cSJason M. Bills messages::propertyValueFormatError( 51835a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 51983ff9ab6SJames Feist return CreatePIDRet::fail; 52083ff9ab6SJames Feist } 52183ff9ab6SJames Feist output[field.key()] = *ptr; 52283ff9ab6SJames Feist } 52383ff9ab6SJames Feist 52483ff9ab6SJames Feist else 52583ff9ab6SJames Feist { 52683ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 52735a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 52883ff9ab6SJames Feist return CreatePIDRet::fail; 52983ff9ab6SJames Feist } 53083ff9ab6SJames Feist } 53183ff9ab6SJames Feist } 53283ff9ab6SJames Feist else if (type == "FanZones") 53383ff9ab6SJames Feist { 53483ff9ab6SJames Feist if (!createNewObject && record == nullptr) 53583ff9ab6SJames Feist { 53683ff9ab6SJames Feist // delete interface 53783ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 53883ff9ab6SJames Feist [response, 53983ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 54083ff9ab6SJames Feist if (ec) 54183ff9ab6SJames Feist { 54283ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 54383ff9ab6SJames Feist << ec; 54435a62c7cSJason M. Bills messages::internalError(response->res); 54583ff9ab6SJames Feist } 54683ff9ab6SJames Feist }, 54783ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 54883ff9ab6SJames Feist pidZoneConfigurationIface, "Delete"); 54983ff9ab6SJames Feist return CreatePIDRet::del; 55083ff9ab6SJames Feist } 55183ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 55283ff9ab6SJames Feist 55383ff9ab6SJames Feist for (auto& field : record.items()) 55483ff9ab6SJames Feist { 55583ff9ab6SJames Feist if (field.key() == "Chassis") 55683ff9ab6SJames Feist { 55783ff9ab6SJames Feist const std::string* chassisId = nullptr; 55883ff9ab6SJames Feist for (const auto& id : field.value().items()) 55983ff9ab6SJames Feist { 56083ff9ab6SJames Feist if (id.key() != "@odata.id") 56183ff9ab6SJames Feist { 56283ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << id.key(); 56335a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 56483ff9ab6SJames Feist return CreatePIDRet::fail; 56583ff9ab6SJames Feist } 56683ff9ab6SJames Feist chassisId = id.value().get_ptr<const std::string*>(); 56783ff9ab6SJames Feist if (chassisId == nullptr) 56883ff9ab6SJames Feist { 56983ff9ab6SJames Feist messages::createFailedMissingReqProperties( 57035a62c7cSJason M. Bills response->res, field.key()); 57183ff9ab6SJames Feist return CreatePIDRet::fail; 57283ff9ab6SJames Feist } 57383ff9ab6SJames Feist } 57483ff9ab6SJames Feist 57583ff9ab6SJames Feist // /refish/v1/chassis/chassis_name/ 57683ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*chassisId, 3, 57783ff9ab6SJames Feist chassis)) 57883ff9ab6SJames Feist { 57983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId; 58035a62c7cSJason M. Bills messages::invalidObject(response->res, *chassisId); 58183ff9ab6SJames Feist return CreatePIDRet::fail; 58283ff9ab6SJames Feist } 58383ff9ab6SJames Feist } 58483ff9ab6SJames Feist else if (field.key() == "FailSafePercent" || 58583ff9ab6SJames Feist field.key() == "MinThermalRpm") 58683ff9ab6SJames Feist { 58783ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 58883ff9ab6SJames Feist if (ptr == nullptr) 58983ff9ab6SJames Feist { 59083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 59135a62c7cSJason M. Bills messages::propertyValueFormatError( 59235a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 59383ff9ab6SJames Feist return CreatePIDRet::fail; 59483ff9ab6SJames Feist } 59583ff9ab6SJames Feist output[field.key()] = *ptr; 59683ff9ab6SJames Feist } 59783ff9ab6SJames Feist else 59883ff9ab6SJames Feist { 59983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 60035a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 60183ff9ab6SJames Feist return CreatePIDRet::fail; 60283ff9ab6SJames Feist } 60383ff9ab6SJames Feist } 60483ff9ab6SJames Feist } 60583ff9ab6SJames Feist else 60683ff9ab6SJames Feist { 60783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type; 60835a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 60983ff9ab6SJames Feist return CreatePIDRet::fail; 61083ff9ab6SJames Feist } 61183ff9ab6SJames Feist return CreatePIDRet::patch; 61283ff9ab6SJames Feist } 61383ff9ab6SJames Feist 6141abe55efSEd Tanous class Manager : public Node 6151abe55efSEd Tanous { 6169c310685SBorawski.Lukasz public: 6175b4aa86bSJames Feist Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") 6181abe55efSEd Tanous { 6195b4aa86bSJames Feist Node::json["@odata.id"] = "/redfish/v1/Managers/bmc"; 6209c310685SBorawski.Lukasz Node::json["@odata.type"] = "#Manager.v1_3_0.Manager"; 6219c310685SBorawski.Lukasz Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager"; 6225b4aa86bSJames Feist Node::json["Id"] = "bmc"; 6239c310685SBorawski.Lukasz Node::json["Name"] = "OpenBmc Manager"; 6249c310685SBorawski.Lukasz Node::json["Description"] = "Baseboard Management Controller"; 6259c310685SBorawski.Lukasz Node::json["PowerState"] = "On"; 626ca537928SJennifer Lee Node::json["ManagerType"] = "BMC"; 6279c310685SBorawski.Lukasz Node::json["UUID"] = 62855c7b7a2SEd Tanous app.template getMiddleware<crow::persistent_data::Middleware>() 62955c7b7a2SEd Tanous .systemUuid; 6309c310685SBorawski.Lukasz Node::json["Model"] = "OpenBmc"; // TODO(ed), get model 631ca537928SJennifer Lee Node::json["EthernetInterfaces"] = { 6325b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 6333ebd75f7SEd Tanous 634a434f2bdSEd Tanous entityPrivileges = { 635a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 636e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 637e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 638e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 639e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 640e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 6415b4aa86bSJames Feist 6425b4aa86bSJames Feist // default oem data 6435b4aa86bSJames Feist nlohmann::json& oem = Node::json["Oem"]; 6445b4aa86bSJames Feist nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 6455b4aa86bSJames Feist oem["@odata.type"] = "#OemManager.Oem"; 6465b4aa86bSJames Feist oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 6475b4aa86bSJames Feist oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem"; 6485b4aa86bSJames Feist oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 6495b4aa86bSJames Feist oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 6505b4aa86bSJames Feist oemOpenbmc["@odata.context"] = 6515b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.OpenBmc"; 6529c310685SBorawski.Lukasz } 6539c310685SBorawski.Lukasz 6549c310685SBorawski.Lukasz private: 6555b4aa86bSJames Feist void getPidValues(std::shared_ptr<AsyncResp> asyncResp) 6565b4aa86bSJames Feist { 6575b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 6585b4aa86bSJames Feist [asyncResp](const boost::system::error_code ec, 6595b4aa86bSJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 6605b4aa86bSJames Feist if (ec) 6615b4aa86bSJames Feist { 6625b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 663f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6645b4aa86bSJames Feist return; 6655b4aa86bSJames Feist } 6665b4aa86bSJames Feist 6675b4aa86bSJames Feist // create map of <connection, path to objMgr>> 6685b4aa86bSJames Feist boost::container::flat_map<std::string, std::string> 6695b4aa86bSJames Feist objectMgrPaths; 6706bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 6715b4aa86bSJames Feist for (const auto& pathGroup : subtree) 6725b4aa86bSJames Feist { 6735b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 6745b4aa86bSJames Feist { 6756bce33bcSJames Feist auto findConnection = 6766bce33bcSJames Feist calledConnections.find(connectionGroup.first); 6776bce33bcSJames Feist if (findConnection != calledConnections.end()) 6786bce33bcSJames Feist { 6796bce33bcSJames Feist break; 6806bce33bcSJames Feist } 6815b4aa86bSJames Feist for (const std::string& interface : 6825b4aa86bSJames Feist connectionGroup.second) 6835b4aa86bSJames Feist { 6845b4aa86bSJames Feist if (interface == objectManagerIface) 6855b4aa86bSJames Feist { 6865b4aa86bSJames Feist objectMgrPaths[connectionGroup.first] = 6875b4aa86bSJames Feist pathGroup.first; 6885b4aa86bSJames Feist } 6895b4aa86bSJames Feist // this list is alphabetical, so we 6905b4aa86bSJames Feist // should have found the objMgr by now 6915b4aa86bSJames Feist if (interface == pidConfigurationIface || 6925b4aa86bSJames Feist interface == pidZoneConfigurationIface) 6935b4aa86bSJames Feist { 6945b4aa86bSJames Feist auto findObjMgr = 6955b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 6965b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 6975b4aa86bSJames Feist { 6985b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 6995b4aa86bSJames Feist << "Has no Object Manager"; 7005b4aa86bSJames Feist continue; 7015b4aa86bSJames Feist } 7026bce33bcSJames Feist 7036bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 7046bce33bcSJames Feist 7055b4aa86bSJames Feist asyncPopulatePid(findObjMgr->first, 7065b4aa86bSJames Feist findObjMgr->second, asyncResp); 7075b4aa86bSJames Feist break; 7085b4aa86bSJames Feist } 7095b4aa86bSJames Feist } 7105b4aa86bSJames Feist } 7115b4aa86bSJames Feist } 7125b4aa86bSJames Feist }, 7135b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 7145b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 7155b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 7165b4aa86bSJames Feist std::array<const char*, 3>{pidConfigurationIface, 7175b4aa86bSJames Feist pidZoneConfigurationIface, 7185b4aa86bSJames Feist objectManagerIface}); 7195b4aa86bSJames Feist } 7205b4aa86bSJames Feist 72155c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 7221abe55efSEd Tanous const std::vector<std::string>& params) override 7231abe55efSEd Tanous { 724*ed5befbdSJennifer Lee // Update Actions object. 725*ed5befbdSJennifer Lee nlohmann::json& manager_reset = Node::json["Actions"]["#Manager.Reset"]; 726*ed5befbdSJennifer Lee manager_reset["target"] = 727*ed5befbdSJennifer Lee "/redfish/v1/Managers/bmc/Actions/Manager.Reset"; 728*ed5befbdSJennifer Lee manager_reset["ResetType@Redfish.AllowableValues"] = { 729*ed5befbdSJennifer Lee "GracefulRestart"}; 730ca537928SJennifer Lee 7319c310685SBorawski.Lukasz Node::json["DateTime"] = getDateTime(); 732*ed5befbdSJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 733*ed5befbdSJennifer Lee asyncResp->res.jsonValue = Node::json; 7345b4aa86bSJames Feist 735ca537928SJennifer Lee crow::connections::systemBus->async_method_call( 736ca537928SJennifer Lee [asyncResp](const boost::system::error_code ec, 7375b4aa86bSJames Feist const dbus::utility::ManagedObjectType& resp) { 738ca537928SJennifer Lee if (ec) 739ca537928SJennifer Lee { 740ca537928SJennifer Lee BMCWEB_LOG_ERROR << "Error while getting Software Version"; 741f12894f8SJason M. Bills messages::internalError(asyncResp->res); 742ca537928SJennifer Lee return; 743ca537928SJennifer Lee } 744ca537928SJennifer Lee 745ca537928SJennifer Lee for (auto& objpath : resp) 746ca537928SJennifer Lee { 747ca537928SJennifer Lee for (auto& interface : objpath.second) 748ca537928SJennifer Lee { 749ca537928SJennifer Lee // If interface is xyz.openbmc_project.Software.Version, 750ca537928SJennifer Lee // this is what we're looking for. 751ca537928SJennifer Lee if (interface.first == 752ca537928SJennifer Lee "xyz.openbmc_project.Software.Version") 753ca537928SJennifer Lee { 754ca537928SJennifer Lee // Cut out everyting until last "/", ... 755ca537928SJennifer Lee const std::string& iface_id = objpath.first; 756ca537928SJennifer Lee for (auto& property : interface.second) 757ca537928SJennifer Lee { 758ca537928SJennifer Lee if (property.first == "Version") 759ca537928SJennifer Lee { 760ca537928SJennifer Lee const std::string* value = 761ca537928SJennifer Lee mapbox::getPtr<const std::string>( 762ca537928SJennifer Lee property.second); 763ca537928SJennifer Lee if (value == nullptr) 764ca537928SJennifer Lee { 765ca537928SJennifer Lee continue; 766ca537928SJennifer Lee } 767ca537928SJennifer Lee asyncResp->res 768ca537928SJennifer Lee .jsonValue["FirmwareVersion"] = *value; 769ca537928SJennifer Lee } 770ca537928SJennifer Lee } 771ca537928SJennifer Lee } 772ca537928SJennifer Lee } 773ca537928SJennifer Lee } 774ca537928SJennifer Lee }, 775ca537928SJennifer Lee "xyz.openbmc_project.Software.BMC.Updater", 776ca537928SJennifer Lee "/xyz/openbmc_project/software", 777ca537928SJennifer Lee "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7785b4aa86bSJames Feist getPidValues(asyncResp); 7795b4aa86bSJames Feist } 78083ff9ab6SJames Feist void setPidValues(std::shared_ptr<AsyncResp> response, 78183ff9ab6SJames Feist const nlohmann::json& data) 78283ff9ab6SJames Feist { 78383ff9ab6SJames Feist // todo(james): might make sense to do a mapper call here if this 78483ff9ab6SJames Feist // interface gets more traction 78583ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 78683ff9ab6SJames Feist [response, 78783ff9ab6SJames Feist data](const boost::system::error_code ec, 78883ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj) { 78983ff9ab6SJames Feist if (ec) 79083ff9ab6SJames Feist { 79183ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 79235a62c7cSJason M. Bills messages::internalError(response->res); 79383ff9ab6SJames Feist return; 79483ff9ab6SJames Feist } 79583ff9ab6SJames Feist for (const auto& type : data.items()) 79683ff9ab6SJames Feist { 79783ff9ab6SJames Feist if (!type.value().is_object()) 79883ff9ab6SJames Feist { 79983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type.key(); 80035a62c7cSJason M. Bills messages::propertyValueFormatError( 80135a62c7cSJason M. Bills response->res, type.value(), type.key()); 80283ff9ab6SJames Feist return; 80383ff9ab6SJames Feist } 80483ff9ab6SJames Feist for (const auto& record : type.value().items()) 80583ff9ab6SJames Feist { 80683ff9ab6SJames Feist const std::string& name = record.key(); 80783ff9ab6SJames Feist auto pathItr = 80883ff9ab6SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 80983ff9ab6SJames Feist [&name](const auto& obj) { 81083ff9ab6SJames Feist return boost::algorithm::ends_with( 81183ff9ab6SJames Feist obj.first.str, name); 81283ff9ab6SJames Feist }); 81383ff9ab6SJames Feist boost::container::flat_map< 81483ff9ab6SJames Feist std::string, dbus::utility::DbusVariantType> 81583ff9ab6SJames Feist output; 81683ff9ab6SJames Feist 81783ff9ab6SJames Feist output.reserve(16); // The pid interface length 81883ff9ab6SJames Feist 81983ff9ab6SJames Feist // determines if we're patching entity-manager or 82083ff9ab6SJames Feist // creating a new object 82183ff9ab6SJames Feist bool createNewObject = (pathItr == managedObj.end()); 82283ff9ab6SJames Feist if (type.key() == "PidControllers" || 82383ff9ab6SJames Feist type.key() == "FanControllers") 82483ff9ab6SJames Feist { 82583ff9ab6SJames Feist if (!createNewObject && 82683ff9ab6SJames Feist pathItr->second.find(pidConfigurationIface) == 82783ff9ab6SJames Feist pathItr->second.end()) 82883ff9ab6SJames Feist { 82983ff9ab6SJames Feist createNewObject = true; 83083ff9ab6SJames Feist } 83183ff9ab6SJames Feist } 83283ff9ab6SJames Feist else if (!createNewObject && 83383ff9ab6SJames Feist pathItr->second.find( 83483ff9ab6SJames Feist pidZoneConfigurationIface) == 83583ff9ab6SJames Feist pathItr->second.end()) 83683ff9ab6SJames Feist { 83783ff9ab6SJames Feist createNewObject = true; 83883ff9ab6SJames Feist } 83983ff9ab6SJames Feist output["Name"] = 84083ff9ab6SJames Feist boost::replace_all_copy(name, "_", " "); 84183ff9ab6SJames Feist 84283ff9ab6SJames Feist std::string chassis; 84383ff9ab6SJames Feist CreatePIDRet ret = createPidInterface( 84483ff9ab6SJames Feist response, type.key(), record.value(), 84583ff9ab6SJames Feist pathItr->first.str, managedObj, createNewObject, 84683ff9ab6SJames Feist output, chassis); 84783ff9ab6SJames Feist if (ret == CreatePIDRet::fail) 84883ff9ab6SJames Feist { 84983ff9ab6SJames Feist return; 85083ff9ab6SJames Feist } 85183ff9ab6SJames Feist else if (ret == CreatePIDRet::del) 85283ff9ab6SJames Feist { 85383ff9ab6SJames Feist continue; 85483ff9ab6SJames Feist } 85583ff9ab6SJames Feist 85683ff9ab6SJames Feist if (!createNewObject) 85783ff9ab6SJames Feist { 85883ff9ab6SJames Feist for (const auto& property : output) 85983ff9ab6SJames Feist { 86083ff9ab6SJames Feist const char* iface = 86183ff9ab6SJames Feist type.key() == "FanZones" 86283ff9ab6SJames Feist ? pidZoneConfigurationIface 86383ff9ab6SJames Feist : pidConfigurationIface; 86483ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 86583ff9ab6SJames Feist [response, 86683ff9ab6SJames Feist propertyName{std::string(property.first)}]( 86783ff9ab6SJames Feist const boost::system::error_code ec) { 86883ff9ab6SJames Feist if (ec) 86983ff9ab6SJames Feist { 87083ff9ab6SJames Feist BMCWEB_LOG_ERROR 87183ff9ab6SJames Feist << "Error patching " 87283ff9ab6SJames Feist << propertyName << ": " << ec; 87335a62c7cSJason M. Bills messages::internalError( 87435a62c7cSJason M. Bills response->res); 87583ff9ab6SJames Feist } 87683ff9ab6SJames Feist }, 87783ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", 87883ff9ab6SJames Feist pathItr->first.str, 87983ff9ab6SJames Feist "org.freedesktop.DBus.Properties", "Set", 88083ff9ab6SJames Feist std::string(iface), property.first, 88183ff9ab6SJames Feist property.second); 88283ff9ab6SJames Feist } 88383ff9ab6SJames Feist } 88483ff9ab6SJames Feist else 88583ff9ab6SJames Feist { 88683ff9ab6SJames Feist if (chassis.empty()) 88783ff9ab6SJames Feist { 88883ff9ab6SJames Feist BMCWEB_LOG_ERROR 88983ff9ab6SJames Feist << "Failed to get chassis from config"; 89035a62c7cSJason M. Bills messages::invalidObject(response->res, name); 89183ff9ab6SJames Feist return; 89283ff9ab6SJames Feist } 89383ff9ab6SJames Feist 89483ff9ab6SJames Feist bool foundChassis = false; 89583ff9ab6SJames Feist for (const auto& obj : managedObj) 89683ff9ab6SJames Feist { 89783ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 89883ff9ab6SJames Feist chassis)) 89983ff9ab6SJames Feist { 90083ff9ab6SJames Feist chassis = obj.first.str; 90183ff9ab6SJames Feist foundChassis = true; 90283ff9ab6SJames Feist break; 90383ff9ab6SJames Feist } 90483ff9ab6SJames Feist } 90583ff9ab6SJames Feist if (!foundChassis) 90683ff9ab6SJames Feist { 90783ff9ab6SJames Feist BMCWEB_LOG_ERROR 90883ff9ab6SJames Feist << "Failed to find chassis on dbus"; 90983ff9ab6SJames Feist messages::resourceMissingAtURI( 91035a62c7cSJason M. Bills response->res, 91135a62c7cSJason M. Bills "/redfish/v1/Chassis/" + chassis); 91283ff9ab6SJames Feist return; 91383ff9ab6SJames Feist } 91483ff9ab6SJames Feist 91583ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 91683ff9ab6SJames Feist [response](const boost::system::error_code ec) { 91783ff9ab6SJames Feist if (ec) 91883ff9ab6SJames Feist { 91983ff9ab6SJames Feist BMCWEB_LOG_ERROR 92083ff9ab6SJames Feist << "Error Adding Pid Object " << ec; 92135a62c7cSJason M. Bills messages::internalError(response->res); 92283ff9ab6SJames Feist } 92383ff9ab6SJames Feist }, 92483ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", chassis, 92583ff9ab6SJames Feist "xyz.openbmc_project.AddObject", "AddObject", 92683ff9ab6SJames Feist output); 92783ff9ab6SJames Feist } 92883ff9ab6SJames Feist } 92983ff9ab6SJames Feist } 93083ff9ab6SJames Feist }, 93183ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 93283ff9ab6SJames Feist "GetManagedObjects"); 93383ff9ab6SJames Feist } 9345b4aa86bSJames Feist 9355b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 9365b4aa86bSJames Feist const std::vector<std::string>& params) override 9375b4aa86bSJames Feist { 93883ff9ab6SJames Feist nlohmann::json patch; 93983ff9ab6SJames Feist if (!json_util::processJsonFromRequest(res, req, patch)) 94083ff9ab6SJames Feist { 94183ff9ab6SJames Feist return; 94283ff9ab6SJames Feist } 94383ff9ab6SJames Feist std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 94483ff9ab6SJames Feist for (const auto& topLevel : patch.items()) 94583ff9ab6SJames Feist { 94683ff9ab6SJames Feist if (topLevel.key() == "Oem") 94783ff9ab6SJames Feist { 94883ff9ab6SJames Feist if (!topLevel.value().is_object()) 94983ff9ab6SJames Feist { 95083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 95135a62c7cSJason M. Bills messages::propertyValueFormatError( 95235a62c7cSJason M. Bills response->res, topLevel.key(), "OemManager.Oem"); 95383ff9ab6SJames Feist return; 95483ff9ab6SJames Feist } 95583ff9ab6SJames Feist } 95683ff9ab6SJames Feist else 95783ff9ab6SJames Feist { 95883ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 95935a62c7cSJason M. Bills messages::propertyUnknown(response->res, topLevel.key()); 96083ff9ab6SJames Feist return; 96183ff9ab6SJames Feist } 96283ff9ab6SJames Feist for (const auto& oemLevel : topLevel.value().items()) 96383ff9ab6SJames Feist { 96483ff9ab6SJames Feist if (oemLevel.key() == "OpenBmc") 96583ff9ab6SJames Feist { 96683ff9ab6SJames Feist if (!oemLevel.value().is_object()) 96783ff9ab6SJames Feist { 96883ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 96935a62c7cSJason M. Bills messages::propertyValueFormatError( 97035a62c7cSJason M. Bills response->res, topLevel.key(), 97135a62c7cSJason M. Bills "OemManager.OpenBmc"); 97283ff9ab6SJames Feist return; 97383ff9ab6SJames Feist } 97483ff9ab6SJames Feist for (const auto& typeLevel : oemLevel.value().items()) 97583ff9ab6SJames Feist { 97683ff9ab6SJames Feist 97783ff9ab6SJames Feist if (typeLevel.key() == "Fan") 97883ff9ab6SJames Feist { 97983ff9ab6SJames Feist if (!typeLevel.value().is_object()) 98083ff9ab6SJames Feist { 98183ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " 98283ff9ab6SJames Feist << typeLevel.key(); 98383ff9ab6SJames Feist messages::propertyValueFormatError( 98435a62c7cSJason M. Bills response->res, typeLevel.value().dump(), 98535a62c7cSJason M. Bills typeLevel.key()); 98683ff9ab6SJames Feist return; 98783ff9ab6SJames Feist } 98883ff9ab6SJames Feist setPidValues(response, 98983ff9ab6SJames Feist std::move(typeLevel.value())); 99083ff9ab6SJames Feist } 99183ff9ab6SJames Feist else 99283ff9ab6SJames Feist { 99383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key(); 99435a62c7cSJason M. Bills messages::propertyUnknown(response->res, 99535a62c7cSJason M. Bills typeLevel.key()); 99683ff9ab6SJames Feist return; 99783ff9ab6SJames Feist } 99883ff9ab6SJames Feist } 99983ff9ab6SJames Feist } 100083ff9ab6SJames Feist else 100183ff9ab6SJames Feist { 100283ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 100335a62c7cSJason M. Bills messages::propertyUnknown(response->res, oemLevel.key()); 100483ff9ab6SJames Feist return; 100583ff9ab6SJames Feist } 100683ff9ab6SJames Feist } 100783ff9ab6SJames Feist } 10089c310685SBorawski.Lukasz } 10099c310685SBorawski.Lukasz 10101abe55efSEd Tanous std::string getDateTime() const 10111abe55efSEd Tanous { 10129c310685SBorawski.Lukasz std::array<char, 128> dateTime; 10139c310685SBorawski.Lukasz std::string redfishDateTime("0000-00-00T00:00:00Z00:00"); 10149c310685SBorawski.Lukasz std::time_t time = std::time(nullptr); 10159c310685SBorawski.Lukasz 10169c310685SBorawski.Lukasz if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z", 10171abe55efSEd Tanous std::localtime(&time))) 10181abe55efSEd Tanous { 10199c310685SBorawski.Lukasz // insert the colon required by the ISO 8601 standard 10209c310685SBorawski.Lukasz redfishDateTime = std::string(dateTime.data()); 10219c310685SBorawski.Lukasz redfishDateTime.insert(redfishDateTime.end() - 2, ':'); 10229c310685SBorawski.Lukasz } 10239c310685SBorawski.Lukasz 10249c310685SBorawski.Lukasz return redfishDateTime; 10259c310685SBorawski.Lukasz } 10269c310685SBorawski.Lukasz }; 10279c310685SBorawski.Lukasz 10281abe55efSEd Tanous class ManagerCollection : public Node 10291abe55efSEd Tanous { 10309c310685SBorawski.Lukasz public: 10311abe55efSEd Tanous ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") 10321abe55efSEd Tanous { 10339c310685SBorawski.Lukasz Node::json["@odata.id"] = "/redfish/v1/Managers"; 10349c310685SBorawski.Lukasz Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection"; 10359c310685SBorawski.Lukasz Node::json["@odata.context"] = 10369c310685SBorawski.Lukasz "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 10379c310685SBorawski.Lukasz Node::json["Name"] = "Manager Collection"; 10389c310685SBorawski.Lukasz Node::json["Members@odata.count"] = 1; 10395b4aa86bSJames Feist Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 10403ebd75f7SEd Tanous 1041a434f2bdSEd Tanous entityPrivileges = { 1042a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 1043e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1044e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1045e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1046e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1047e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 10489c310685SBorawski.Lukasz } 10499c310685SBorawski.Lukasz 10509c310685SBorawski.Lukasz private: 105155c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 10521abe55efSEd Tanous const std::vector<std::string>& params) override 10531abe55efSEd Tanous { 105483ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 105583ff9ab6SJames Feist // because it has a duplicate entry for members 105655c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 105755c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 105855c7b7a2SEd Tanous res.jsonValue["@odata.context"] = 105955c7b7a2SEd Tanous "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 106055c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 106155c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 106255c7b7a2SEd Tanous res.jsonValue["Members"] = { 10635b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 10649c310685SBorawski.Lukasz res.end(); 10659c310685SBorawski.Lukasz } 10669c310685SBorawski.Lukasz }; 10679c310685SBorawski.Lukasz } // namespace redfish 1068