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 { 255b4aa86bSJames Feist static constexpr const char* objectManagerIface = 265b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 275b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 285b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 295b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 305b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 319c310685SBorawski.Lukasz 325b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection, 335b4aa86bSJames Feist const std::string& path, 345b4aa86bSJames Feist std::shared_ptr<AsyncResp> asyncResp) 355b4aa86bSJames Feist { 365b4aa86bSJames Feist 375b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 385b4aa86bSJames Feist [asyncResp](const boost::system::error_code ec, 395b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 405b4aa86bSJames Feist if (ec) 415b4aa86bSJames Feist { 425b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 435b4aa86bSJames Feist asyncResp->res.jsonValue.clear(); 44f12894f8SJason M. Bills messages::internalError(asyncResp->res); 455b4aa86bSJames Feist return; 465b4aa86bSJames Feist } 475b4aa86bSJames Feist nlohmann::json& configRoot = 485b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 495b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 505b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 515b4aa86bSJames Feist fans["@odata.context"] = 525b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanControllers"; 535b4aa86bSJames Feist fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" 545b4aa86bSJames Feist "Fan/FanControllers"; 555b4aa86bSJames Feist 565b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 575b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 585b4aa86bSJames Feist pids["@odata.context"] = 595b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.PidControllers"; 605b4aa86bSJames Feist pids["@odata.id"] = 615b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; 625b4aa86bSJames Feist 635b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 645b4aa86bSJames Feist zones["@odata.id"] = 655b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; 665b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 675b4aa86bSJames Feist zones["@odata.context"] = 685b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanZones"; 695b4aa86bSJames Feist configRoot["@odata.id"] = 705b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; 715b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 725b4aa86bSJames Feist configRoot["@odata.context"] = 735b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.Fan"; 745b4aa86bSJames Feist 755b4aa86bSJames Feist bool propertyError = false; 765b4aa86bSJames Feist for (const auto& pathPair : managedObj) 775b4aa86bSJames Feist { 785b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 795b4aa86bSJames Feist { 805b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 815b4aa86bSJames Feist intfPair.first != pidZoneConfigurationIface) 825b4aa86bSJames Feist { 835b4aa86bSJames Feist continue; 845b4aa86bSJames Feist } 855b4aa86bSJames Feist auto findName = intfPair.second.find("Name"); 865b4aa86bSJames Feist if (findName == intfPair.second.end()) 875b4aa86bSJames Feist { 885b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Field missing Name"; 89f12894f8SJason M. Bills messages::internalError(asyncResp->res, "Name"); 905b4aa86bSJames Feist return; 915b4aa86bSJames Feist } 925b4aa86bSJames Feist const std::string* namePtr = 935b4aa86bSJames Feist mapbox::getPtr<const std::string>(findName->second); 945b4aa86bSJames Feist if (namePtr == nullptr) 955b4aa86bSJames Feist { 965b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Name Field illegal"; 975b4aa86bSJames Feist return; 985b4aa86bSJames Feist } 995b4aa86bSJames Feist 1005b4aa86bSJames Feist std::string name = *namePtr; 1015b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 1025b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 1035b4aa86bSJames Feist { 1045b4aa86bSJames Feist std::string chassis; 1055b4aa86bSJames Feist if (!dbus::utility::getNthStringFromPath( 1065b4aa86bSJames Feist pathPair.first.str, 5, chassis)) 1075b4aa86bSJames Feist { 1085b4aa86bSJames Feist chassis = "#IllegalValue"; 1095b4aa86bSJames Feist } 1105b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 1115b4aa86bSJames Feist zone["Chassis"] = { 1125b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; 1135b4aa86bSJames Feist zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" 1145b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 1155b4aa86bSJames Feist name; 1165b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 1175b4aa86bSJames Feist zone["@odata.context"] = 1185b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.FanZone"; 1195b4aa86bSJames Feist } 1205b4aa86bSJames Feist 1215b4aa86bSJames Feist for (const auto& propertyPair : intfPair.second) 1225b4aa86bSJames Feist { 1235b4aa86bSJames Feist if (propertyPair.first == "Type" || 1245b4aa86bSJames Feist propertyPair.first == "Class" || 1255b4aa86bSJames Feist propertyPair.first == "Name") 1265b4aa86bSJames Feist { 1275b4aa86bSJames Feist continue; 1285b4aa86bSJames Feist } 1295b4aa86bSJames Feist 1305b4aa86bSJames Feist // zones 1315b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 1325b4aa86bSJames Feist { 1335b4aa86bSJames Feist const double* ptr = mapbox::getPtr<const double>( 1345b4aa86bSJames Feist propertyPair.second); 1355b4aa86bSJames Feist if (ptr == nullptr) 1365b4aa86bSJames Feist { 1375b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 1385b4aa86bSJames Feist << propertyPair.first; 139f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1405b4aa86bSJames Feist return; 1415b4aa86bSJames Feist } 1425b4aa86bSJames Feist zones[name][propertyPair.first] = *ptr; 1435b4aa86bSJames Feist } 1445b4aa86bSJames Feist 1455b4aa86bSJames Feist // pid and fans are off the same configuration 1465b4aa86bSJames Feist if (intfPair.first == pidConfigurationIface) 1475b4aa86bSJames Feist { 1485b4aa86bSJames Feist const std::string* classPtr = nullptr; 1495b4aa86bSJames Feist auto findClass = intfPair.second.find("Class"); 1505b4aa86bSJames Feist if (findClass != intfPair.second.end()) 1515b4aa86bSJames Feist { 1525b4aa86bSJames Feist classPtr = mapbox::getPtr<const std::string>( 1535b4aa86bSJames Feist findClass->second); 1545b4aa86bSJames Feist } 1555b4aa86bSJames Feist if (classPtr == nullptr) 1565b4aa86bSJames Feist { 1575b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 158f12894f8SJason M. Bills messages::internalError(asyncResp->res, 159f12894f8SJason M. Bills "Class"); 1605b4aa86bSJames Feist return; 1615b4aa86bSJames Feist } 1625b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 1635b4aa86bSJames Feist nlohmann::json& element = 1645b4aa86bSJames Feist isFan ? fans[name] : pids[name]; 1655b4aa86bSJames Feist if (isFan) 1665b4aa86bSJames Feist { 1675b4aa86bSJames Feist element["@odata.id"] = 1685b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 1695b4aa86bSJames Feist "OpenBmc/Fan/FanControllers/" + 1705b4aa86bSJames Feist std::string(name); 1715b4aa86bSJames Feist element["@odata.type"] = 1725b4aa86bSJames Feist "#OemManager.FanController"; 1735b4aa86bSJames Feist 1745b4aa86bSJames Feist element["@odata.context"] = 1755b4aa86bSJames Feist "/redfish/v1/" 1765b4aa86bSJames Feist "$metadata#OemManager.FanController"; 1775b4aa86bSJames Feist } 1785b4aa86bSJames Feist else 1795b4aa86bSJames Feist { 1805b4aa86bSJames Feist element["@odata.id"] = 1815b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 1825b4aa86bSJames Feist "OpenBmc/Fan/PidControllers/" + 1835b4aa86bSJames Feist std::string(name); 1845b4aa86bSJames Feist element["@odata.type"] = 1855b4aa86bSJames Feist "#OemManager.PidController"; 1865b4aa86bSJames Feist element["@odata.context"] = 1875b4aa86bSJames Feist "/redfish/v1/$metadata" 1885b4aa86bSJames Feist "#OemManager.PidController"; 1895b4aa86bSJames Feist } 1905b4aa86bSJames Feist 1915b4aa86bSJames Feist if (propertyPair.first == "Zones") 1925b4aa86bSJames Feist { 1935b4aa86bSJames Feist const std::vector<std::string>* inputs = 1945b4aa86bSJames Feist mapbox::getPtr< 1955b4aa86bSJames Feist const std::vector<std::string>>( 1965b4aa86bSJames Feist propertyPair.second); 1975b4aa86bSJames Feist 1985b4aa86bSJames Feist if (inputs == nullptr) 1995b4aa86bSJames Feist { 2005b4aa86bSJames Feist BMCWEB_LOG_ERROR 2015b4aa86bSJames Feist << "Zones Pid Field Illegal"; 202f12894f8SJason M. Bills messages::internalError(asyncResp->res, 203f12894f8SJason M. Bills "Zones"); 2045b4aa86bSJames Feist return; 2055b4aa86bSJames Feist } 2065b4aa86bSJames Feist auto& data = element[propertyPair.first]; 2075b4aa86bSJames Feist data = nlohmann::json::array(); 2085b4aa86bSJames Feist for (std::string itemCopy : *inputs) 2095b4aa86bSJames Feist { 2105b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 2115b4aa86bSJames Feist data.push_back( 2125b4aa86bSJames Feist {{"@odata.id", 2135b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 2145b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 2155b4aa86bSJames Feist itemCopy}}); 2165b4aa86bSJames Feist } 2175b4aa86bSJames Feist } 2185b4aa86bSJames Feist // todo(james): may never happen, but this 2195b4aa86bSJames Feist // assumes configuration data referenced in the 2205b4aa86bSJames Feist // PID config is provided by the same daemon, we 2215b4aa86bSJames Feist // could add another loop to cover all cases, 2225b4aa86bSJames Feist // but I'm okay kicking this can down the road a 2235b4aa86bSJames Feist // bit 2245b4aa86bSJames Feist 2255b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 2265b4aa86bSJames Feist propertyPair.first == "Outputs") 2275b4aa86bSJames Feist { 2285b4aa86bSJames Feist auto& data = element[propertyPair.first]; 2295b4aa86bSJames Feist const std::vector<std::string>* inputs = 2305b4aa86bSJames Feist mapbox::getPtr< 2315b4aa86bSJames Feist const std::vector<std::string>>( 2325b4aa86bSJames Feist propertyPair.second); 2335b4aa86bSJames Feist 2345b4aa86bSJames Feist if (inputs == nullptr) 2355b4aa86bSJames Feist { 2365b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 2375b4aa86bSJames Feist << propertyPair.first; 238f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2395b4aa86bSJames Feist return; 2405b4aa86bSJames Feist } 2415b4aa86bSJames Feist data = *inputs; 2425b4aa86bSJames Feist } // doubles 2435b4aa86bSJames Feist else if (propertyPair.first == 2445b4aa86bSJames Feist "FFGainCoefficient" || 2455b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 2465b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 2475b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 2485b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 2495b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 2505b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 2515b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 2525b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 2535b4aa86bSJames Feist propertyPair.first == "SlewPos") 2545b4aa86bSJames Feist { 2555b4aa86bSJames Feist const double* ptr = 2565b4aa86bSJames Feist mapbox::getPtr<const double>( 2575b4aa86bSJames Feist propertyPair.second); 2585b4aa86bSJames Feist if (ptr == nullptr) 2595b4aa86bSJames Feist { 2605b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 2615b4aa86bSJames Feist << propertyPair.first; 262f12894f8SJason M. Bills messages::internalError(asyncResp->res); 2635b4aa86bSJames Feist return; 2645b4aa86bSJames Feist } 2655b4aa86bSJames Feist element[propertyPair.first] = *ptr; 2665b4aa86bSJames Feist } 2675b4aa86bSJames Feist } 2685b4aa86bSJames Feist } 2695b4aa86bSJames Feist } 2705b4aa86bSJames Feist } 2715b4aa86bSJames Feist }, 2725b4aa86bSJames Feist connection, path, objectManagerIface, "GetManagedObjects"); 2735b4aa86bSJames Feist } 274ca537928SJennifer Lee 275*83ff9ab6SJames Feist enum class CreatePIDRet 276*83ff9ab6SJames Feist { 277*83ff9ab6SJames Feist fail, 278*83ff9ab6SJames Feist del, 279*83ff9ab6SJames Feist patch 280*83ff9ab6SJames Feist }; 281*83ff9ab6SJames Feist 282*83ff9ab6SJames Feist static CreatePIDRet createPidInterface( 283*83ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 284*83ff9ab6SJames Feist const nlohmann::json& record, const std::string& path, 285*83ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 286*83ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 287*83ff9ab6SJames Feist output, 288*83ff9ab6SJames Feist std::string& chassis) 289*83ff9ab6SJames Feist { 290*83ff9ab6SJames Feist 291*83ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 292*83ff9ab6SJames Feist { 293*83ff9ab6SJames Feist if (createNewObject) 294*83ff9ab6SJames Feist { 295*83ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 296*83ff9ab6SJames Feist : std::string("fan"); 297*83ff9ab6SJames Feist output["Type"] = std::string("Pid"); 298*83ff9ab6SJames Feist } 299*83ff9ab6SJames Feist else if (record == nullptr) 300*83ff9ab6SJames Feist { 301*83ff9ab6SJames Feist // delete interface 302*83ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 303*83ff9ab6SJames Feist [response, 304*83ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 305*83ff9ab6SJames Feist if (ec) 306*83ff9ab6SJames Feist { 307*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 308*83ff9ab6SJames Feist << ec; 309*83ff9ab6SJames Feist response->res.result( 310*83ff9ab6SJames Feist boost::beast::http::status::internal_server_error); 311*83ff9ab6SJames Feist } 312*83ff9ab6SJames Feist }, 313*83ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 314*83ff9ab6SJames Feist pidConfigurationIface, "Delete"); 315*83ff9ab6SJames Feist return CreatePIDRet::del; 316*83ff9ab6SJames Feist } 317*83ff9ab6SJames Feist 318*83ff9ab6SJames Feist for (auto& field : record.items()) 319*83ff9ab6SJames Feist { 320*83ff9ab6SJames Feist if (field.key() == "Zones") 321*83ff9ab6SJames Feist { 322*83ff9ab6SJames Feist if (!field.value().is_array()) 323*83ff9ab6SJames Feist { 324*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 325*83ff9ab6SJames Feist messages::addMessageToErrorJson( 326*83ff9ab6SJames Feist response->res.jsonValue, 327*83ff9ab6SJames Feist messages::propertyValueFormatError(field.value(), 328*83ff9ab6SJames Feist field.key())); 329*83ff9ab6SJames Feist response->res.result( 330*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 331*83ff9ab6SJames Feist return CreatePIDRet::fail; 332*83ff9ab6SJames Feist } 333*83ff9ab6SJames Feist std::vector<std::string> inputs; 334*83ff9ab6SJames Feist for (const auto& odata : field.value().items()) 335*83ff9ab6SJames Feist { 336*83ff9ab6SJames Feist for (const auto& value : odata.value().items()) 337*83ff9ab6SJames Feist { 338*83ff9ab6SJames Feist const std::string* path = 339*83ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 340*83ff9ab6SJames Feist if (path == nullptr) 341*83ff9ab6SJames Feist { 342*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 343*83ff9ab6SJames Feist messages::addMessageToErrorJson( 344*83ff9ab6SJames Feist response->res.jsonValue, 345*83ff9ab6SJames Feist messages::propertyValueFormatError( 346*83ff9ab6SJames Feist field.value().dump(), field.key())); 347*83ff9ab6SJames Feist response->res.result( 348*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 349*83ff9ab6SJames Feist return CreatePIDRet::fail; 350*83ff9ab6SJames Feist } 351*83ff9ab6SJames Feist std::string input; 352*83ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*path, 4, 353*83ff9ab6SJames Feist input)) 354*83ff9ab6SJames Feist { 355*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *path; 356*83ff9ab6SJames Feist messages::addMessageToErrorJson( 357*83ff9ab6SJames Feist response->res.jsonValue, 358*83ff9ab6SJames Feist messages::propertyValueFormatError( 359*83ff9ab6SJames Feist field.value().dump(), field.key())); 360*83ff9ab6SJames Feist response->res.result( 361*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 362*83ff9ab6SJames Feist return CreatePIDRet::fail; 363*83ff9ab6SJames Feist } 364*83ff9ab6SJames Feist boost::replace_all(input, "_", " "); 365*83ff9ab6SJames Feist inputs.emplace_back(std::move(input)); 366*83ff9ab6SJames Feist } 367*83ff9ab6SJames Feist } 368*83ff9ab6SJames Feist output["Zones"] = std::move(inputs); 369*83ff9ab6SJames Feist } 370*83ff9ab6SJames Feist else if (field.key() == "Inputs" || field.key() == "Outputs") 371*83ff9ab6SJames Feist { 372*83ff9ab6SJames Feist if (!field.value().is_array()) 373*83ff9ab6SJames Feist { 374*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 375*83ff9ab6SJames Feist messages::addMessageToErrorJson( 376*83ff9ab6SJames Feist response->res.jsonValue, 377*83ff9ab6SJames Feist messages::propertyValueFormatError(field.value().dump(), 378*83ff9ab6SJames Feist field.key())); 379*83ff9ab6SJames Feist response->res.result( 380*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 381*83ff9ab6SJames Feist return CreatePIDRet::fail; 382*83ff9ab6SJames Feist } 383*83ff9ab6SJames Feist std::vector<std::string> inputs; 384*83ff9ab6SJames Feist for (const auto& value : field.value().items()) 385*83ff9ab6SJames Feist { 386*83ff9ab6SJames Feist const std::string* sensor = 387*83ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 388*83ff9ab6SJames Feist 389*83ff9ab6SJames Feist if (sensor == nullptr) 390*83ff9ab6SJames Feist { 391*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " 392*83ff9ab6SJames Feist << field.value().dump(); 393*83ff9ab6SJames Feist messages::addMessageToErrorJson( 394*83ff9ab6SJames Feist response->res.jsonValue, 395*83ff9ab6SJames Feist messages::propertyValueFormatError( 396*83ff9ab6SJames Feist field.value().dump(), field.key())); 397*83ff9ab6SJames Feist response->res.result( 398*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 399*83ff9ab6SJames Feist return CreatePIDRet::fail; 400*83ff9ab6SJames Feist } 401*83ff9ab6SJames Feist 402*83ff9ab6SJames Feist std::string input = 403*83ff9ab6SJames Feist boost::replace_all_copy(*sensor, "_", " "); 404*83ff9ab6SJames Feist inputs.push_back(std::move(input)); 405*83ff9ab6SJames Feist // try to find the sensor in the 406*83ff9ab6SJames Feist // configuration 407*83ff9ab6SJames Feist if (chassis.empty()) 408*83ff9ab6SJames Feist { 409*83ff9ab6SJames Feist std::find_if( 410*83ff9ab6SJames Feist managedObj.begin(), managedObj.end(), 411*83ff9ab6SJames Feist [&chassis, sensor](const auto& obj) { 412*83ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 413*83ff9ab6SJames Feist *sensor)) 414*83ff9ab6SJames Feist { 415*83ff9ab6SJames Feist return dbus::utility::getNthStringFromPath( 416*83ff9ab6SJames Feist obj.first.str, 5, chassis); 417*83ff9ab6SJames Feist } 418*83ff9ab6SJames Feist return false; 419*83ff9ab6SJames Feist }); 420*83ff9ab6SJames Feist } 421*83ff9ab6SJames Feist } 422*83ff9ab6SJames Feist output[field.key()] = inputs; 423*83ff9ab6SJames Feist } 424*83ff9ab6SJames Feist 425*83ff9ab6SJames Feist // doubles 426*83ff9ab6SJames Feist else if (field.key() == "FFGainCoefficient" || 427*83ff9ab6SJames Feist field.key() == "FFOffCoefficient" || 428*83ff9ab6SJames Feist field.key() == "ICoefficient" || 429*83ff9ab6SJames Feist field.key() == "ILimitMax" || field.key() == "ILimitMin" || 430*83ff9ab6SJames Feist field.key() == "OutLimitMax" || 431*83ff9ab6SJames Feist field.key() == "OutLimitMin" || 432*83ff9ab6SJames Feist field.key() == "PCoefficient" || 433*83ff9ab6SJames Feist field.key() == "SetPoint" || field.key() == "SlewNeg" || 434*83ff9ab6SJames Feist field.key() == "SlewPos") 435*83ff9ab6SJames Feist { 436*83ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 437*83ff9ab6SJames Feist if (ptr == nullptr) 438*83ff9ab6SJames Feist { 439*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 440*83ff9ab6SJames Feist messages::addMessageToErrorJson( 441*83ff9ab6SJames Feist response->res.jsonValue, 442*83ff9ab6SJames Feist messages::propertyValueFormatError(field.value().dump(), 443*83ff9ab6SJames Feist field.key())); 444*83ff9ab6SJames Feist response->res.result( 445*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 446*83ff9ab6SJames Feist return CreatePIDRet::fail; 447*83ff9ab6SJames Feist } 448*83ff9ab6SJames Feist output[field.key()] = *ptr; 449*83ff9ab6SJames Feist } 450*83ff9ab6SJames Feist 451*83ff9ab6SJames Feist else 452*83ff9ab6SJames Feist { 453*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 454*83ff9ab6SJames Feist messages::addMessageToErrorJson( 455*83ff9ab6SJames Feist response->res.jsonValue, 456*83ff9ab6SJames Feist messages::propertyUnknown(field.key())); 457*83ff9ab6SJames Feist response->res.result(boost::beast::http::status::bad_request); 458*83ff9ab6SJames Feist return CreatePIDRet::fail; 459*83ff9ab6SJames Feist } 460*83ff9ab6SJames Feist } 461*83ff9ab6SJames Feist } 462*83ff9ab6SJames Feist else if (type == "FanZones") 463*83ff9ab6SJames Feist { 464*83ff9ab6SJames Feist if (!createNewObject && record == nullptr) 465*83ff9ab6SJames Feist { 466*83ff9ab6SJames Feist // delete interface 467*83ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 468*83ff9ab6SJames Feist [response, 469*83ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 470*83ff9ab6SJames Feist if (ec) 471*83ff9ab6SJames Feist { 472*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 473*83ff9ab6SJames Feist << ec; 474*83ff9ab6SJames Feist response->res.result( 475*83ff9ab6SJames Feist boost::beast::http::status::internal_server_error); 476*83ff9ab6SJames Feist } 477*83ff9ab6SJames Feist }, 478*83ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 479*83ff9ab6SJames Feist pidZoneConfigurationIface, "Delete"); 480*83ff9ab6SJames Feist return CreatePIDRet::del; 481*83ff9ab6SJames Feist } 482*83ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 483*83ff9ab6SJames Feist 484*83ff9ab6SJames Feist for (auto& field : record.items()) 485*83ff9ab6SJames Feist { 486*83ff9ab6SJames Feist if (field.key() == "Chassis") 487*83ff9ab6SJames Feist { 488*83ff9ab6SJames Feist const std::string* chassisId = nullptr; 489*83ff9ab6SJames Feist for (const auto& id : field.value().items()) 490*83ff9ab6SJames Feist { 491*83ff9ab6SJames Feist if (id.key() != "@odata.id") 492*83ff9ab6SJames Feist { 493*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << id.key(); 494*83ff9ab6SJames Feist messages::addMessageToErrorJson( 495*83ff9ab6SJames Feist response->res.jsonValue, 496*83ff9ab6SJames Feist messages::propertyUnknown(field.key())); 497*83ff9ab6SJames Feist response->res.result( 498*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 499*83ff9ab6SJames Feist return CreatePIDRet::fail; 500*83ff9ab6SJames Feist } 501*83ff9ab6SJames Feist chassisId = id.value().get_ptr<const std::string*>(); 502*83ff9ab6SJames Feist if (chassisId == nullptr) 503*83ff9ab6SJames Feist { 504*83ff9ab6SJames Feist messages::addMessageToErrorJson( 505*83ff9ab6SJames Feist response->res.jsonValue, 506*83ff9ab6SJames Feist messages::createFailedMissingReqProperties( 507*83ff9ab6SJames Feist field.key())); 508*83ff9ab6SJames Feist response->res.result( 509*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 510*83ff9ab6SJames Feist return CreatePIDRet::fail; 511*83ff9ab6SJames Feist } 512*83ff9ab6SJames Feist } 513*83ff9ab6SJames Feist 514*83ff9ab6SJames Feist // /refish/v1/chassis/chassis_name/ 515*83ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*chassisId, 3, 516*83ff9ab6SJames Feist chassis)) 517*83ff9ab6SJames Feist { 518*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId; 519*83ff9ab6SJames Feist response->res.result( 520*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 521*83ff9ab6SJames Feist return CreatePIDRet::fail; 522*83ff9ab6SJames Feist } 523*83ff9ab6SJames Feist } 524*83ff9ab6SJames Feist else if (field.key() == "FailSafePercent" || 525*83ff9ab6SJames Feist field.key() == "MinThermalRpm") 526*83ff9ab6SJames Feist { 527*83ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 528*83ff9ab6SJames Feist if (ptr == nullptr) 529*83ff9ab6SJames Feist { 530*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 531*83ff9ab6SJames Feist messages::addMessageToErrorJson( 532*83ff9ab6SJames Feist response->res.jsonValue, 533*83ff9ab6SJames Feist messages::propertyValueFormatError(field.value().dump(), 534*83ff9ab6SJames Feist field.key())); 535*83ff9ab6SJames Feist response->res.result( 536*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 537*83ff9ab6SJames Feist return CreatePIDRet::fail; 538*83ff9ab6SJames Feist } 539*83ff9ab6SJames Feist output[field.key()] = *ptr; 540*83ff9ab6SJames Feist } 541*83ff9ab6SJames Feist else 542*83ff9ab6SJames Feist { 543*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 544*83ff9ab6SJames Feist messages::addMessageToErrorJson( 545*83ff9ab6SJames Feist response->res.jsonValue, 546*83ff9ab6SJames Feist messages::propertyUnknown(field.key())); 547*83ff9ab6SJames Feist response->res.result(boost::beast::http::status::bad_request); 548*83ff9ab6SJames Feist return CreatePIDRet::fail; 549*83ff9ab6SJames Feist } 550*83ff9ab6SJames Feist } 551*83ff9ab6SJames Feist } 552*83ff9ab6SJames Feist else 553*83ff9ab6SJames Feist { 554*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type; 555*83ff9ab6SJames Feist messages::addMessageToErrorJson(response->res.jsonValue, 556*83ff9ab6SJames Feist messages::propertyUnknown(type)); 557*83ff9ab6SJames Feist response->res.result(boost::beast::http::status::bad_request); 558*83ff9ab6SJames Feist return CreatePIDRet::fail; 559*83ff9ab6SJames Feist } 560*83ff9ab6SJames Feist return CreatePIDRet::patch; 561*83ff9ab6SJames Feist } 562*83ff9ab6SJames Feist 5631abe55efSEd Tanous class Manager : public Node 5641abe55efSEd Tanous { 5659c310685SBorawski.Lukasz public: 5665b4aa86bSJames Feist Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") 5671abe55efSEd Tanous { 5685b4aa86bSJames Feist Node::json["@odata.id"] = "/redfish/v1/Managers/bmc"; 5699c310685SBorawski.Lukasz Node::json["@odata.type"] = "#Manager.v1_3_0.Manager"; 5709c310685SBorawski.Lukasz Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager"; 5715b4aa86bSJames Feist Node::json["Id"] = "bmc"; 5729c310685SBorawski.Lukasz Node::json["Name"] = "OpenBmc Manager"; 5739c310685SBorawski.Lukasz Node::json["Description"] = "Baseboard Management Controller"; 5749c310685SBorawski.Lukasz Node::json["PowerState"] = "On"; 575ca537928SJennifer Lee Node::json["ManagerType"] = "BMC"; 5769c310685SBorawski.Lukasz Node::json["UUID"] = 57755c7b7a2SEd Tanous app.template getMiddleware<crow::persistent_data::Middleware>() 57855c7b7a2SEd Tanous .systemUuid; 5799c310685SBorawski.Lukasz Node::json["Model"] = "OpenBmc"; // TODO(ed), get model 580ca537928SJennifer Lee Node::json["EthernetInterfaces"] = { 5815b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 5823ebd75f7SEd Tanous 583a434f2bdSEd Tanous entityPrivileges = { 584a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 585e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 586e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 587e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 588e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 589e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 5905b4aa86bSJames Feist 5915b4aa86bSJames Feist // default oem data 5925b4aa86bSJames Feist nlohmann::json& oem = Node::json["Oem"]; 5935b4aa86bSJames Feist nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 5945b4aa86bSJames Feist oem["@odata.type"] = "#OemManager.Oem"; 5955b4aa86bSJames Feist oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 5965b4aa86bSJames Feist oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem"; 5975b4aa86bSJames Feist oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 5985b4aa86bSJames Feist oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 5995b4aa86bSJames Feist oemOpenbmc["@odata.context"] = 6005b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.OpenBmc"; 6019c310685SBorawski.Lukasz } 6029c310685SBorawski.Lukasz 6039c310685SBorawski.Lukasz private: 6045b4aa86bSJames Feist void getPidValues(std::shared_ptr<AsyncResp> asyncResp) 6055b4aa86bSJames Feist { 6065b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 6075b4aa86bSJames Feist [asyncResp](const boost::system::error_code ec, 6085b4aa86bSJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 6095b4aa86bSJames Feist if (ec) 6105b4aa86bSJames Feist { 6115b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 612f12894f8SJason M. Bills messages::internalError(asyncResp->res); 6135b4aa86bSJames Feist return; 6145b4aa86bSJames Feist } 6155b4aa86bSJames Feist 6165b4aa86bSJames Feist // create map of <connection, path to objMgr>> 6175b4aa86bSJames Feist boost::container::flat_map<std::string, std::string> 6185b4aa86bSJames Feist objectMgrPaths; 6196bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 6205b4aa86bSJames Feist for (const auto& pathGroup : subtree) 6215b4aa86bSJames Feist { 6225b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 6235b4aa86bSJames Feist { 6246bce33bcSJames Feist auto findConnection = 6256bce33bcSJames Feist calledConnections.find(connectionGroup.first); 6266bce33bcSJames Feist if (findConnection != calledConnections.end()) 6276bce33bcSJames Feist { 6286bce33bcSJames Feist break; 6296bce33bcSJames Feist } 6305b4aa86bSJames Feist for (const std::string& interface : 6315b4aa86bSJames Feist connectionGroup.second) 6325b4aa86bSJames Feist { 6335b4aa86bSJames Feist if (interface == objectManagerIface) 6345b4aa86bSJames Feist { 6355b4aa86bSJames Feist objectMgrPaths[connectionGroup.first] = 6365b4aa86bSJames Feist pathGroup.first; 6375b4aa86bSJames Feist } 6385b4aa86bSJames Feist // this list is alphabetical, so we 6395b4aa86bSJames Feist // should have found the objMgr by now 6405b4aa86bSJames Feist if (interface == pidConfigurationIface || 6415b4aa86bSJames Feist interface == pidZoneConfigurationIface) 6425b4aa86bSJames Feist { 6435b4aa86bSJames Feist auto findObjMgr = 6445b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 6455b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 6465b4aa86bSJames Feist { 6475b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 6485b4aa86bSJames Feist << "Has no Object Manager"; 6495b4aa86bSJames Feist continue; 6505b4aa86bSJames Feist } 6516bce33bcSJames Feist 6526bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 6536bce33bcSJames Feist 6545b4aa86bSJames Feist asyncPopulatePid(findObjMgr->first, 6555b4aa86bSJames Feist findObjMgr->second, asyncResp); 6565b4aa86bSJames Feist break; 6575b4aa86bSJames Feist } 6585b4aa86bSJames Feist } 6595b4aa86bSJames Feist } 6605b4aa86bSJames Feist } 6615b4aa86bSJames Feist }, 6625b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 6635b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 6645b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 6655b4aa86bSJames Feist std::array<const char*, 3>{pidConfigurationIface, 6665b4aa86bSJames Feist pidZoneConfigurationIface, 6675b4aa86bSJames Feist objectManagerIface}); 6685b4aa86bSJames Feist } 6695b4aa86bSJames Feist 67055c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 6711abe55efSEd Tanous const std::vector<std::string>& params) override 6721abe55efSEd Tanous { 673ca537928SJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 674ca537928SJennifer Lee asyncResp->res.jsonValue = Node::json; 675ca537928SJennifer Lee 6769c310685SBorawski.Lukasz Node::json["DateTime"] = getDateTime(); 67755c7b7a2SEd Tanous res.jsonValue = Node::json; 6785b4aa86bSJames Feist 679ca537928SJennifer Lee crow::connections::systemBus->async_method_call( 680ca537928SJennifer Lee [asyncResp](const boost::system::error_code ec, 6815b4aa86bSJames Feist const dbus::utility::ManagedObjectType& resp) { 682ca537928SJennifer Lee if (ec) 683ca537928SJennifer Lee { 684ca537928SJennifer Lee BMCWEB_LOG_ERROR << "Error while getting Software Version"; 685f12894f8SJason M. Bills messages::internalError(asyncResp->res); 686ca537928SJennifer Lee return; 687ca537928SJennifer Lee } 688ca537928SJennifer Lee 689ca537928SJennifer Lee for (auto& objpath : resp) 690ca537928SJennifer Lee { 691ca537928SJennifer Lee for (auto& interface : objpath.second) 692ca537928SJennifer Lee { 693ca537928SJennifer Lee // If interface is xyz.openbmc_project.Software.Version, 694ca537928SJennifer Lee // this is what we're looking for. 695ca537928SJennifer Lee if (interface.first == 696ca537928SJennifer Lee "xyz.openbmc_project.Software.Version") 697ca537928SJennifer Lee { 698ca537928SJennifer Lee // Cut out everyting until last "/", ... 699ca537928SJennifer Lee const std::string& iface_id = objpath.first; 700ca537928SJennifer Lee for (auto& property : interface.second) 701ca537928SJennifer Lee { 702ca537928SJennifer Lee if (property.first == "Version") 703ca537928SJennifer Lee { 704ca537928SJennifer Lee const std::string* value = 705ca537928SJennifer Lee mapbox::getPtr<const std::string>( 706ca537928SJennifer Lee property.second); 707ca537928SJennifer Lee if (value == nullptr) 708ca537928SJennifer Lee { 709ca537928SJennifer Lee continue; 710ca537928SJennifer Lee } 711ca537928SJennifer Lee asyncResp->res 712ca537928SJennifer Lee .jsonValue["FirmwareVersion"] = *value; 713ca537928SJennifer Lee } 714ca537928SJennifer Lee } 715ca537928SJennifer Lee } 716ca537928SJennifer Lee } 717ca537928SJennifer Lee } 718ca537928SJennifer Lee }, 719ca537928SJennifer Lee "xyz.openbmc_project.Software.BMC.Updater", 720ca537928SJennifer Lee "/xyz/openbmc_project/software", 721ca537928SJennifer Lee "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 7225b4aa86bSJames Feist getPidValues(asyncResp); 7235b4aa86bSJames Feist } 724*83ff9ab6SJames Feist void setPidValues(std::shared_ptr<AsyncResp> response, 725*83ff9ab6SJames Feist const nlohmann::json& data) 726*83ff9ab6SJames Feist { 727*83ff9ab6SJames Feist // todo(james): might make sense to do a mapper call here if this 728*83ff9ab6SJames Feist // interface gets more traction 729*83ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 730*83ff9ab6SJames Feist [response, 731*83ff9ab6SJames Feist data](const boost::system::error_code ec, 732*83ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj) { 733*83ff9ab6SJames Feist if (ec) 734*83ff9ab6SJames Feist { 735*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 736*83ff9ab6SJames Feist response->res.result( 737*83ff9ab6SJames Feist boost::beast::http::status::internal_server_error); 738*83ff9ab6SJames Feist return; 739*83ff9ab6SJames Feist } 740*83ff9ab6SJames Feist for (const auto& type : data.items()) 741*83ff9ab6SJames Feist { 742*83ff9ab6SJames Feist if (!type.value().is_object()) 743*83ff9ab6SJames Feist { 744*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type.key(); 745*83ff9ab6SJames Feist messages::addMessageToErrorJson( 746*83ff9ab6SJames Feist response->res.jsonValue, 747*83ff9ab6SJames Feist messages::propertyValueFormatError(type.value(), 748*83ff9ab6SJames Feist type.key())); 749*83ff9ab6SJames Feist response->res.result( 750*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 751*83ff9ab6SJames Feist return; 752*83ff9ab6SJames Feist } 753*83ff9ab6SJames Feist for (const auto& record : type.value().items()) 754*83ff9ab6SJames Feist { 755*83ff9ab6SJames Feist const std::string& name = record.key(); 756*83ff9ab6SJames Feist auto pathItr = 757*83ff9ab6SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 758*83ff9ab6SJames Feist [&name](const auto& obj) { 759*83ff9ab6SJames Feist return boost::algorithm::ends_with( 760*83ff9ab6SJames Feist obj.first.str, name); 761*83ff9ab6SJames Feist }); 762*83ff9ab6SJames Feist boost::container::flat_map< 763*83ff9ab6SJames Feist std::string, dbus::utility::DbusVariantType> 764*83ff9ab6SJames Feist output; 765*83ff9ab6SJames Feist 766*83ff9ab6SJames Feist output.reserve(16); // The pid interface length 767*83ff9ab6SJames Feist 768*83ff9ab6SJames Feist // determines if we're patching entity-manager or 769*83ff9ab6SJames Feist // creating a new object 770*83ff9ab6SJames Feist bool createNewObject = (pathItr == managedObj.end()); 771*83ff9ab6SJames Feist if (type.key() == "PidControllers" || 772*83ff9ab6SJames Feist type.key() == "FanControllers") 773*83ff9ab6SJames Feist { 774*83ff9ab6SJames Feist if (!createNewObject && 775*83ff9ab6SJames Feist pathItr->second.find(pidConfigurationIface) == 776*83ff9ab6SJames Feist pathItr->second.end()) 777*83ff9ab6SJames Feist { 778*83ff9ab6SJames Feist createNewObject = true; 779*83ff9ab6SJames Feist } 780*83ff9ab6SJames Feist } 781*83ff9ab6SJames Feist else if (!createNewObject && 782*83ff9ab6SJames Feist pathItr->second.find( 783*83ff9ab6SJames Feist pidZoneConfigurationIface) == 784*83ff9ab6SJames Feist pathItr->second.end()) 785*83ff9ab6SJames Feist { 786*83ff9ab6SJames Feist createNewObject = true; 787*83ff9ab6SJames Feist } 788*83ff9ab6SJames Feist output["Name"] = 789*83ff9ab6SJames Feist boost::replace_all_copy(name, "_", " "); 790*83ff9ab6SJames Feist 791*83ff9ab6SJames Feist std::string chassis; 792*83ff9ab6SJames Feist CreatePIDRet ret = createPidInterface( 793*83ff9ab6SJames Feist response, type.key(), record.value(), 794*83ff9ab6SJames Feist pathItr->first.str, managedObj, createNewObject, 795*83ff9ab6SJames Feist output, chassis); 796*83ff9ab6SJames Feist if (ret == CreatePIDRet::fail) 797*83ff9ab6SJames Feist { 798*83ff9ab6SJames Feist return; 799*83ff9ab6SJames Feist } 800*83ff9ab6SJames Feist else if (ret == CreatePIDRet::del) 801*83ff9ab6SJames Feist { 802*83ff9ab6SJames Feist continue; 803*83ff9ab6SJames Feist } 804*83ff9ab6SJames Feist 805*83ff9ab6SJames Feist if (!createNewObject) 806*83ff9ab6SJames Feist { 807*83ff9ab6SJames Feist for (const auto& property : output) 808*83ff9ab6SJames Feist { 809*83ff9ab6SJames Feist const char* iface = 810*83ff9ab6SJames Feist type.key() == "FanZones" 811*83ff9ab6SJames Feist ? pidZoneConfigurationIface 812*83ff9ab6SJames Feist : pidConfigurationIface; 813*83ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 814*83ff9ab6SJames Feist [response, 815*83ff9ab6SJames Feist propertyName{std::string(property.first)}]( 816*83ff9ab6SJames Feist const boost::system::error_code ec) { 817*83ff9ab6SJames Feist if (ec) 818*83ff9ab6SJames Feist { 819*83ff9ab6SJames Feist BMCWEB_LOG_ERROR 820*83ff9ab6SJames Feist << "Error patching " 821*83ff9ab6SJames Feist << propertyName << ": " << ec; 822*83ff9ab6SJames Feist response->res.result( 823*83ff9ab6SJames Feist boost::beast::http::status:: 824*83ff9ab6SJames Feist internal_server_error); 825*83ff9ab6SJames Feist } 826*83ff9ab6SJames Feist }, 827*83ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", 828*83ff9ab6SJames Feist pathItr->first.str, 829*83ff9ab6SJames Feist "org.freedesktop.DBus.Properties", "Set", 830*83ff9ab6SJames Feist std::string(iface), property.first, 831*83ff9ab6SJames Feist property.second); 832*83ff9ab6SJames Feist } 833*83ff9ab6SJames Feist } 834*83ff9ab6SJames Feist else 835*83ff9ab6SJames Feist { 836*83ff9ab6SJames Feist if (chassis.empty()) 837*83ff9ab6SJames Feist { 838*83ff9ab6SJames Feist BMCWEB_LOG_ERROR 839*83ff9ab6SJames Feist << "Failed to get chassis from config"; 840*83ff9ab6SJames Feist response->res.result( 841*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 842*83ff9ab6SJames Feist return; 843*83ff9ab6SJames Feist } 844*83ff9ab6SJames Feist 845*83ff9ab6SJames Feist bool foundChassis = false; 846*83ff9ab6SJames Feist for (const auto& obj : managedObj) 847*83ff9ab6SJames Feist { 848*83ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 849*83ff9ab6SJames Feist chassis)) 850*83ff9ab6SJames Feist { 851*83ff9ab6SJames Feist chassis = obj.first.str; 852*83ff9ab6SJames Feist foundChassis = true; 853*83ff9ab6SJames Feist break; 854*83ff9ab6SJames Feist } 855*83ff9ab6SJames Feist } 856*83ff9ab6SJames Feist if (!foundChassis) 857*83ff9ab6SJames Feist { 858*83ff9ab6SJames Feist BMCWEB_LOG_ERROR 859*83ff9ab6SJames Feist << "Failed to find chassis on dbus"; 860*83ff9ab6SJames Feist messages::addMessageToErrorJson( 861*83ff9ab6SJames Feist response->res.jsonValue, 862*83ff9ab6SJames Feist messages::resourceMissingAtURI( 863*83ff9ab6SJames Feist "/redfish/v1/Chassis/" + chassis)); 864*83ff9ab6SJames Feist response->res.result( 865*83ff9ab6SJames Feist boost::beast::http::status:: 866*83ff9ab6SJames Feist internal_server_error); 867*83ff9ab6SJames Feist return; 868*83ff9ab6SJames Feist } 869*83ff9ab6SJames Feist 870*83ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 871*83ff9ab6SJames Feist [response](const boost::system::error_code ec) { 872*83ff9ab6SJames Feist if (ec) 873*83ff9ab6SJames Feist { 874*83ff9ab6SJames Feist BMCWEB_LOG_ERROR 875*83ff9ab6SJames Feist << "Error Adding Pid Object " << ec; 876*83ff9ab6SJames Feist response->res.result( 877*83ff9ab6SJames Feist boost::beast::http::status:: 878*83ff9ab6SJames Feist internal_server_error); 879*83ff9ab6SJames Feist } 880*83ff9ab6SJames Feist }, 881*83ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", chassis, 882*83ff9ab6SJames Feist "xyz.openbmc_project.AddObject", "AddObject", 883*83ff9ab6SJames Feist output); 884*83ff9ab6SJames Feist } 885*83ff9ab6SJames Feist } 886*83ff9ab6SJames Feist } 887*83ff9ab6SJames Feist }, 888*83ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 889*83ff9ab6SJames Feist "GetManagedObjects"); 890*83ff9ab6SJames Feist } 8915b4aa86bSJames Feist 8925b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 8935b4aa86bSJames Feist const std::vector<std::string>& params) override 8945b4aa86bSJames Feist { 895*83ff9ab6SJames Feist nlohmann::json patch; 896*83ff9ab6SJames Feist if (!json_util::processJsonFromRequest(res, req, patch)) 897*83ff9ab6SJames Feist { 898*83ff9ab6SJames Feist return; 899*83ff9ab6SJames Feist } 900*83ff9ab6SJames Feist std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 901*83ff9ab6SJames Feist for (const auto& topLevel : patch.items()) 902*83ff9ab6SJames Feist { 903*83ff9ab6SJames Feist if (topLevel.key() == "Oem") 904*83ff9ab6SJames Feist { 905*83ff9ab6SJames Feist if (!topLevel.value().is_object()) 906*83ff9ab6SJames Feist { 907*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 908*83ff9ab6SJames Feist res.result(boost::beast::http::status::bad_request); 909*83ff9ab6SJames Feist return; 910*83ff9ab6SJames Feist } 911*83ff9ab6SJames Feist } 912*83ff9ab6SJames Feist else 913*83ff9ab6SJames Feist { 914*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 915*83ff9ab6SJames Feist messages::addMessageToErrorJson( 916*83ff9ab6SJames Feist response->res.jsonValue, 917*83ff9ab6SJames Feist messages::propertyUnknown(topLevel.key())); 918*83ff9ab6SJames Feist res.result(boost::beast::http::status::bad_request); 919*83ff9ab6SJames Feist return; 920*83ff9ab6SJames Feist } 921*83ff9ab6SJames Feist for (const auto& oemLevel : topLevel.value().items()) 922*83ff9ab6SJames Feist { 923*83ff9ab6SJames Feist if (oemLevel.key() == "OpenBmc") 924*83ff9ab6SJames Feist { 925*83ff9ab6SJames Feist if (!oemLevel.value().is_object()) 926*83ff9ab6SJames Feist { 927*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 928*83ff9ab6SJames Feist res.result(boost::beast::http::status::bad_request); 929*83ff9ab6SJames Feist return; 930*83ff9ab6SJames Feist } 931*83ff9ab6SJames Feist for (const auto& typeLevel : oemLevel.value().items()) 932*83ff9ab6SJames Feist { 933*83ff9ab6SJames Feist 934*83ff9ab6SJames Feist if (typeLevel.key() == "Fan") 935*83ff9ab6SJames Feist { 936*83ff9ab6SJames Feist if (!typeLevel.value().is_object()) 937*83ff9ab6SJames Feist { 938*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " 939*83ff9ab6SJames Feist << typeLevel.key(); 940*83ff9ab6SJames Feist messages::addMessageToErrorJson( 941*83ff9ab6SJames Feist response->res.jsonValue, 942*83ff9ab6SJames Feist messages::propertyValueFormatError( 943*83ff9ab6SJames Feist typeLevel.value().dump(), 944*83ff9ab6SJames Feist typeLevel.key())); 945*83ff9ab6SJames Feist res.result( 946*83ff9ab6SJames Feist boost::beast::http::status::bad_request); 947*83ff9ab6SJames Feist return; 948*83ff9ab6SJames Feist } 949*83ff9ab6SJames Feist setPidValues(response, 950*83ff9ab6SJames Feist std::move(typeLevel.value())); 951*83ff9ab6SJames Feist } 952*83ff9ab6SJames Feist else 953*83ff9ab6SJames Feist { 954*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key(); 955*83ff9ab6SJames Feist messages::addMessageToErrorJson( 956*83ff9ab6SJames Feist response->res.jsonValue, 957*83ff9ab6SJames Feist messages::propertyUnknown(typeLevel.key())); 958*83ff9ab6SJames Feist res.result(boost::beast::http::status::bad_request); 959*83ff9ab6SJames Feist return; 960*83ff9ab6SJames Feist } 961*83ff9ab6SJames Feist } 962*83ff9ab6SJames Feist } 963*83ff9ab6SJames Feist else 964*83ff9ab6SJames Feist { 965*83ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 966*83ff9ab6SJames Feist messages::addMessageToErrorJson( 967*83ff9ab6SJames Feist response->res.jsonValue, 968*83ff9ab6SJames Feist messages::propertyUnknown(oemLevel.key())); 969*83ff9ab6SJames Feist res.result(boost::beast::http::status::bad_request); 970*83ff9ab6SJames Feist return; 971*83ff9ab6SJames Feist } 972*83ff9ab6SJames Feist } 973*83ff9ab6SJames Feist } 9749c310685SBorawski.Lukasz } 9759c310685SBorawski.Lukasz 9761abe55efSEd Tanous std::string getDateTime() const 9771abe55efSEd Tanous { 9789c310685SBorawski.Lukasz std::array<char, 128> dateTime; 9799c310685SBorawski.Lukasz std::string redfishDateTime("0000-00-00T00:00:00Z00:00"); 9809c310685SBorawski.Lukasz std::time_t time = std::time(nullptr); 9819c310685SBorawski.Lukasz 9829c310685SBorawski.Lukasz if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z", 9831abe55efSEd Tanous std::localtime(&time))) 9841abe55efSEd Tanous { 9859c310685SBorawski.Lukasz // insert the colon required by the ISO 8601 standard 9869c310685SBorawski.Lukasz redfishDateTime = std::string(dateTime.data()); 9879c310685SBorawski.Lukasz redfishDateTime.insert(redfishDateTime.end() - 2, ':'); 9889c310685SBorawski.Lukasz } 9899c310685SBorawski.Lukasz 9909c310685SBorawski.Lukasz return redfishDateTime; 9919c310685SBorawski.Lukasz } 9929c310685SBorawski.Lukasz }; 9939c310685SBorawski.Lukasz 9941abe55efSEd Tanous class ManagerCollection : public Node 9951abe55efSEd Tanous { 9969c310685SBorawski.Lukasz public: 9971abe55efSEd Tanous ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") 9981abe55efSEd Tanous { 9999c310685SBorawski.Lukasz Node::json["@odata.id"] = "/redfish/v1/Managers"; 10009c310685SBorawski.Lukasz Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection"; 10019c310685SBorawski.Lukasz Node::json["@odata.context"] = 10029c310685SBorawski.Lukasz "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 10039c310685SBorawski.Lukasz Node::json["Name"] = "Manager Collection"; 10049c310685SBorawski.Lukasz Node::json["Members@odata.count"] = 1; 10055b4aa86bSJames Feist Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 10063ebd75f7SEd Tanous 1007a434f2bdSEd Tanous entityPrivileges = { 1008a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 1009e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1010e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1011e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1012e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1013e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 10149c310685SBorawski.Lukasz } 10159c310685SBorawski.Lukasz 10169c310685SBorawski.Lukasz private: 101755c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 10181abe55efSEd Tanous const std::vector<std::string>& params) override 10191abe55efSEd Tanous { 1020*83ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 1021*83ff9ab6SJames Feist // because it has a duplicate entry for members 102255c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 102355c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 102455c7b7a2SEd Tanous res.jsonValue["@odata.context"] = 102555c7b7a2SEd Tanous "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 102655c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 102755c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 102855c7b7a2SEd Tanous res.jsonValue["Members"] = { 10295b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 10309c310685SBorawski.Lukasz res.end(); 10319c310685SBorawski.Lukasz } 10329c310685SBorawski.Lukasz }; 10339c310685SBorawski.Lukasz } // namespace redfish 1034