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 27583ff9ab6SJames Feist enum class CreatePIDRet 27683ff9ab6SJames Feist { 27783ff9ab6SJames Feist fail, 27883ff9ab6SJames Feist del, 27983ff9ab6SJames Feist patch 28083ff9ab6SJames Feist }; 28183ff9ab6SJames Feist 28283ff9ab6SJames Feist static CreatePIDRet createPidInterface( 28383ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 28483ff9ab6SJames Feist const nlohmann::json& record, const std::string& path, 28583ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 28683ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 28783ff9ab6SJames Feist output, 28883ff9ab6SJames Feist std::string& chassis) 28983ff9ab6SJames Feist { 29083ff9ab6SJames Feist 29183ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 29283ff9ab6SJames Feist { 29383ff9ab6SJames Feist if (createNewObject) 29483ff9ab6SJames Feist { 29583ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 29683ff9ab6SJames Feist : std::string("fan"); 29783ff9ab6SJames Feist output["Type"] = std::string("Pid"); 29883ff9ab6SJames Feist } 29983ff9ab6SJames Feist else if (record == nullptr) 30083ff9ab6SJames Feist { 30183ff9ab6SJames Feist // delete interface 30283ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 30383ff9ab6SJames Feist [response, 30483ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 30583ff9ab6SJames Feist if (ec) 30683ff9ab6SJames Feist { 30783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 30883ff9ab6SJames Feist << ec; 309*35a62c7cSJason M. Bills messages::internalError(response->res); 31083ff9ab6SJames Feist } 31183ff9ab6SJames Feist }, 31283ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 31383ff9ab6SJames Feist pidConfigurationIface, "Delete"); 31483ff9ab6SJames Feist return CreatePIDRet::del; 31583ff9ab6SJames Feist } 31683ff9ab6SJames Feist 31783ff9ab6SJames Feist for (auto& field : record.items()) 31883ff9ab6SJames Feist { 31983ff9ab6SJames Feist if (field.key() == "Zones") 32083ff9ab6SJames Feist { 32183ff9ab6SJames Feist if (!field.value().is_array()) 32283ff9ab6SJames Feist { 32383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 324*35a62c7cSJason M. Bills messages::propertyValueFormatError( 325*35a62c7cSJason M. Bills response->res, field.value(), field.key()); 32683ff9ab6SJames Feist return CreatePIDRet::fail; 32783ff9ab6SJames Feist } 32883ff9ab6SJames Feist std::vector<std::string> inputs; 32983ff9ab6SJames Feist for (const auto& odata : field.value().items()) 33083ff9ab6SJames Feist { 33183ff9ab6SJames Feist for (const auto& value : odata.value().items()) 33283ff9ab6SJames Feist { 33383ff9ab6SJames Feist const std::string* path = 33483ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 33583ff9ab6SJames Feist if (path == nullptr) 33683ff9ab6SJames Feist { 33783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 33883ff9ab6SJames Feist messages::propertyValueFormatError( 339*35a62c7cSJason M. Bills response->res, field.value().dump(), 340*35a62c7cSJason M. Bills field.key()); 34183ff9ab6SJames Feist return CreatePIDRet::fail; 34283ff9ab6SJames Feist } 34383ff9ab6SJames Feist std::string input; 34483ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*path, 4, 34583ff9ab6SJames Feist input)) 34683ff9ab6SJames Feist { 34783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *path; 34883ff9ab6SJames Feist messages::propertyValueFormatError( 349*35a62c7cSJason M. Bills response->res, field.value().dump(), 350*35a62c7cSJason M. Bills field.key()); 35183ff9ab6SJames Feist return CreatePIDRet::fail; 35283ff9ab6SJames Feist } 35383ff9ab6SJames Feist boost::replace_all(input, "_", " "); 35483ff9ab6SJames Feist inputs.emplace_back(std::move(input)); 35583ff9ab6SJames Feist } 35683ff9ab6SJames Feist } 35783ff9ab6SJames Feist output["Zones"] = std::move(inputs); 35883ff9ab6SJames Feist } 35983ff9ab6SJames Feist else if (field.key() == "Inputs" || field.key() == "Outputs") 36083ff9ab6SJames Feist { 36183ff9ab6SJames Feist if (!field.value().is_array()) 36283ff9ab6SJames Feist { 36383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 364*35a62c7cSJason M. Bills messages::propertyValueFormatError( 365*35a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 36683ff9ab6SJames Feist return CreatePIDRet::fail; 36783ff9ab6SJames Feist } 36883ff9ab6SJames Feist std::vector<std::string> inputs; 36983ff9ab6SJames Feist for (const auto& value : field.value().items()) 37083ff9ab6SJames Feist { 37183ff9ab6SJames Feist const std::string* sensor = 37283ff9ab6SJames Feist value.value().get_ptr<const std::string*>(); 37383ff9ab6SJames Feist 37483ff9ab6SJames Feist if (sensor == nullptr) 37583ff9ab6SJames Feist { 37683ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " 37783ff9ab6SJames Feist << field.value().dump(); 37883ff9ab6SJames Feist messages::propertyValueFormatError( 379*35a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 38083ff9ab6SJames Feist return CreatePIDRet::fail; 38183ff9ab6SJames Feist } 38283ff9ab6SJames Feist 38383ff9ab6SJames Feist std::string input = 38483ff9ab6SJames Feist boost::replace_all_copy(*sensor, "_", " "); 38583ff9ab6SJames Feist inputs.push_back(std::move(input)); 38683ff9ab6SJames Feist // try to find the sensor in the 38783ff9ab6SJames Feist // configuration 38883ff9ab6SJames Feist if (chassis.empty()) 38983ff9ab6SJames Feist { 39083ff9ab6SJames Feist std::find_if( 39183ff9ab6SJames Feist managedObj.begin(), managedObj.end(), 39283ff9ab6SJames Feist [&chassis, sensor](const auto& obj) { 39383ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 39483ff9ab6SJames Feist *sensor)) 39583ff9ab6SJames Feist { 39683ff9ab6SJames Feist return dbus::utility::getNthStringFromPath( 39783ff9ab6SJames Feist obj.first.str, 5, chassis); 39883ff9ab6SJames Feist } 39983ff9ab6SJames Feist return false; 40083ff9ab6SJames Feist }); 40183ff9ab6SJames Feist } 40283ff9ab6SJames Feist } 40383ff9ab6SJames Feist output[field.key()] = inputs; 40483ff9ab6SJames Feist } 40583ff9ab6SJames Feist 40683ff9ab6SJames Feist // doubles 40783ff9ab6SJames Feist else if (field.key() == "FFGainCoefficient" || 40883ff9ab6SJames Feist field.key() == "FFOffCoefficient" || 40983ff9ab6SJames Feist field.key() == "ICoefficient" || 41083ff9ab6SJames Feist field.key() == "ILimitMax" || field.key() == "ILimitMin" || 41183ff9ab6SJames Feist field.key() == "OutLimitMax" || 41283ff9ab6SJames Feist field.key() == "OutLimitMin" || 41383ff9ab6SJames Feist field.key() == "PCoefficient" || 41483ff9ab6SJames Feist field.key() == "SetPoint" || field.key() == "SlewNeg" || 41583ff9ab6SJames Feist field.key() == "SlewPos") 41683ff9ab6SJames Feist { 41783ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 41883ff9ab6SJames Feist if (ptr == nullptr) 41983ff9ab6SJames Feist { 42083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 421*35a62c7cSJason M. Bills messages::propertyValueFormatError( 422*35a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 42383ff9ab6SJames Feist return CreatePIDRet::fail; 42483ff9ab6SJames Feist } 42583ff9ab6SJames Feist output[field.key()] = *ptr; 42683ff9ab6SJames Feist } 42783ff9ab6SJames Feist 42883ff9ab6SJames Feist else 42983ff9ab6SJames Feist { 43083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 431*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 43283ff9ab6SJames Feist return CreatePIDRet::fail; 43383ff9ab6SJames Feist } 43483ff9ab6SJames Feist } 43583ff9ab6SJames Feist } 43683ff9ab6SJames Feist else if (type == "FanZones") 43783ff9ab6SJames Feist { 43883ff9ab6SJames Feist if (!createNewObject && record == nullptr) 43983ff9ab6SJames Feist { 44083ff9ab6SJames Feist // delete interface 44183ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 44283ff9ab6SJames Feist [response, 44383ff9ab6SJames Feist path{std::string(path)}](const boost::system::error_code ec) { 44483ff9ab6SJames Feist if (ec) 44583ff9ab6SJames Feist { 44683ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " 44783ff9ab6SJames Feist << ec; 448*35a62c7cSJason M. Bills messages::internalError(response->res); 44983ff9ab6SJames Feist } 45083ff9ab6SJames Feist }, 45183ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", path, 45283ff9ab6SJames Feist pidZoneConfigurationIface, "Delete"); 45383ff9ab6SJames Feist return CreatePIDRet::del; 45483ff9ab6SJames Feist } 45583ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 45683ff9ab6SJames Feist 45783ff9ab6SJames Feist for (auto& field : record.items()) 45883ff9ab6SJames Feist { 45983ff9ab6SJames Feist if (field.key() == "Chassis") 46083ff9ab6SJames Feist { 46183ff9ab6SJames Feist const std::string* chassisId = nullptr; 46283ff9ab6SJames Feist for (const auto& id : field.value().items()) 46383ff9ab6SJames Feist { 46483ff9ab6SJames Feist if (id.key() != "@odata.id") 46583ff9ab6SJames Feist { 46683ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << id.key(); 467*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 46883ff9ab6SJames Feist return CreatePIDRet::fail; 46983ff9ab6SJames Feist } 47083ff9ab6SJames Feist chassisId = id.value().get_ptr<const std::string*>(); 47183ff9ab6SJames Feist if (chassisId == nullptr) 47283ff9ab6SJames Feist { 47383ff9ab6SJames Feist messages::createFailedMissingReqProperties( 474*35a62c7cSJason M. Bills response->res, field.key()); 47583ff9ab6SJames Feist return CreatePIDRet::fail; 47683ff9ab6SJames Feist } 47783ff9ab6SJames Feist } 47883ff9ab6SJames Feist 47983ff9ab6SJames Feist // /refish/v1/chassis/chassis_name/ 48083ff9ab6SJames Feist if (!dbus::utility::getNthStringFromPath(*chassisId, 3, 48183ff9ab6SJames Feist chassis)) 48283ff9ab6SJames Feist { 48383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId; 484*35a62c7cSJason M. Bills messages::invalidObject(response->res, *chassisId); 48583ff9ab6SJames Feist return CreatePIDRet::fail; 48683ff9ab6SJames Feist } 48783ff9ab6SJames Feist } 48883ff9ab6SJames Feist else if (field.key() == "FailSafePercent" || 48983ff9ab6SJames Feist field.key() == "MinThermalRpm") 49083ff9ab6SJames Feist { 49183ff9ab6SJames Feist const double* ptr = field.value().get_ptr<const double*>(); 49283ff9ab6SJames Feist if (ptr == nullptr) 49383ff9ab6SJames Feist { 49483ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 495*35a62c7cSJason M. Bills messages::propertyValueFormatError( 496*35a62c7cSJason M. Bills response->res, field.value().dump(), field.key()); 49783ff9ab6SJames Feist return CreatePIDRet::fail; 49883ff9ab6SJames Feist } 49983ff9ab6SJames Feist output[field.key()] = *ptr; 50083ff9ab6SJames Feist } 50183ff9ab6SJames Feist else 50283ff9ab6SJames Feist { 50383ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); 504*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, field.key()); 50583ff9ab6SJames Feist return CreatePIDRet::fail; 50683ff9ab6SJames Feist } 50783ff9ab6SJames Feist } 50883ff9ab6SJames Feist } 50983ff9ab6SJames Feist else 51083ff9ab6SJames Feist { 51183ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type; 512*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 51383ff9ab6SJames Feist return CreatePIDRet::fail; 51483ff9ab6SJames Feist } 51583ff9ab6SJames Feist return CreatePIDRet::patch; 51683ff9ab6SJames Feist } 51783ff9ab6SJames Feist 5181abe55efSEd Tanous class Manager : public Node 5191abe55efSEd Tanous { 5209c310685SBorawski.Lukasz public: 5215b4aa86bSJames Feist Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") 5221abe55efSEd Tanous { 5235b4aa86bSJames Feist Node::json["@odata.id"] = "/redfish/v1/Managers/bmc"; 5249c310685SBorawski.Lukasz Node::json["@odata.type"] = "#Manager.v1_3_0.Manager"; 5259c310685SBorawski.Lukasz Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager"; 5265b4aa86bSJames Feist Node::json["Id"] = "bmc"; 5279c310685SBorawski.Lukasz Node::json["Name"] = "OpenBmc Manager"; 5289c310685SBorawski.Lukasz Node::json["Description"] = "Baseboard Management Controller"; 5299c310685SBorawski.Lukasz Node::json["PowerState"] = "On"; 530ca537928SJennifer Lee Node::json["ManagerType"] = "BMC"; 5319c310685SBorawski.Lukasz Node::json["UUID"] = 53255c7b7a2SEd Tanous app.template getMiddleware<crow::persistent_data::Middleware>() 53355c7b7a2SEd Tanous .systemUuid; 5349c310685SBorawski.Lukasz Node::json["Model"] = "OpenBmc"; // TODO(ed), get model 535ca537928SJennifer Lee Node::json["EthernetInterfaces"] = { 5365b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 5373ebd75f7SEd Tanous 538a434f2bdSEd Tanous entityPrivileges = { 539a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 540e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 541e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 542e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 543e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 544e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 5455b4aa86bSJames Feist 5465b4aa86bSJames Feist // default oem data 5475b4aa86bSJames Feist nlohmann::json& oem = Node::json["Oem"]; 5485b4aa86bSJames Feist nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 5495b4aa86bSJames Feist oem["@odata.type"] = "#OemManager.Oem"; 5505b4aa86bSJames Feist oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 5515b4aa86bSJames Feist oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem"; 5525b4aa86bSJames Feist oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 5535b4aa86bSJames Feist oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 5545b4aa86bSJames Feist oemOpenbmc["@odata.context"] = 5555b4aa86bSJames Feist "/redfish/v1/$metadata#OemManager.OpenBmc"; 5569c310685SBorawski.Lukasz } 5579c310685SBorawski.Lukasz 5589c310685SBorawski.Lukasz private: 5595b4aa86bSJames Feist void getPidValues(std::shared_ptr<AsyncResp> asyncResp) 5605b4aa86bSJames Feist { 5615b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 5625b4aa86bSJames Feist [asyncResp](const boost::system::error_code ec, 5635b4aa86bSJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 5645b4aa86bSJames Feist if (ec) 5655b4aa86bSJames Feist { 5665b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 567f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5685b4aa86bSJames Feist return; 5695b4aa86bSJames Feist } 5705b4aa86bSJames Feist 5715b4aa86bSJames Feist // create map of <connection, path to objMgr>> 5725b4aa86bSJames Feist boost::container::flat_map<std::string, std::string> 5735b4aa86bSJames Feist objectMgrPaths; 5746bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 5755b4aa86bSJames Feist for (const auto& pathGroup : subtree) 5765b4aa86bSJames Feist { 5775b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 5785b4aa86bSJames Feist { 5796bce33bcSJames Feist auto findConnection = 5806bce33bcSJames Feist calledConnections.find(connectionGroup.first); 5816bce33bcSJames Feist if (findConnection != calledConnections.end()) 5826bce33bcSJames Feist { 5836bce33bcSJames Feist break; 5846bce33bcSJames Feist } 5855b4aa86bSJames Feist for (const std::string& interface : 5865b4aa86bSJames Feist connectionGroup.second) 5875b4aa86bSJames Feist { 5885b4aa86bSJames Feist if (interface == objectManagerIface) 5895b4aa86bSJames Feist { 5905b4aa86bSJames Feist objectMgrPaths[connectionGroup.first] = 5915b4aa86bSJames Feist pathGroup.first; 5925b4aa86bSJames Feist } 5935b4aa86bSJames Feist // this list is alphabetical, so we 5945b4aa86bSJames Feist // should have found the objMgr by now 5955b4aa86bSJames Feist if (interface == pidConfigurationIface || 5965b4aa86bSJames Feist interface == pidZoneConfigurationIface) 5975b4aa86bSJames Feist { 5985b4aa86bSJames Feist auto findObjMgr = 5995b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 6005b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 6015b4aa86bSJames Feist { 6025b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 6035b4aa86bSJames Feist << "Has no Object Manager"; 6045b4aa86bSJames Feist continue; 6055b4aa86bSJames Feist } 6066bce33bcSJames Feist 6076bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 6086bce33bcSJames Feist 6095b4aa86bSJames Feist asyncPopulatePid(findObjMgr->first, 6105b4aa86bSJames Feist findObjMgr->second, asyncResp); 6115b4aa86bSJames Feist break; 6125b4aa86bSJames Feist } 6135b4aa86bSJames Feist } 6145b4aa86bSJames Feist } 6155b4aa86bSJames Feist } 6165b4aa86bSJames Feist }, 6175b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 6185b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 6195b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 6205b4aa86bSJames Feist std::array<const char*, 3>{pidConfigurationIface, 6215b4aa86bSJames Feist pidZoneConfigurationIface, 6225b4aa86bSJames Feist objectManagerIface}); 6235b4aa86bSJames Feist } 6245b4aa86bSJames Feist 62555c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 6261abe55efSEd Tanous const std::vector<std::string>& params) override 6271abe55efSEd Tanous { 628ca537928SJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 629ca537928SJennifer Lee asyncResp->res.jsonValue = Node::json; 630ca537928SJennifer Lee 6319c310685SBorawski.Lukasz Node::json["DateTime"] = getDateTime(); 63255c7b7a2SEd Tanous res.jsonValue = Node::json; 6335b4aa86bSJames Feist 634ca537928SJennifer Lee crow::connections::systemBus->async_method_call( 635ca537928SJennifer Lee [asyncResp](const boost::system::error_code ec, 6365b4aa86bSJames Feist const dbus::utility::ManagedObjectType& resp) { 637ca537928SJennifer Lee if (ec) 638ca537928SJennifer Lee { 639ca537928SJennifer Lee BMCWEB_LOG_ERROR << "Error while getting Software Version"; 640f12894f8SJason M. Bills messages::internalError(asyncResp->res); 641ca537928SJennifer Lee return; 642ca537928SJennifer Lee } 643ca537928SJennifer Lee 644ca537928SJennifer Lee for (auto& objpath : resp) 645ca537928SJennifer Lee { 646ca537928SJennifer Lee for (auto& interface : objpath.second) 647ca537928SJennifer Lee { 648ca537928SJennifer Lee // If interface is xyz.openbmc_project.Software.Version, 649ca537928SJennifer Lee // this is what we're looking for. 650ca537928SJennifer Lee if (interface.first == 651ca537928SJennifer Lee "xyz.openbmc_project.Software.Version") 652ca537928SJennifer Lee { 653ca537928SJennifer Lee // Cut out everyting until last "/", ... 654ca537928SJennifer Lee const std::string& iface_id = objpath.first; 655ca537928SJennifer Lee for (auto& property : interface.second) 656ca537928SJennifer Lee { 657ca537928SJennifer Lee if (property.first == "Version") 658ca537928SJennifer Lee { 659ca537928SJennifer Lee const std::string* value = 660ca537928SJennifer Lee mapbox::getPtr<const std::string>( 661ca537928SJennifer Lee property.second); 662ca537928SJennifer Lee if (value == nullptr) 663ca537928SJennifer Lee { 664ca537928SJennifer Lee continue; 665ca537928SJennifer Lee } 666ca537928SJennifer Lee asyncResp->res 667ca537928SJennifer Lee .jsonValue["FirmwareVersion"] = *value; 668ca537928SJennifer Lee } 669ca537928SJennifer Lee } 670ca537928SJennifer Lee } 671ca537928SJennifer Lee } 672ca537928SJennifer Lee } 673ca537928SJennifer Lee }, 674ca537928SJennifer Lee "xyz.openbmc_project.Software.BMC.Updater", 675ca537928SJennifer Lee "/xyz/openbmc_project/software", 676ca537928SJennifer Lee "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 6775b4aa86bSJames Feist getPidValues(asyncResp); 6785b4aa86bSJames Feist } 67983ff9ab6SJames Feist void setPidValues(std::shared_ptr<AsyncResp> response, 68083ff9ab6SJames Feist const nlohmann::json& data) 68183ff9ab6SJames Feist { 68283ff9ab6SJames Feist // todo(james): might make sense to do a mapper call here if this 68383ff9ab6SJames Feist // interface gets more traction 68483ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 68583ff9ab6SJames Feist [response, 68683ff9ab6SJames Feist data](const boost::system::error_code ec, 68783ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj) { 68883ff9ab6SJames Feist if (ec) 68983ff9ab6SJames Feist { 69083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 691*35a62c7cSJason M. Bills messages::internalError(response->res); 69283ff9ab6SJames Feist return; 69383ff9ab6SJames Feist } 69483ff9ab6SJames Feist for (const auto& type : data.items()) 69583ff9ab6SJames Feist { 69683ff9ab6SJames Feist if (!type.value().is_object()) 69783ff9ab6SJames Feist { 69883ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Illegal Type " << type.key(); 699*35a62c7cSJason M. Bills messages::propertyValueFormatError( 700*35a62c7cSJason M. Bills response->res, type.value(), type.key()); 70183ff9ab6SJames Feist return; 70283ff9ab6SJames Feist } 70383ff9ab6SJames Feist for (const auto& record : type.value().items()) 70483ff9ab6SJames Feist { 70583ff9ab6SJames Feist const std::string& name = record.key(); 70683ff9ab6SJames Feist auto pathItr = 70783ff9ab6SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 70883ff9ab6SJames Feist [&name](const auto& obj) { 70983ff9ab6SJames Feist return boost::algorithm::ends_with( 71083ff9ab6SJames Feist obj.first.str, name); 71183ff9ab6SJames Feist }); 71283ff9ab6SJames Feist boost::container::flat_map< 71383ff9ab6SJames Feist std::string, dbus::utility::DbusVariantType> 71483ff9ab6SJames Feist output; 71583ff9ab6SJames Feist 71683ff9ab6SJames Feist output.reserve(16); // The pid interface length 71783ff9ab6SJames Feist 71883ff9ab6SJames Feist // determines if we're patching entity-manager or 71983ff9ab6SJames Feist // creating a new object 72083ff9ab6SJames Feist bool createNewObject = (pathItr == managedObj.end()); 72183ff9ab6SJames Feist if (type.key() == "PidControllers" || 72283ff9ab6SJames Feist type.key() == "FanControllers") 72383ff9ab6SJames Feist { 72483ff9ab6SJames Feist if (!createNewObject && 72583ff9ab6SJames Feist pathItr->second.find(pidConfigurationIface) == 72683ff9ab6SJames Feist pathItr->second.end()) 72783ff9ab6SJames Feist { 72883ff9ab6SJames Feist createNewObject = true; 72983ff9ab6SJames Feist } 73083ff9ab6SJames Feist } 73183ff9ab6SJames Feist else if (!createNewObject && 73283ff9ab6SJames Feist pathItr->second.find( 73383ff9ab6SJames Feist pidZoneConfigurationIface) == 73483ff9ab6SJames Feist pathItr->second.end()) 73583ff9ab6SJames Feist { 73683ff9ab6SJames Feist createNewObject = true; 73783ff9ab6SJames Feist } 73883ff9ab6SJames Feist output["Name"] = 73983ff9ab6SJames Feist boost::replace_all_copy(name, "_", " "); 74083ff9ab6SJames Feist 74183ff9ab6SJames Feist std::string chassis; 74283ff9ab6SJames Feist CreatePIDRet ret = createPidInterface( 74383ff9ab6SJames Feist response, type.key(), record.value(), 74483ff9ab6SJames Feist pathItr->first.str, managedObj, createNewObject, 74583ff9ab6SJames Feist output, chassis); 74683ff9ab6SJames Feist if (ret == CreatePIDRet::fail) 74783ff9ab6SJames Feist { 74883ff9ab6SJames Feist return; 74983ff9ab6SJames Feist } 75083ff9ab6SJames Feist else if (ret == CreatePIDRet::del) 75183ff9ab6SJames Feist { 75283ff9ab6SJames Feist continue; 75383ff9ab6SJames Feist } 75483ff9ab6SJames Feist 75583ff9ab6SJames Feist if (!createNewObject) 75683ff9ab6SJames Feist { 75783ff9ab6SJames Feist for (const auto& property : output) 75883ff9ab6SJames Feist { 75983ff9ab6SJames Feist const char* iface = 76083ff9ab6SJames Feist type.key() == "FanZones" 76183ff9ab6SJames Feist ? pidZoneConfigurationIface 76283ff9ab6SJames Feist : pidConfigurationIface; 76383ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 76483ff9ab6SJames Feist [response, 76583ff9ab6SJames Feist propertyName{std::string(property.first)}]( 76683ff9ab6SJames Feist const boost::system::error_code ec) { 76783ff9ab6SJames Feist if (ec) 76883ff9ab6SJames Feist { 76983ff9ab6SJames Feist BMCWEB_LOG_ERROR 77083ff9ab6SJames Feist << "Error patching " 77183ff9ab6SJames Feist << propertyName << ": " << ec; 772*35a62c7cSJason M. Bills messages::internalError( 773*35a62c7cSJason M. Bills response->res); 77483ff9ab6SJames Feist } 77583ff9ab6SJames Feist }, 77683ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", 77783ff9ab6SJames Feist pathItr->first.str, 77883ff9ab6SJames Feist "org.freedesktop.DBus.Properties", "Set", 77983ff9ab6SJames Feist std::string(iface), property.first, 78083ff9ab6SJames Feist property.second); 78183ff9ab6SJames Feist } 78283ff9ab6SJames Feist } 78383ff9ab6SJames Feist else 78483ff9ab6SJames Feist { 78583ff9ab6SJames Feist if (chassis.empty()) 78683ff9ab6SJames Feist { 78783ff9ab6SJames Feist BMCWEB_LOG_ERROR 78883ff9ab6SJames Feist << "Failed to get chassis from config"; 789*35a62c7cSJason M. Bills messages::invalidObject(response->res, name); 79083ff9ab6SJames Feist return; 79183ff9ab6SJames Feist } 79283ff9ab6SJames Feist 79383ff9ab6SJames Feist bool foundChassis = false; 79483ff9ab6SJames Feist for (const auto& obj : managedObj) 79583ff9ab6SJames Feist { 79683ff9ab6SJames Feist if (boost::algorithm::ends_with(obj.first.str, 79783ff9ab6SJames Feist chassis)) 79883ff9ab6SJames Feist { 79983ff9ab6SJames Feist chassis = obj.first.str; 80083ff9ab6SJames Feist foundChassis = true; 80183ff9ab6SJames Feist break; 80283ff9ab6SJames Feist } 80383ff9ab6SJames Feist } 80483ff9ab6SJames Feist if (!foundChassis) 80583ff9ab6SJames Feist { 80683ff9ab6SJames Feist BMCWEB_LOG_ERROR 80783ff9ab6SJames Feist << "Failed to find chassis on dbus"; 80883ff9ab6SJames Feist messages::resourceMissingAtURI( 809*35a62c7cSJason M. Bills response->res, 810*35a62c7cSJason M. Bills "/redfish/v1/Chassis/" + chassis); 81183ff9ab6SJames Feist return; 81283ff9ab6SJames Feist } 81383ff9ab6SJames Feist 81483ff9ab6SJames Feist crow::connections::systemBus->async_method_call( 81583ff9ab6SJames Feist [response](const boost::system::error_code ec) { 81683ff9ab6SJames Feist if (ec) 81783ff9ab6SJames Feist { 81883ff9ab6SJames Feist BMCWEB_LOG_ERROR 81983ff9ab6SJames Feist << "Error Adding Pid Object " << ec; 820*35a62c7cSJason M. Bills messages::internalError(response->res); 82183ff9ab6SJames Feist } 82283ff9ab6SJames Feist }, 82383ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", chassis, 82483ff9ab6SJames Feist "xyz.openbmc_project.AddObject", "AddObject", 82583ff9ab6SJames Feist output); 82683ff9ab6SJames Feist } 82783ff9ab6SJames Feist } 82883ff9ab6SJames Feist } 82983ff9ab6SJames Feist }, 83083ff9ab6SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 83183ff9ab6SJames Feist "GetManagedObjects"); 83283ff9ab6SJames Feist } 8335b4aa86bSJames Feist 8345b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 8355b4aa86bSJames Feist const std::vector<std::string>& params) override 8365b4aa86bSJames Feist { 83783ff9ab6SJames Feist nlohmann::json patch; 83883ff9ab6SJames Feist if (!json_util::processJsonFromRequest(res, req, patch)) 83983ff9ab6SJames Feist { 84083ff9ab6SJames Feist return; 84183ff9ab6SJames Feist } 84283ff9ab6SJames Feist std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 84383ff9ab6SJames Feist for (const auto& topLevel : patch.items()) 84483ff9ab6SJames Feist { 84583ff9ab6SJames Feist if (topLevel.key() == "Oem") 84683ff9ab6SJames Feist { 84783ff9ab6SJames Feist if (!topLevel.value().is_object()) 84883ff9ab6SJames Feist { 84983ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 850*35a62c7cSJason M. Bills messages::propertyValueFormatError( 851*35a62c7cSJason M. Bills response->res, topLevel.key(), "OemManager.Oem"); 85283ff9ab6SJames Feist return; 85383ff9ab6SJames Feist } 85483ff9ab6SJames Feist } 85583ff9ab6SJames Feist else 85683ff9ab6SJames Feist { 85783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << topLevel.key(); 858*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, topLevel.key()); 85983ff9ab6SJames Feist return; 86083ff9ab6SJames Feist } 86183ff9ab6SJames Feist for (const auto& oemLevel : topLevel.value().items()) 86283ff9ab6SJames Feist { 86383ff9ab6SJames Feist if (oemLevel.key() == "OpenBmc") 86483ff9ab6SJames Feist { 86583ff9ab6SJames Feist if (!oemLevel.value().is_object()) 86683ff9ab6SJames Feist { 86783ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 868*35a62c7cSJason M. Bills messages::propertyValueFormatError( 869*35a62c7cSJason M. Bills response->res, topLevel.key(), 870*35a62c7cSJason M. Bills "OemManager.OpenBmc"); 87183ff9ab6SJames Feist return; 87283ff9ab6SJames Feist } 87383ff9ab6SJames Feist for (const auto& typeLevel : oemLevel.value().items()) 87483ff9ab6SJames Feist { 87583ff9ab6SJames Feist 87683ff9ab6SJames Feist if (typeLevel.key() == "Fan") 87783ff9ab6SJames Feist { 87883ff9ab6SJames Feist if (!typeLevel.value().is_object()) 87983ff9ab6SJames Feist { 88083ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " 88183ff9ab6SJames Feist << typeLevel.key(); 88283ff9ab6SJames Feist messages::propertyValueFormatError( 883*35a62c7cSJason M. Bills response->res, typeLevel.value().dump(), 884*35a62c7cSJason M. Bills typeLevel.key()); 88583ff9ab6SJames Feist return; 88683ff9ab6SJames Feist } 88783ff9ab6SJames Feist setPidValues(response, 88883ff9ab6SJames Feist std::move(typeLevel.value())); 88983ff9ab6SJames Feist } 89083ff9ab6SJames Feist else 89183ff9ab6SJames Feist { 89283ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key(); 893*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, 894*35a62c7cSJason M. Bills typeLevel.key()); 89583ff9ab6SJames Feist return; 89683ff9ab6SJames Feist } 89783ff9ab6SJames Feist } 89883ff9ab6SJames Feist } 89983ff9ab6SJames Feist else 90083ff9ab6SJames Feist { 90183ff9ab6SJames Feist BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); 902*35a62c7cSJason M. Bills messages::propertyUnknown(response->res, oemLevel.key()); 90383ff9ab6SJames Feist return; 90483ff9ab6SJames Feist } 90583ff9ab6SJames Feist } 90683ff9ab6SJames Feist } 9079c310685SBorawski.Lukasz } 9089c310685SBorawski.Lukasz 9091abe55efSEd Tanous std::string getDateTime() const 9101abe55efSEd Tanous { 9119c310685SBorawski.Lukasz std::array<char, 128> dateTime; 9129c310685SBorawski.Lukasz std::string redfishDateTime("0000-00-00T00:00:00Z00:00"); 9139c310685SBorawski.Lukasz std::time_t time = std::time(nullptr); 9149c310685SBorawski.Lukasz 9159c310685SBorawski.Lukasz if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z", 9161abe55efSEd Tanous std::localtime(&time))) 9171abe55efSEd Tanous { 9189c310685SBorawski.Lukasz // insert the colon required by the ISO 8601 standard 9199c310685SBorawski.Lukasz redfishDateTime = std::string(dateTime.data()); 9209c310685SBorawski.Lukasz redfishDateTime.insert(redfishDateTime.end() - 2, ':'); 9219c310685SBorawski.Lukasz } 9229c310685SBorawski.Lukasz 9239c310685SBorawski.Lukasz return redfishDateTime; 9249c310685SBorawski.Lukasz } 9259c310685SBorawski.Lukasz }; 9269c310685SBorawski.Lukasz 9271abe55efSEd Tanous class ManagerCollection : public Node 9281abe55efSEd Tanous { 9299c310685SBorawski.Lukasz public: 9301abe55efSEd Tanous ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") 9311abe55efSEd Tanous { 9329c310685SBorawski.Lukasz Node::json["@odata.id"] = "/redfish/v1/Managers"; 9339c310685SBorawski.Lukasz Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection"; 9349c310685SBorawski.Lukasz Node::json["@odata.context"] = 9359c310685SBorawski.Lukasz "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 9369c310685SBorawski.Lukasz Node::json["Name"] = "Manager Collection"; 9379c310685SBorawski.Lukasz Node::json["Members@odata.count"] = 1; 9385b4aa86bSJames Feist Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 9393ebd75f7SEd Tanous 940a434f2bdSEd Tanous entityPrivileges = { 941a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 942e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 943e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 944e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 945e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 946e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 9479c310685SBorawski.Lukasz } 9489c310685SBorawski.Lukasz 9499c310685SBorawski.Lukasz private: 95055c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 9511abe55efSEd Tanous const std::vector<std::string>& params) override 9521abe55efSEd Tanous { 95383ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 95483ff9ab6SJames Feist // because it has a duplicate entry for members 95555c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 95655c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 95755c7b7a2SEd Tanous res.jsonValue["@odata.context"] = 95855c7b7a2SEd Tanous "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; 95955c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 96055c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 96155c7b7a2SEd Tanous res.jsonValue["Members"] = { 9625b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 9639c310685SBorawski.Lukasz res.end(); 9649c310685SBorawski.Lukasz } 9659c310685SBorawski.Lukasz }; 9669c310685SBorawski.Lukasz } // namespace redfish 967