19c310685SBorawski.Lukasz /* 29c310685SBorawski.Lukasz // Copyright (c) 2018 Intel Corporation 39c310685SBorawski.Lukasz // 49c310685SBorawski.Lukasz // Licensed under the Apache License, Version 2.0 (the "License"); 59c310685SBorawski.Lukasz // you may not use this file except in compliance with the License. 69c310685SBorawski.Lukasz // You may obtain a copy of the License at 79c310685SBorawski.Lukasz // 89c310685SBorawski.Lukasz // http://www.apache.org/licenses/LICENSE-2.0 99c310685SBorawski.Lukasz // 109c310685SBorawski.Lukasz // Unless required by applicable law or agreed to in writing, software 119c310685SBorawski.Lukasz // distributed under the License is distributed on an "AS IS" BASIS, 129c310685SBorawski.Lukasz // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139c310685SBorawski.Lukasz // See the License for the specific language governing permissions and 149c310685SBorawski.Lukasz // limitations under the License. 159c310685SBorawski.Lukasz */ 169c310685SBorawski.Lukasz #pragma once 179c310685SBorawski.Lukasz 18b49ac873SJames Feist #include "health.hpp" 199c310685SBorawski.Lukasz #include "node.hpp" 20c5d03ff4SJennifer Lee #include "redfish_util.hpp" 219c310685SBorawski.Lukasz 225b4aa86bSJames Feist #include <boost/algorithm/string/replace.hpp> 23af5d6058SSantosh Puranik #include <boost/date_time.hpp> 245b4aa86bSJames Feist #include <dbus_utility.hpp> 2573df0db0SJames Feist #include <memory> 26af5d6058SSantosh Puranik #include <sstream> 27e90c5052SAndrew Geissler #include <utils/fw_utils.hpp> 287bffdb7eSBernard Wong #include <utils/systemd_utils.hpp> 29abf2add6SEd Tanous #include <variant> 305b4aa86bSJames Feist 311abe55efSEd Tanous namespace redfish 321abe55efSEd Tanous { 33ed5befbdSJennifer Lee 34ed5befbdSJennifer Lee /** 35*2a5c4407SGunnar Mills * Function reboots the BMC. 36*2a5c4407SGunnar Mills * 37*2a5c4407SGunnar Mills * @param[in] asyncResp - Shared pointer for completing asynchronous calls 38ed5befbdSJennifer Lee */ 39*2a5c4407SGunnar Mills void doBMCGracefulRestart(std::shared_ptr<AsyncResp> asyncResp) 40ed5befbdSJennifer Lee { 41ed5befbdSJennifer Lee const char* processName = "xyz.openbmc_project.State.BMC"; 42ed5befbdSJennifer Lee const char* objectPath = "/xyz/openbmc_project/state/bmc0"; 43ed5befbdSJennifer Lee const char* interfaceName = "xyz.openbmc_project.State.BMC"; 44ed5befbdSJennifer Lee const std::string& propertyValue = 45ed5befbdSJennifer Lee "xyz.openbmc_project.State.BMC.Transition.Reboot"; 46ed5befbdSJennifer Lee const char* destProperty = "RequestedBMCTransition"; 47ed5befbdSJennifer Lee 48ed5befbdSJennifer Lee // Create the D-Bus variant for D-Bus call. 49ed5befbdSJennifer Lee VariantType dbusPropertyValue(propertyValue); 50ed5befbdSJennifer Lee 51ed5befbdSJennifer Lee crow::connections::systemBus->async_method_call( 52ed5befbdSJennifer Lee [asyncResp](const boost::system::error_code ec) { 53ed5befbdSJennifer Lee // Use "Set" method to set the property value. 54ed5befbdSJennifer Lee if (ec) 55ed5befbdSJennifer Lee { 56*2a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "[Set] Bad D-Bus request error: " << ec; 57ed5befbdSJennifer Lee messages::internalError(asyncResp->res); 58ed5befbdSJennifer Lee return; 59ed5befbdSJennifer Lee } 60ed5befbdSJennifer Lee 61ed5befbdSJennifer Lee messages::success(asyncResp->res); 62ed5befbdSJennifer Lee }, 63ed5befbdSJennifer Lee processName, objectPath, "org.freedesktop.DBus.Properties", "Set", 64ed5befbdSJennifer Lee interfaceName, destProperty, dbusPropertyValue); 65ed5befbdSJennifer Lee } 66*2a5c4407SGunnar Mills 67*2a5c4407SGunnar Mills /** 68*2a5c4407SGunnar Mills * ManagerResetAction class supports the POST method for the Reset (reboot) 69*2a5c4407SGunnar Mills * action. 70*2a5c4407SGunnar Mills */ 71*2a5c4407SGunnar Mills class ManagerResetAction : public Node 72*2a5c4407SGunnar Mills { 73*2a5c4407SGunnar Mills public: 74*2a5c4407SGunnar Mills ManagerResetAction(CrowApp& app) : 75*2a5c4407SGunnar Mills Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/") 76*2a5c4407SGunnar Mills { 77*2a5c4407SGunnar Mills entityPrivileges = { 78*2a5c4407SGunnar Mills {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 79*2a5c4407SGunnar Mills } 80*2a5c4407SGunnar Mills 81*2a5c4407SGunnar Mills private: 82*2a5c4407SGunnar Mills /** 83*2a5c4407SGunnar Mills * Function handles POST method request. 84*2a5c4407SGunnar Mills * Analyzes POST body before sending Reset (Reboot) request data to D-Bus. 85*2a5c4407SGunnar Mills * OpenBMC only supports ResetType "GracefulRestart". 86*2a5c4407SGunnar Mills */ 87*2a5c4407SGunnar Mills void doPost(crow::Response& res, const crow::Request& req, 88*2a5c4407SGunnar Mills const std::vector<std::string>& params) override 89*2a5c4407SGunnar Mills { 90*2a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Post Manager Reset."; 91*2a5c4407SGunnar Mills 92*2a5c4407SGunnar Mills std::string resetType; 93*2a5c4407SGunnar Mills auto asyncResp = std::make_shared<AsyncResp>(res); 94*2a5c4407SGunnar Mills 95*2a5c4407SGunnar Mills if (!json_util::readJson(req, asyncResp->res, "ResetType", resetType)) 96*2a5c4407SGunnar Mills { 97*2a5c4407SGunnar Mills return; 98*2a5c4407SGunnar Mills } 99*2a5c4407SGunnar Mills 100*2a5c4407SGunnar Mills if (resetType != "GracefulRestart") 101*2a5c4407SGunnar Mills { 102*2a5c4407SGunnar Mills BMCWEB_LOG_DEBUG << "Invalid property value for ResetType: " 103*2a5c4407SGunnar Mills << resetType; 104*2a5c4407SGunnar Mills messages::actionParameterNotSupported(asyncResp->res, resetType, 105*2a5c4407SGunnar Mills "ResetType"); 106*2a5c4407SGunnar Mills 107*2a5c4407SGunnar Mills return; 108*2a5c4407SGunnar Mills } 109*2a5c4407SGunnar Mills doBMCGracefulRestart(asyncResp); 110*2a5c4407SGunnar Mills } 111ed5befbdSJennifer Lee }; 112ed5befbdSJennifer Lee 1135b4aa86bSJames Feist static constexpr const char* objectManagerIface = 1145b4aa86bSJames Feist "org.freedesktop.DBus.ObjectManager"; 1155b4aa86bSJames Feist static constexpr const char* pidConfigurationIface = 1165b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid"; 1175b4aa86bSJames Feist static constexpr const char* pidZoneConfigurationIface = 1185b4aa86bSJames Feist "xyz.openbmc_project.Configuration.Pid.Zone"; 119b7a08d04SJames Feist static constexpr const char* stepwiseConfigurationIface = 120b7a08d04SJames Feist "xyz.openbmc_project.Configuration.Stepwise"; 12173df0db0SJames Feist static constexpr const char* thermalModeIface = 12273df0db0SJames Feist "xyz.openbmc_project.Control.ThermalMode"; 1239c310685SBorawski.Lukasz 1245b4aa86bSJames Feist static void asyncPopulatePid(const std::string& connection, 1255b4aa86bSJames Feist const std::string& path, 12673df0db0SJames Feist const std::string& currentProfile, 12773df0db0SJames Feist const std::vector<std::string>& supportedProfiles, 1285b4aa86bSJames Feist std::shared_ptr<AsyncResp> asyncResp) 1295b4aa86bSJames Feist { 1305b4aa86bSJames Feist 1315b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 13273df0db0SJames Feist [asyncResp, currentProfile, supportedProfiles]( 13373df0db0SJames Feist const boost::system::error_code ec, 1345b4aa86bSJames Feist const dbus::utility::ManagedObjectType& managedObj) { 1355b4aa86bSJames Feist if (ec) 1365b4aa86bSJames Feist { 1375b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 1385b4aa86bSJames Feist asyncResp->res.jsonValue.clear(); 139f12894f8SJason M. Bills messages::internalError(asyncResp->res); 1405b4aa86bSJames Feist return; 1415b4aa86bSJames Feist } 1425b4aa86bSJames Feist nlohmann::json& configRoot = 1435b4aa86bSJames Feist asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; 1445b4aa86bSJames Feist nlohmann::json& fans = configRoot["FanControllers"]; 1455b4aa86bSJames Feist fans["@odata.type"] = "#OemManager.FanControllers"; 1465b4aa86bSJames Feist fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" 1475b4aa86bSJames Feist "Fan/FanControllers"; 1485b4aa86bSJames Feist 1495b4aa86bSJames Feist nlohmann::json& pids = configRoot["PidControllers"]; 1505b4aa86bSJames Feist pids["@odata.type"] = "#OemManager.PidControllers"; 1515b4aa86bSJames Feist pids["@odata.id"] = 1525b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; 1535b4aa86bSJames Feist 154b7a08d04SJames Feist nlohmann::json& stepwise = configRoot["StepwiseControllers"]; 155b7a08d04SJames Feist stepwise["@odata.type"] = "#OemManager.StepwiseControllers"; 156b7a08d04SJames Feist stepwise["@odata.id"] = 157b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers"; 158b7a08d04SJames Feist 1595b4aa86bSJames Feist nlohmann::json& zones = configRoot["FanZones"]; 1605b4aa86bSJames Feist zones["@odata.id"] = 1615b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; 1625b4aa86bSJames Feist zones["@odata.type"] = "#OemManager.FanZones"; 1635b4aa86bSJames Feist configRoot["@odata.id"] = 1645b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; 1655b4aa86bSJames Feist configRoot["@odata.type"] = "#OemManager.Fan"; 16673df0db0SJames Feist configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles; 16773df0db0SJames Feist 16873df0db0SJames Feist if (!currentProfile.empty()) 16973df0db0SJames Feist { 17073df0db0SJames Feist configRoot["Profile"] = currentProfile; 17173df0db0SJames Feist } 17273df0db0SJames Feist BMCWEB_LOG_ERROR << "profile = " << currentProfile << " !"; 1735b4aa86bSJames Feist 1745b4aa86bSJames Feist for (const auto& pathPair : managedObj) 1755b4aa86bSJames Feist { 1765b4aa86bSJames Feist for (const auto& intfPair : pathPair.second) 1775b4aa86bSJames Feist { 1785b4aa86bSJames Feist if (intfPair.first != pidConfigurationIface && 179b7a08d04SJames Feist intfPair.first != pidZoneConfigurationIface && 180b7a08d04SJames Feist intfPair.first != stepwiseConfigurationIface) 1815b4aa86bSJames Feist { 1825b4aa86bSJames Feist continue; 1835b4aa86bSJames Feist } 1845b4aa86bSJames Feist auto findName = intfPair.second.find("Name"); 1855b4aa86bSJames Feist if (findName == intfPair.second.end()) 1865b4aa86bSJames Feist { 1875b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Field missing Name"; 188a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 1895b4aa86bSJames Feist return; 1905b4aa86bSJames Feist } 19173df0db0SJames Feist 1925b4aa86bSJames Feist const std::string* namePtr = 193abf2add6SEd Tanous std::get_if<std::string>(&findName->second); 1945b4aa86bSJames Feist if (namePtr == nullptr) 1955b4aa86bSJames Feist { 1965b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Name Field illegal"; 197b7a08d04SJames Feist messages::internalError(asyncResp->res); 1985b4aa86bSJames Feist return; 1995b4aa86bSJames Feist } 2005b4aa86bSJames Feist std::string name = *namePtr; 2015b4aa86bSJames Feist dbus::utility::escapePathForDbus(name); 20273df0db0SJames Feist 20373df0db0SJames Feist auto findProfiles = intfPair.second.find("Profiles"); 20473df0db0SJames Feist if (findProfiles != intfPair.second.end()) 20573df0db0SJames Feist { 20673df0db0SJames Feist const std::vector<std::string>* profiles = 20773df0db0SJames Feist std::get_if<std::vector<std::string>>( 20873df0db0SJames Feist &findProfiles->second); 20973df0db0SJames Feist if (profiles == nullptr) 21073df0db0SJames Feist { 21173df0db0SJames Feist BMCWEB_LOG_ERROR << "Pid Profiles Field illegal"; 21273df0db0SJames Feist messages::internalError(asyncResp->res); 21373df0db0SJames Feist return; 21473df0db0SJames Feist } 21573df0db0SJames Feist if (std::find(profiles->begin(), profiles->end(), 21673df0db0SJames Feist currentProfile) == profiles->end()) 21773df0db0SJames Feist { 21873df0db0SJames Feist BMCWEB_LOG_INFO 21973df0db0SJames Feist << name << " not supported in current profile"; 22073df0db0SJames Feist continue; 22173df0db0SJames Feist } 22273df0db0SJames Feist } 223b7a08d04SJames Feist nlohmann::json* config = nullptr; 224c33a90ecSJames Feist 225c33a90ecSJames Feist const std::string* classPtr = nullptr; 226c33a90ecSJames Feist auto findClass = intfPair.second.find("Class"); 227c33a90ecSJames Feist if (findClass != intfPair.second.end()) 228c33a90ecSJames Feist { 229c33a90ecSJames Feist classPtr = std::get_if<std::string>(&findClass->second); 230c33a90ecSJames Feist } 231c33a90ecSJames Feist 2325b4aa86bSJames Feist if (intfPair.first == pidZoneConfigurationIface) 2335b4aa86bSJames Feist { 2345b4aa86bSJames Feist std::string chassis; 2355b4aa86bSJames Feist if (!dbus::utility::getNthStringFromPath( 2365b4aa86bSJames Feist pathPair.first.str, 5, chassis)) 2375b4aa86bSJames Feist { 2385b4aa86bSJames Feist chassis = "#IllegalValue"; 2395b4aa86bSJames Feist } 2405b4aa86bSJames Feist nlohmann::json& zone = zones[name]; 2415b4aa86bSJames Feist zone["Chassis"] = { 2425b4aa86bSJames Feist {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; 2435b4aa86bSJames Feist zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" 2445b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 2455b4aa86bSJames Feist name; 2465b4aa86bSJames Feist zone["@odata.type"] = "#OemManager.FanZone"; 247b7a08d04SJames Feist config = &zone; 2485b4aa86bSJames Feist } 2495b4aa86bSJames Feist 250b7a08d04SJames Feist else if (intfPair.first == stepwiseConfigurationIface) 2515b4aa86bSJames Feist { 252c33a90ecSJames Feist if (classPtr == nullptr) 253c33a90ecSJames Feist { 254c33a90ecSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 255c33a90ecSJames Feist messages::internalError(asyncResp->res); 256c33a90ecSJames Feist return; 257c33a90ecSJames Feist } 258c33a90ecSJames Feist 259b7a08d04SJames Feist nlohmann::json& controller = stepwise[name]; 260b7a08d04SJames Feist config = &controller; 2615b4aa86bSJames Feist 262b7a08d04SJames Feist controller["@odata.id"] = 263b7a08d04SJames Feist "/redfish/v1/Managers/bmc#/Oem/" 264b7a08d04SJames Feist "OpenBmc/Fan/StepwiseControllers/" + 265271584abSEd Tanous name; 266b7a08d04SJames Feist controller["@odata.type"] = 267b7a08d04SJames Feist "#OemManager.StepwiseController"; 268b7a08d04SJames Feist 269c33a90ecSJames Feist controller["Direction"] = *classPtr; 2705b4aa86bSJames Feist } 2715b4aa86bSJames Feist 2725b4aa86bSJames Feist // pid and fans are off the same configuration 273b7a08d04SJames Feist else if (intfPair.first == pidConfigurationIface) 2745b4aa86bSJames Feist { 275c33a90ecSJames Feist 2765b4aa86bSJames Feist if (classPtr == nullptr) 2775b4aa86bSJames Feist { 2785b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Pid Class Field illegal"; 279a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 2805b4aa86bSJames Feist return; 2815b4aa86bSJames Feist } 2825b4aa86bSJames Feist bool isFan = *classPtr == "fan"; 2835b4aa86bSJames Feist nlohmann::json& element = 2845b4aa86bSJames Feist isFan ? fans[name] : pids[name]; 285b7a08d04SJames Feist config = &element; 2865b4aa86bSJames Feist if (isFan) 2875b4aa86bSJames Feist { 2885b4aa86bSJames Feist element["@odata.id"] = 2895b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 2905b4aa86bSJames Feist "OpenBmc/Fan/FanControllers/" + 291271584abSEd Tanous name; 2925b4aa86bSJames Feist element["@odata.type"] = 2935b4aa86bSJames Feist "#OemManager.FanController"; 2945b4aa86bSJames Feist } 2955b4aa86bSJames Feist else 2965b4aa86bSJames Feist { 2975b4aa86bSJames Feist element["@odata.id"] = 2985b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 2995b4aa86bSJames Feist "OpenBmc/Fan/PidControllers/" + 300271584abSEd Tanous name; 3015b4aa86bSJames Feist element["@odata.type"] = 3025b4aa86bSJames Feist "#OemManager.PidController"; 3035b4aa86bSJames Feist } 304b7a08d04SJames Feist } 305b7a08d04SJames Feist else 306b7a08d04SJames Feist { 307b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Unexpected configuration"; 308b7a08d04SJames Feist messages::internalError(asyncResp->res); 309b7a08d04SJames Feist return; 310b7a08d04SJames Feist } 311b7a08d04SJames Feist 312b7a08d04SJames Feist // used for making maps out of 2 vectors 313b7a08d04SJames Feist const std::vector<double>* keys = nullptr; 314b7a08d04SJames Feist const std::vector<double>* values = nullptr; 315b7a08d04SJames Feist 316b7a08d04SJames Feist for (const auto& propertyPair : intfPair.second) 317b7a08d04SJames Feist { 318b7a08d04SJames Feist if (propertyPair.first == "Type" || 319b7a08d04SJames Feist propertyPair.first == "Class" || 320b7a08d04SJames Feist propertyPair.first == "Name") 321b7a08d04SJames Feist { 322b7a08d04SJames Feist continue; 323b7a08d04SJames Feist } 324b7a08d04SJames Feist 325b7a08d04SJames Feist // zones 326b7a08d04SJames Feist if (intfPair.first == pidZoneConfigurationIface) 327b7a08d04SJames Feist { 328b7a08d04SJames Feist const double* ptr = 329abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 330b7a08d04SJames Feist if (ptr == nullptr) 331b7a08d04SJames Feist { 332b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 333b7a08d04SJames Feist << propertyPair.first; 334b7a08d04SJames Feist messages::internalError(asyncResp->res); 335b7a08d04SJames Feist return; 336b7a08d04SJames Feist } 337b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 338b7a08d04SJames Feist } 339b7a08d04SJames Feist 340b7a08d04SJames Feist if (intfPair.first == stepwiseConfigurationIface) 341b7a08d04SJames Feist { 342b7a08d04SJames Feist if (propertyPair.first == "Reading" || 343b7a08d04SJames Feist propertyPair.first == "Output") 344b7a08d04SJames Feist { 345b7a08d04SJames Feist const std::vector<double>* ptr = 346abf2add6SEd Tanous std::get_if<std::vector<double>>( 347b7a08d04SJames Feist &propertyPair.second); 348b7a08d04SJames Feist 349b7a08d04SJames Feist if (ptr == nullptr) 350b7a08d04SJames Feist { 351b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 352b7a08d04SJames Feist << propertyPair.first; 353b7a08d04SJames Feist messages::internalError(asyncResp->res); 354b7a08d04SJames Feist return; 355b7a08d04SJames Feist } 356b7a08d04SJames Feist 357b7a08d04SJames Feist if (propertyPair.first == "Reading") 358b7a08d04SJames Feist { 359b7a08d04SJames Feist keys = ptr; 360b7a08d04SJames Feist } 361b7a08d04SJames Feist else 362b7a08d04SJames Feist { 363b7a08d04SJames Feist values = ptr; 364b7a08d04SJames Feist } 365b7a08d04SJames Feist if (keys && values) 366b7a08d04SJames Feist { 367b7a08d04SJames Feist if (keys->size() != values->size()) 368b7a08d04SJames Feist { 369b7a08d04SJames Feist BMCWEB_LOG_ERROR 370b7a08d04SJames Feist << "Reading and Output size don't " 371b7a08d04SJames Feist "match "; 372b7a08d04SJames Feist messages::internalError(asyncResp->res); 373b7a08d04SJames Feist return; 374b7a08d04SJames Feist } 375b7a08d04SJames Feist nlohmann::json& steps = (*config)["Steps"]; 376b7a08d04SJames Feist steps = nlohmann::json::array(); 377b7a08d04SJames Feist for (size_t ii = 0; ii < keys->size(); ii++) 378b7a08d04SJames Feist { 379b7a08d04SJames Feist steps.push_back( 380b7a08d04SJames Feist {{"Target", (*keys)[ii]}, 381b7a08d04SJames Feist {"Output", (*values)[ii]}}); 382b7a08d04SJames Feist } 383b7a08d04SJames Feist } 384b7a08d04SJames Feist } 385b7a08d04SJames Feist if (propertyPair.first == "NegativeHysteresis" || 386b7a08d04SJames Feist propertyPair.first == "PositiveHysteresis") 387b7a08d04SJames Feist { 388b7a08d04SJames Feist const double* ptr = 389abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 390b7a08d04SJames Feist if (ptr == nullptr) 391b7a08d04SJames Feist { 392b7a08d04SJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 393b7a08d04SJames Feist << propertyPair.first; 394b7a08d04SJames Feist messages::internalError(asyncResp->res); 395b7a08d04SJames Feist return; 396b7a08d04SJames Feist } 397b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 398b7a08d04SJames Feist } 399b7a08d04SJames Feist } 400b7a08d04SJames Feist 401b7a08d04SJames Feist // pid and fans are off the same configuration 402b7a08d04SJames Feist if (intfPair.first == pidConfigurationIface || 403b7a08d04SJames Feist intfPair.first == stepwiseConfigurationIface) 404b7a08d04SJames Feist { 4055b4aa86bSJames Feist 4065b4aa86bSJames Feist if (propertyPair.first == "Zones") 4075b4aa86bSJames Feist { 4085b4aa86bSJames Feist const std::vector<std::string>* inputs = 409abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 4101b6b96c5SEd Tanous &propertyPair.second); 4115b4aa86bSJames Feist 4125b4aa86bSJames Feist if (inputs == nullptr) 4135b4aa86bSJames Feist { 4145b4aa86bSJames Feist BMCWEB_LOG_ERROR 4155b4aa86bSJames Feist << "Zones Pid Field Illegal"; 416a08b46ccSJason M. Bills messages::internalError(asyncResp->res); 4175b4aa86bSJames Feist return; 4185b4aa86bSJames Feist } 419b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 4205b4aa86bSJames Feist data = nlohmann::json::array(); 4215b4aa86bSJames Feist for (std::string itemCopy : *inputs) 4225b4aa86bSJames Feist { 4235b4aa86bSJames Feist dbus::utility::escapePathForDbus(itemCopy); 4245b4aa86bSJames Feist data.push_back( 4255b4aa86bSJames Feist {{"@odata.id", 4265b4aa86bSJames Feist "/redfish/v1/Managers/bmc#/Oem/" 4275b4aa86bSJames Feist "OpenBmc/Fan/FanZones/" + 4285b4aa86bSJames Feist itemCopy}}); 4295b4aa86bSJames Feist } 4305b4aa86bSJames Feist } 4315b4aa86bSJames Feist // todo(james): may never happen, but this 4325b4aa86bSJames Feist // assumes configuration data referenced in the 4335b4aa86bSJames Feist // PID config is provided by the same daemon, we 4345b4aa86bSJames Feist // could add another loop to cover all cases, 4355b4aa86bSJames Feist // but I'm okay kicking this can down the road a 4365b4aa86bSJames Feist // bit 4375b4aa86bSJames Feist 4385b4aa86bSJames Feist else if (propertyPair.first == "Inputs" || 4395b4aa86bSJames Feist propertyPair.first == "Outputs") 4405b4aa86bSJames Feist { 441b7a08d04SJames Feist auto& data = (*config)[propertyPair.first]; 4425b4aa86bSJames Feist const std::vector<std::string>* inputs = 443abf2add6SEd Tanous std::get_if<std::vector<std::string>>( 4441b6b96c5SEd Tanous &propertyPair.second); 4455b4aa86bSJames Feist 4465b4aa86bSJames Feist if (inputs == nullptr) 4475b4aa86bSJames Feist { 4485b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 4495b4aa86bSJames Feist << propertyPair.first; 450f12894f8SJason M. Bills messages::internalError(asyncResp->res); 4515b4aa86bSJames Feist return; 4525b4aa86bSJames Feist } 4535b4aa86bSJames Feist data = *inputs; 454b943aaefSJames Feist } 455b943aaefSJames Feist else if (propertyPair.first == "SetPointOffset") 456b943aaefSJames Feist { 457b943aaefSJames Feist const std::string* ptr = 458b943aaefSJames Feist std::get_if<std::string>( 459b943aaefSJames Feist &propertyPair.second); 460b943aaefSJames Feist 461b943aaefSJames Feist if (ptr == nullptr) 462b943aaefSJames Feist { 463b943aaefSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 464b943aaefSJames Feist << propertyPair.first; 465b943aaefSJames Feist messages::internalError(asyncResp->res); 466b943aaefSJames Feist return; 467b943aaefSJames Feist } 468b943aaefSJames Feist // translate from dbus to redfish 469b943aaefSJames Feist if (*ptr == "WarningHigh") 470b943aaefSJames Feist { 471b943aaefSJames Feist (*config)["SetPointOffset"] = 472b943aaefSJames Feist "UpperThresholdNonCritical"; 473b943aaefSJames Feist } 474b943aaefSJames Feist else if (*ptr == "WarningLow") 475b943aaefSJames Feist { 476b943aaefSJames Feist (*config)["SetPointOffset"] = 477b943aaefSJames Feist "LowerThresholdNonCritical"; 478b943aaefSJames Feist } 479b943aaefSJames Feist else if (*ptr == "CriticalHigh") 480b943aaefSJames Feist { 481b943aaefSJames Feist (*config)["SetPointOffset"] = 482b943aaefSJames Feist "UpperThresholdCritical"; 483b943aaefSJames Feist } 484b943aaefSJames Feist else if (*ptr == "CriticalLow") 485b943aaefSJames Feist { 486b943aaefSJames Feist (*config)["SetPointOffset"] = 487b943aaefSJames Feist "LowerThresholdCritical"; 488b943aaefSJames Feist } 489b943aaefSJames Feist else 490b943aaefSJames Feist { 491b943aaefSJames Feist BMCWEB_LOG_ERROR << "Value Illegal " 492b943aaefSJames Feist << *ptr; 493b943aaefSJames Feist messages::internalError(asyncResp->res); 494b943aaefSJames Feist return; 495b943aaefSJames Feist } 496b943aaefSJames Feist } 497b943aaefSJames Feist // doubles 4985b4aa86bSJames Feist else if (propertyPair.first == 4995b4aa86bSJames Feist "FFGainCoefficient" || 5005b4aa86bSJames Feist propertyPair.first == "FFOffCoefficient" || 5015b4aa86bSJames Feist propertyPair.first == "ICoefficient" || 5025b4aa86bSJames Feist propertyPair.first == "ILimitMax" || 5035b4aa86bSJames Feist propertyPair.first == "ILimitMin" || 504aad1a257SJames Feist propertyPair.first == 505aad1a257SJames Feist "PositiveHysteresis" || 506aad1a257SJames Feist propertyPair.first == 507aad1a257SJames Feist "NegativeHysteresis" || 5085b4aa86bSJames Feist propertyPair.first == "OutLimitMax" || 5095b4aa86bSJames Feist propertyPair.first == "OutLimitMin" || 5105b4aa86bSJames Feist propertyPair.first == "PCoefficient" || 5117625cb81SJames Feist propertyPair.first == "SetPoint" || 5125b4aa86bSJames Feist propertyPair.first == "SlewNeg" || 5135b4aa86bSJames Feist propertyPair.first == "SlewPos") 5145b4aa86bSJames Feist { 5155b4aa86bSJames Feist const double* ptr = 516abf2add6SEd Tanous std::get_if<double>(&propertyPair.second); 5175b4aa86bSJames Feist if (ptr == nullptr) 5185b4aa86bSJames Feist { 5195b4aa86bSJames Feist BMCWEB_LOG_ERROR << "Field Illegal " 5205b4aa86bSJames Feist << propertyPair.first; 521f12894f8SJason M. Bills messages::internalError(asyncResp->res); 5225b4aa86bSJames Feist return; 5235b4aa86bSJames Feist } 524b7a08d04SJames Feist (*config)[propertyPair.first] = *ptr; 5255b4aa86bSJames Feist } 5265b4aa86bSJames Feist } 5275b4aa86bSJames Feist } 5285b4aa86bSJames Feist } 5295b4aa86bSJames Feist } 5305b4aa86bSJames Feist }, 5315b4aa86bSJames Feist connection, path, objectManagerIface, "GetManagedObjects"); 5325b4aa86bSJames Feist } 533ca537928SJennifer Lee 53483ff9ab6SJames Feist enum class CreatePIDRet 53583ff9ab6SJames Feist { 53683ff9ab6SJames Feist fail, 53783ff9ab6SJames Feist del, 53883ff9ab6SJames Feist patch 53983ff9ab6SJames Feist }; 54083ff9ab6SJames Feist 5415f2caaefSJames Feist static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response, 5425f2caaefSJames Feist std::vector<nlohmann::json>& config, 5435f2caaefSJames Feist std::vector<std::string>& zones) 5445f2caaefSJames Feist { 545b6baeaa4SJames Feist if (config.empty()) 546b6baeaa4SJames Feist { 547b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Empty Zones"; 548b6baeaa4SJames Feist messages::propertyValueFormatError(response->res, 549b6baeaa4SJames Feist nlohmann::json::array(), "Zones"); 550b6baeaa4SJames Feist return false; 551b6baeaa4SJames Feist } 5525f2caaefSJames Feist for (auto& odata : config) 5535f2caaefSJames Feist { 5545f2caaefSJames Feist std::string path; 5555f2caaefSJames Feist if (!redfish::json_util::readJson(odata, response->res, "@odata.id", 5565f2caaefSJames Feist path)) 5575f2caaefSJames Feist { 5585f2caaefSJames Feist return false; 5595f2caaefSJames Feist } 5605f2caaefSJames Feist std::string input; 56161adbda3SJames Feist 56261adbda3SJames Feist // 8 below comes from 56361adbda3SJames Feist // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left 56461adbda3SJames Feist // 0 1 2 3 4 5 6 7 8 56561adbda3SJames Feist if (!dbus::utility::getNthStringFromPath(path, 8, input)) 5665f2caaefSJames Feist { 5675f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << path; 5685f2caaefSJames Feist BMCWEB_LOG_ERROR << "Illegal Type Zones"; 5695f2caaefSJames Feist messages::propertyValueFormatError(response->res, odata.dump(), 5705f2caaefSJames Feist "Zones"); 5715f2caaefSJames Feist return false; 5725f2caaefSJames Feist } 5735f2caaefSJames Feist boost::replace_all(input, "_", " "); 5745f2caaefSJames Feist zones.emplace_back(std::move(input)); 5755f2caaefSJames Feist } 5765f2caaefSJames Feist return true; 5775f2caaefSJames Feist } 5785f2caaefSJames Feist 57973df0db0SJames Feist static const dbus::utility::ManagedItem* 58073df0db0SJames Feist findChassis(const dbus::utility::ManagedObjectType& managedObj, 581b6baeaa4SJames Feist const std::string& value, std::string& chassis) 582b6baeaa4SJames Feist { 583b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n"; 584b6baeaa4SJames Feist 585b6baeaa4SJames Feist std::string escaped = boost::replace_all_copy(value, " ", "_"); 586b6baeaa4SJames Feist escaped = "/" + escaped; 587b6baeaa4SJames Feist auto it = std::find_if( 588b6baeaa4SJames Feist managedObj.begin(), managedObj.end(), [&escaped](const auto& obj) { 589b6baeaa4SJames Feist if (boost::algorithm::ends_with(obj.first.str, escaped)) 590b6baeaa4SJames Feist { 591b6baeaa4SJames Feist BMCWEB_LOG_DEBUG << "Matched " << obj.first.str << "\n"; 592b6baeaa4SJames Feist return true; 593b6baeaa4SJames Feist } 594b6baeaa4SJames Feist return false; 595b6baeaa4SJames Feist }); 596b6baeaa4SJames Feist 597b6baeaa4SJames Feist if (it == managedObj.end()) 598b6baeaa4SJames Feist { 59973df0db0SJames Feist return nullptr; 600b6baeaa4SJames Feist } 601b6baeaa4SJames Feist // 5 comes from <chassis-name> being the 5th element 602b6baeaa4SJames Feist // /xyz/openbmc_project/inventory/system/chassis/<chassis-name> 60373df0db0SJames Feist if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis)) 60473df0db0SJames Feist { 60573df0db0SJames Feist return &(*it); 60673df0db0SJames Feist } 60773df0db0SJames Feist 60873df0db0SJames Feist return nullptr; 609b6baeaa4SJames Feist } 610b6baeaa4SJames Feist 61183ff9ab6SJames Feist static CreatePIDRet createPidInterface( 61283ff9ab6SJames Feist const std::shared_ptr<AsyncResp>& response, const std::string& type, 613b6baeaa4SJames Feist nlohmann::json::iterator it, const std::string& path, 61483ff9ab6SJames Feist const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, 61583ff9ab6SJames Feist boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& 61683ff9ab6SJames Feist output, 61773df0db0SJames Feist std::string& chassis, const std::string& profile) 61883ff9ab6SJames Feist { 61983ff9ab6SJames Feist 6205f2caaefSJames Feist // common deleter 621b6baeaa4SJames Feist if (it.value() == nullptr) 6225f2caaefSJames Feist { 6235f2caaefSJames Feist std::string iface; 6245f2caaefSJames Feist if (type == "PidControllers" || type == "FanControllers") 6255f2caaefSJames Feist { 6265f2caaefSJames Feist iface = pidConfigurationIface; 6275f2caaefSJames Feist } 6285f2caaefSJames Feist else if (type == "FanZones") 6295f2caaefSJames Feist { 6305f2caaefSJames Feist iface = pidZoneConfigurationIface; 6315f2caaefSJames Feist } 6325f2caaefSJames Feist else if (type == "StepwiseControllers") 6335f2caaefSJames Feist { 6345f2caaefSJames Feist iface = stepwiseConfigurationIface; 6355f2caaefSJames Feist } 6365f2caaefSJames Feist else 6375f2caaefSJames Feist { 6385f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " 6395f2caaefSJames Feist << type; 6405f2caaefSJames Feist messages::propertyUnknown(response->res, type); 6415f2caaefSJames Feist return CreatePIDRet::fail; 6425f2caaefSJames Feist } 6436ee7f774SJames Feist 6446ee7f774SJames Feist BMCWEB_LOG_DEBUG << "del " << path << " " << iface << "\n"; 6455f2caaefSJames Feist // delete interface 6465f2caaefSJames Feist crow::connections::systemBus->async_method_call( 6475f2caaefSJames Feist [response, path](const boost::system::error_code ec) { 6485f2caaefSJames Feist if (ec) 6495f2caaefSJames Feist { 6505f2caaefSJames Feist BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec; 6515f2caaefSJames Feist messages::internalError(response->res); 652b6baeaa4SJames Feist return; 6535f2caaefSJames Feist } 654b6baeaa4SJames Feist messages::success(response->res); 6555f2caaefSJames Feist }, 6565f2caaefSJames Feist "xyz.openbmc_project.EntityManager", path, iface, "Delete"); 6575f2caaefSJames Feist return CreatePIDRet::del; 6585f2caaefSJames Feist } 6595f2caaefSJames Feist 66073df0db0SJames Feist const dbus::utility::ManagedItem* managedItem = nullptr; 661b6baeaa4SJames Feist if (!createNewObject) 662b6baeaa4SJames Feist { 663b6baeaa4SJames Feist // if we aren't creating a new object, we should be able to find it on 664b6baeaa4SJames Feist // d-bus 66573df0db0SJames Feist managedItem = findChassis(managedObj, it.key(), chassis); 66673df0db0SJames Feist if (managedItem == nullptr) 667b6baeaa4SJames Feist { 668b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 669b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 670b6baeaa4SJames Feist return CreatePIDRet::fail; 671b6baeaa4SJames Feist } 672b6baeaa4SJames Feist } 673b6baeaa4SJames Feist 67473df0db0SJames Feist if (profile.size() && 67573df0db0SJames Feist (type == "PidControllers" || type == "FanControllers" || 67673df0db0SJames Feist type == "StepwiseControllers")) 67773df0db0SJames Feist { 67873df0db0SJames Feist if (managedItem == nullptr) 67973df0db0SJames Feist { 68073df0db0SJames Feist output["Profiles"] = std::vector<std::string>{profile}; 68173df0db0SJames Feist } 68273df0db0SJames Feist else 68373df0db0SJames Feist { 68473df0db0SJames Feist std::string interface; 68573df0db0SJames Feist if (type == "StepwiseControllers") 68673df0db0SJames Feist { 68773df0db0SJames Feist interface = stepwiseConfigurationIface; 68873df0db0SJames Feist } 68973df0db0SJames Feist else 69073df0db0SJames Feist { 69173df0db0SJames Feist interface = pidConfigurationIface; 69273df0db0SJames Feist } 69373df0db0SJames Feist auto findConfig = managedItem->second.find(interface); 69473df0db0SJames Feist if (findConfig == managedItem->second.end()) 69573df0db0SJames Feist { 69673df0db0SJames Feist BMCWEB_LOG_ERROR 69773df0db0SJames Feist << "Failed to find interface in managed object"; 69873df0db0SJames Feist messages::internalError(response->res); 69973df0db0SJames Feist return CreatePIDRet::fail; 70073df0db0SJames Feist } 70173df0db0SJames Feist auto findProfiles = findConfig->second.find("Profiles"); 70273df0db0SJames Feist if (findProfiles != findConfig->second.end()) 70373df0db0SJames Feist { 70473df0db0SJames Feist const std::vector<std::string>* curProfiles = 70573df0db0SJames Feist std::get_if<std::vector<std::string>>( 70673df0db0SJames Feist &(findProfiles->second)); 70773df0db0SJames Feist if (curProfiles == nullptr) 70873df0db0SJames Feist { 70973df0db0SJames Feist BMCWEB_LOG_ERROR << "Illegal profiles in managed object"; 71073df0db0SJames Feist messages::internalError(response->res); 71173df0db0SJames Feist return CreatePIDRet::fail; 71273df0db0SJames Feist } 71373df0db0SJames Feist if (std::find(curProfiles->begin(), curProfiles->end(), 71473df0db0SJames Feist profile) == curProfiles->end()) 71573df0db0SJames Feist { 71673df0db0SJames Feist std::vector<std::string> newProfiles = *curProfiles; 71773df0db0SJames Feist newProfiles.push_back(profile); 71873df0db0SJames Feist output["Profiles"] = newProfiles; 71973df0db0SJames Feist } 72073df0db0SJames Feist } 72173df0db0SJames Feist } 72273df0db0SJames Feist } 72373df0db0SJames Feist 72483ff9ab6SJames Feist if (type == "PidControllers" || type == "FanControllers") 72583ff9ab6SJames Feist { 72683ff9ab6SJames Feist if (createNewObject) 72783ff9ab6SJames Feist { 72883ff9ab6SJames Feist output["Class"] = type == "PidControllers" ? std::string("temp") 72983ff9ab6SJames Feist : std::string("fan"); 73083ff9ab6SJames Feist output["Type"] = std::string("Pid"); 73183ff9ab6SJames Feist } 7325f2caaefSJames Feist 7335f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 7345f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 7355f2caaefSJames Feist std::optional<std::vector<std::string>> outputs; 7365f2caaefSJames Feist std::map<std::string, std::optional<double>> doubles; 737b943aaefSJames Feist std::optional<std::string> setpointOffset; 7385f2caaefSJames Feist if (!redfish::json_util::readJson( 739b6baeaa4SJames Feist it.value(), response->res, "Inputs", inputs, "Outputs", outputs, 7405f2caaefSJames Feist "Zones", zones, "FFGainCoefficient", 7415f2caaefSJames Feist doubles["FFGainCoefficient"], "FFOffCoefficient", 7425f2caaefSJames Feist doubles["FFOffCoefficient"], "ICoefficient", 7435f2caaefSJames Feist doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], 7445f2caaefSJames Feist "ILimitMin", doubles["ILimitMin"], "OutLimitMax", 7455f2caaefSJames Feist doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], 7465f2caaefSJames Feist "PCoefficient", doubles["PCoefficient"], "SetPoint", 747b943aaefSJames Feist doubles["SetPoint"], "SetPointOffset", setpointOffset, 748b943aaefSJames Feist "SlewNeg", doubles["SlewNeg"], "SlewPos", doubles["SlewPos"], 749b943aaefSJames Feist "PositiveHysteresis", doubles["PositiveHysteresis"], 750b943aaefSJames Feist "NegativeHysteresis", doubles["NegativeHysteresis"])) 75183ff9ab6SJames Feist { 7525f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 753b6baeaa4SJames Feist << it.value().dump(); 7545f2caaefSJames Feist return CreatePIDRet::fail; 75583ff9ab6SJames Feist } 7565f2caaefSJames Feist if (zones) 7575f2caaefSJames Feist { 7585f2caaefSJames Feist std::vector<std::string> zonesStr; 7595f2caaefSJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStr)) 7605f2caaefSJames Feist { 7615f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 7625f2caaefSJames Feist return CreatePIDRet::fail; 7635f2caaefSJames Feist } 764b6baeaa4SJames Feist if (chassis.empty() && 765b6baeaa4SJames Feist !findChassis(managedObj, zonesStr[0], chassis)) 766b6baeaa4SJames Feist { 767b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 768b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 769b6baeaa4SJames Feist return CreatePIDRet::fail; 770b6baeaa4SJames Feist } 771b6baeaa4SJames Feist 7725f2caaefSJames Feist output["Zones"] = std::move(zonesStr); 7735f2caaefSJames Feist } 7745f2caaefSJames Feist if (inputs || outputs) 7755f2caaefSJames Feist { 7765f2caaefSJames Feist std::array<std::optional<std::vector<std::string>>*, 2> containers = 7775f2caaefSJames Feist {&inputs, &outputs}; 7785f2caaefSJames Feist size_t index = 0; 7795f2caaefSJames Feist for (const auto& containerPtr : containers) 7805f2caaefSJames Feist { 7815f2caaefSJames Feist std::optional<std::vector<std::string>>& container = 7825f2caaefSJames Feist *containerPtr; 7835f2caaefSJames Feist if (!container) 7845f2caaefSJames Feist { 7855f2caaefSJames Feist index++; 7865f2caaefSJames Feist continue; 78783ff9ab6SJames Feist } 78883ff9ab6SJames Feist 7895f2caaefSJames Feist for (std::string& value : *container) 79083ff9ab6SJames Feist { 7915f2caaefSJames Feist boost::replace_all(value, "_", " "); 79283ff9ab6SJames Feist } 7935f2caaefSJames Feist std::string key; 7945f2caaefSJames Feist if (index == 0) 7955f2caaefSJames Feist { 7965f2caaefSJames Feist key = "Inputs"; 7975f2caaefSJames Feist } 7985f2caaefSJames Feist else 7995f2caaefSJames Feist { 8005f2caaefSJames Feist key = "Outputs"; 8015f2caaefSJames Feist } 8025f2caaefSJames Feist output[key] = *container; 8035f2caaefSJames Feist index++; 8045f2caaefSJames Feist } 80583ff9ab6SJames Feist } 80683ff9ab6SJames Feist 807b943aaefSJames Feist if (setpointOffset) 808b943aaefSJames Feist { 809b943aaefSJames Feist // translate between redfish and dbus names 810b943aaefSJames Feist if (*setpointOffset == "UpperThresholdNonCritical") 811b943aaefSJames Feist { 812b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningLow"); 813b943aaefSJames Feist } 814b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdNonCritical") 815b943aaefSJames Feist { 816b943aaefSJames Feist output["SetPointOffset"] = std::string("WarningHigh"); 817b943aaefSJames Feist } 818b943aaefSJames Feist else if (*setpointOffset == "LowerThresholdCritical") 819b943aaefSJames Feist { 820b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalLow"); 821b943aaefSJames Feist } 822b943aaefSJames Feist else if (*setpointOffset == "UpperThresholdCritical") 823b943aaefSJames Feist { 824b943aaefSJames Feist output["SetPointOffset"] = std::string("CriticalHigh"); 825b943aaefSJames Feist } 826b943aaefSJames Feist else 827b943aaefSJames Feist { 828b943aaefSJames Feist BMCWEB_LOG_ERROR << "Invalid setpointoffset " 829b943aaefSJames Feist << *setpointOffset; 830b943aaefSJames Feist messages::invalidObject(response->res, it.key()); 831b943aaefSJames Feist return CreatePIDRet::fail; 832b943aaefSJames Feist } 833b943aaefSJames Feist } 834b943aaefSJames Feist 83583ff9ab6SJames Feist // doubles 8365f2caaefSJames Feist for (const auto& pairs : doubles) 83783ff9ab6SJames Feist { 8385f2caaefSJames Feist if (!pairs.second) 83983ff9ab6SJames Feist { 8405f2caaefSJames Feist continue; 84183ff9ab6SJames Feist } 8425f2caaefSJames Feist BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second; 8435f2caaefSJames Feist output[pairs.first] = *(pairs.second); 8445f2caaefSJames Feist } 84583ff9ab6SJames Feist } 84683ff9ab6SJames Feist 84783ff9ab6SJames Feist else if (type == "FanZones") 84883ff9ab6SJames Feist { 84983ff9ab6SJames Feist output["Type"] = std::string("Pid.Zone"); 85083ff9ab6SJames Feist 8515f2caaefSJames Feist std::optional<nlohmann::json> chassisContainer; 8525f2caaefSJames Feist std::optional<double> failSafePercent; 853d3ec07f8SJames Feist std::optional<double> minThermalOutput; 854b6baeaa4SJames Feist if (!redfish::json_util::readJson(it.value(), response->res, "Chassis", 8555f2caaefSJames Feist chassisContainer, "FailSafePercent", 856d3ec07f8SJames Feist failSafePercent, "MinThermalOutput", 857d3ec07f8SJames Feist minThermalOutput)) 85883ff9ab6SJames Feist { 8595f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 860b6baeaa4SJames Feist << it.value().dump(); 86183ff9ab6SJames Feist return CreatePIDRet::fail; 86283ff9ab6SJames Feist } 8635f2caaefSJames Feist 8645f2caaefSJames Feist if (chassisContainer) 86583ff9ab6SJames Feist { 8665f2caaefSJames Feist 8675f2caaefSJames Feist std::string chassisId; 8685f2caaefSJames Feist if (!redfish::json_util::readJson(*chassisContainer, response->res, 8695f2caaefSJames Feist "@odata.id", chassisId)) 8705f2caaefSJames Feist { 8715f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 8725f2caaefSJames Feist << chassisContainer->dump(); 87383ff9ab6SJames Feist return CreatePIDRet::fail; 87483ff9ab6SJames Feist } 87583ff9ab6SJames Feist 876717794d5SAppaRao Puli // /redfish/v1/chassis/chassis_name/ 8775f2caaefSJames Feist if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis)) 87883ff9ab6SJames Feist { 8795f2caaefSJames Feist BMCWEB_LOG_ERROR << "Got invalid path " << chassisId; 8805f2caaefSJames Feist messages::invalidObject(response->res, chassisId); 88183ff9ab6SJames Feist return CreatePIDRet::fail; 88283ff9ab6SJames Feist } 88383ff9ab6SJames Feist } 884d3ec07f8SJames Feist if (minThermalOutput) 88583ff9ab6SJames Feist { 886d3ec07f8SJames Feist output["MinThermalOutput"] = *minThermalOutput; 8875f2caaefSJames Feist } 8885f2caaefSJames Feist if (failSafePercent) 88983ff9ab6SJames Feist { 8905f2caaefSJames Feist output["FailSafePercent"] = *failSafePercent; 8915f2caaefSJames Feist } 8925f2caaefSJames Feist } 8935f2caaefSJames Feist else if (type == "StepwiseControllers") 8945f2caaefSJames Feist { 8955f2caaefSJames Feist output["Type"] = std::string("Stepwise"); 8965f2caaefSJames Feist 8975f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> zones; 8985f2caaefSJames Feist std::optional<std::vector<nlohmann::json>> steps; 8995f2caaefSJames Feist std::optional<std::vector<std::string>> inputs; 9005f2caaefSJames Feist std::optional<double> positiveHysteresis; 9015f2caaefSJames Feist std::optional<double> negativeHysteresis; 902c33a90ecSJames Feist std::optional<std::string> direction; // upper clipping curve vs lower 9035f2caaefSJames Feist if (!redfish::json_util::readJson( 904b6baeaa4SJames Feist it.value(), response->res, "Zones", zones, "Steps", steps, 905b6baeaa4SJames Feist "Inputs", inputs, "PositiveHysteresis", positiveHysteresis, 906c33a90ecSJames Feist "NegativeHysteresis", negativeHysteresis, "Direction", 907c33a90ecSJames Feist direction)) 9085f2caaefSJames Feist { 9095f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 910b6baeaa4SJames Feist << it.value().dump(); 91183ff9ab6SJames Feist return CreatePIDRet::fail; 91283ff9ab6SJames Feist } 9135f2caaefSJames Feist 9145f2caaefSJames Feist if (zones) 91583ff9ab6SJames Feist { 916b6baeaa4SJames Feist std::vector<std::string> zonesStrs; 917b6baeaa4SJames Feist if (!getZonesFromJsonReq(response, *zones, zonesStrs)) 9185f2caaefSJames Feist { 9195f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; 92083ff9ab6SJames Feist return CreatePIDRet::fail; 92183ff9ab6SJames Feist } 922b6baeaa4SJames Feist if (chassis.empty() && 923b6baeaa4SJames Feist !findChassis(managedObj, zonesStrs[0], chassis)) 924b6baeaa4SJames Feist { 925b6baeaa4SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; 926b6baeaa4SJames Feist messages::invalidObject(response->res, it.key()); 927b6baeaa4SJames Feist return CreatePIDRet::fail; 928b6baeaa4SJames Feist } 929b6baeaa4SJames Feist output["Zones"] = std::move(zonesStrs); 9305f2caaefSJames Feist } 9315f2caaefSJames Feist if (steps) 9325f2caaefSJames Feist { 9335f2caaefSJames Feist std::vector<double> readings; 9345f2caaefSJames Feist std::vector<double> outputs; 9355f2caaefSJames Feist for (auto& step : *steps) 9365f2caaefSJames Feist { 9375f2caaefSJames Feist double target; 938b01bf299SEd Tanous double output; 9395f2caaefSJames Feist 9405f2caaefSJames Feist if (!redfish::json_util::readJson(step, response->res, "Target", 941b01bf299SEd Tanous target, "Output", output)) 9425f2caaefSJames Feist { 9435f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 944b6baeaa4SJames Feist << ", Illegal Property " 945b6baeaa4SJames Feist << it.value().dump(); 9465f2caaefSJames Feist return CreatePIDRet::fail; 9475f2caaefSJames Feist } 9485f2caaefSJames Feist readings.emplace_back(target); 949b01bf299SEd Tanous outputs.emplace_back(output); 9505f2caaefSJames Feist } 9515f2caaefSJames Feist output["Reading"] = std::move(readings); 9525f2caaefSJames Feist output["Output"] = std::move(outputs); 9535f2caaefSJames Feist } 9545f2caaefSJames Feist if (inputs) 9555f2caaefSJames Feist { 9565f2caaefSJames Feist for (std::string& value : *inputs) 9575f2caaefSJames Feist { 9585f2caaefSJames Feist boost::replace_all(value, "_", " "); 9595f2caaefSJames Feist } 9605f2caaefSJames Feist output["Inputs"] = std::move(*inputs); 9615f2caaefSJames Feist } 9625f2caaefSJames Feist if (negativeHysteresis) 9635f2caaefSJames Feist { 9645f2caaefSJames Feist output["NegativeHysteresis"] = *negativeHysteresis; 9655f2caaefSJames Feist } 9665f2caaefSJames Feist if (positiveHysteresis) 9675f2caaefSJames Feist { 9685f2caaefSJames Feist output["PositiveHysteresis"] = *positiveHysteresis; 96983ff9ab6SJames Feist } 970c33a90ecSJames Feist if (direction) 971c33a90ecSJames Feist { 972c33a90ecSJames Feist constexpr const std::array<const char*, 2> allowedDirections = { 973c33a90ecSJames Feist "Ceiling", "Floor"}; 974c33a90ecSJames Feist if (std::find(allowedDirections.begin(), allowedDirections.end(), 975c33a90ecSJames Feist *direction) == allowedDirections.end()) 976c33a90ecSJames Feist { 977c33a90ecSJames Feist messages::propertyValueTypeError(response->res, "Direction", 978c33a90ecSJames Feist *direction); 979c33a90ecSJames Feist return CreatePIDRet::fail; 980c33a90ecSJames Feist } 981c33a90ecSJames Feist output["Class"] = *direction; 982c33a90ecSJames Feist } 98383ff9ab6SJames Feist } 98483ff9ab6SJames Feist else 98583ff9ab6SJames Feist { 9865f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type; 98735a62c7cSJason M. Bills messages::propertyUnknown(response->res, type); 98883ff9ab6SJames Feist return CreatePIDRet::fail; 98983ff9ab6SJames Feist } 99083ff9ab6SJames Feist return CreatePIDRet::patch; 99183ff9ab6SJames Feist } 99273df0db0SJames Feist struct GetPIDValues : std::enable_shared_from_this<GetPIDValues> 99373df0db0SJames Feist { 99483ff9ab6SJames Feist 99573df0db0SJames Feist GetPIDValues(const std::shared_ptr<AsyncResp>& asyncResp) : 99673df0db0SJames Feist asyncResp(asyncResp) 99773df0db0SJames Feist 9981abe55efSEd Tanous { 9999c310685SBorawski.Lukasz } 10009c310685SBorawski.Lukasz 100173df0db0SJames Feist void run() 10025b4aa86bSJames Feist { 100373df0db0SJames Feist std::shared_ptr<GetPIDValues> self = shared_from_this(); 100473df0db0SJames Feist 100573df0db0SJames Feist // get all configurations 10065b4aa86bSJames Feist crow::connections::systemBus->async_method_call( 100773df0db0SJames Feist [self](const boost::system::error_code ec, 10085b4aa86bSJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 10095b4aa86bSJames Feist if (ec) 10105b4aa86bSJames Feist { 10115b4aa86bSJames Feist BMCWEB_LOG_ERROR << ec; 101273df0db0SJames Feist messages::internalError(self->asyncResp->res); 101373df0db0SJames Feist return; 101473df0db0SJames Feist } 101573df0db0SJames Feist self->subtree = subtree; 101673df0db0SJames Feist }, 101773df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 101873df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 101973df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 102073df0db0SJames Feist std::array<const char*, 4>{ 102173df0db0SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 102273df0db0SJames Feist objectManagerIface, stepwiseConfigurationIface}); 102373df0db0SJames Feist 102473df0db0SJames Feist // at the same time get the selected profile 102573df0db0SJames Feist crow::connections::systemBus->async_method_call( 102673df0db0SJames Feist [self](const boost::system::error_code ec, 102773df0db0SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 102873df0db0SJames Feist if (ec || subtree.empty()) 102973df0db0SJames Feist { 103073df0db0SJames Feist return; 103173df0db0SJames Feist } 103273df0db0SJames Feist if (subtree[0].second.size() != 1) 103373df0db0SJames Feist { 103473df0db0SJames Feist // invalid mapper response, should never happen 103573df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Mapper Error"; 103673df0db0SJames Feist messages::internalError(self->asyncResp->res); 10375b4aa86bSJames Feist return; 10385b4aa86bSJames Feist } 10395b4aa86bSJames Feist 104073df0db0SJames Feist const std::string& path = subtree[0].first; 104173df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 104273df0db0SJames Feist crow::connections::systemBus->async_method_call( 104373df0db0SJames Feist [path, owner, self]( 104473df0db0SJames Feist const boost::system::error_code ec, 104573df0db0SJames Feist const boost::container::flat_map< 104673df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 104773df0db0SJames Feist std::string>>& resp) { 104873df0db0SJames Feist if (ec) 104973df0db0SJames Feist { 105073df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: Can't get " 105173df0db0SJames Feist "thermalModeIface " 105273df0db0SJames Feist << path; 105373df0db0SJames Feist messages::internalError(self->asyncResp->res); 105473df0db0SJames Feist return; 105573df0db0SJames Feist } 1056271584abSEd Tanous const std::string* current = nullptr; 1057271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 105873df0db0SJames Feist for (auto& [key, value] : resp) 105973df0db0SJames Feist { 106073df0db0SJames Feist if (key == "Current") 106173df0db0SJames Feist { 106273df0db0SJames Feist current = std::get_if<std::string>(&value); 106373df0db0SJames Feist if (current == nullptr) 106473df0db0SJames Feist { 106573df0db0SJames Feist BMCWEB_LOG_ERROR 106673df0db0SJames Feist << "GetPIDValues: thermal mode " 106773df0db0SJames Feist "iface invalid " 106873df0db0SJames Feist << path; 106973df0db0SJames Feist messages::internalError( 107073df0db0SJames Feist self->asyncResp->res); 107173df0db0SJames Feist return; 107273df0db0SJames Feist } 107373df0db0SJames Feist } 107473df0db0SJames Feist if (key == "Supported") 107573df0db0SJames Feist { 107673df0db0SJames Feist supported = 107773df0db0SJames Feist std::get_if<std::vector<std::string>>( 107873df0db0SJames Feist &value); 107973df0db0SJames Feist if (supported == nullptr) 108073df0db0SJames Feist { 108173df0db0SJames Feist BMCWEB_LOG_ERROR 108273df0db0SJames Feist << "GetPIDValues: thermal mode " 108373df0db0SJames Feist "iface invalid" 108473df0db0SJames Feist << path; 108573df0db0SJames Feist messages::internalError( 108673df0db0SJames Feist self->asyncResp->res); 108773df0db0SJames Feist return; 108873df0db0SJames Feist } 108973df0db0SJames Feist } 109073df0db0SJames Feist } 109173df0db0SJames Feist if (current == nullptr || supported == nullptr) 109273df0db0SJames Feist { 109373df0db0SJames Feist BMCWEB_LOG_ERROR << "GetPIDValues: thermal mode " 109473df0db0SJames Feist "iface invalid " 109573df0db0SJames Feist << path; 109673df0db0SJames Feist messages::internalError(self->asyncResp->res); 109773df0db0SJames Feist return; 109873df0db0SJames Feist } 109973df0db0SJames Feist self->currentProfile = *current; 110073df0db0SJames Feist self->supportedProfiles = *supported; 110173df0db0SJames Feist }, 110273df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 110373df0db0SJames Feist thermalModeIface); 110473df0db0SJames Feist }, 110573df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", 110673df0db0SJames Feist "/xyz/openbmc_project/object_mapper", 110773df0db0SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 110873df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 110973df0db0SJames Feist } 111073df0db0SJames Feist 111173df0db0SJames Feist ~GetPIDValues() 111273df0db0SJames Feist { 111373df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 111473df0db0SJames Feist { 111573df0db0SJames Feist return; 111673df0db0SJames Feist } 11175b4aa86bSJames Feist // create map of <connection, path to objMgr>> 111873df0db0SJames Feist boost::container::flat_map<std::string, std::string> objectMgrPaths; 11196bce33bcSJames Feist boost::container::flat_set<std::string> calledConnections; 11205b4aa86bSJames Feist for (const auto& pathGroup : subtree) 11215b4aa86bSJames Feist { 11225b4aa86bSJames Feist for (const auto& connectionGroup : pathGroup.second) 11235b4aa86bSJames Feist { 11246bce33bcSJames Feist auto findConnection = 11256bce33bcSJames Feist calledConnections.find(connectionGroup.first); 11266bce33bcSJames Feist if (findConnection != calledConnections.end()) 11276bce33bcSJames Feist { 11286bce33bcSJames Feist break; 11296bce33bcSJames Feist } 113073df0db0SJames Feist for (const std::string& interface : connectionGroup.second) 11315b4aa86bSJames Feist { 11325b4aa86bSJames Feist if (interface == objectManagerIface) 11335b4aa86bSJames Feist { 113473df0db0SJames Feist objectMgrPaths[connectionGroup.first] = pathGroup.first; 11355b4aa86bSJames Feist } 11365b4aa86bSJames Feist // this list is alphabetical, so we 11375b4aa86bSJames Feist // should have found the objMgr by now 11385b4aa86bSJames Feist if (interface == pidConfigurationIface || 1139b7a08d04SJames Feist interface == pidZoneConfigurationIface || 1140b7a08d04SJames Feist interface == stepwiseConfigurationIface) 11415b4aa86bSJames Feist { 11425b4aa86bSJames Feist auto findObjMgr = 11435b4aa86bSJames Feist objectMgrPaths.find(connectionGroup.first); 11445b4aa86bSJames Feist if (findObjMgr == objectMgrPaths.end()) 11455b4aa86bSJames Feist { 11465b4aa86bSJames Feist BMCWEB_LOG_DEBUG << connectionGroup.first 11475b4aa86bSJames Feist << "Has no Object Manager"; 11485b4aa86bSJames Feist continue; 11495b4aa86bSJames Feist } 11506bce33bcSJames Feist 11516bce33bcSJames Feist calledConnections.insert(connectionGroup.first); 11526bce33bcSJames Feist 115373df0db0SJames Feist asyncPopulatePid(findObjMgr->first, findObjMgr->second, 115473df0db0SJames Feist currentProfile, supportedProfiles, 115573df0db0SJames Feist asyncResp); 11565b4aa86bSJames Feist break; 11575b4aa86bSJames Feist } 11585b4aa86bSJames Feist } 11595b4aa86bSJames Feist } 11605b4aa86bSJames Feist } 116173df0db0SJames Feist } 116273df0db0SJames Feist 116373df0db0SJames Feist std::vector<std::string> supportedProfiles; 116473df0db0SJames Feist std::string currentProfile; 116573df0db0SJames Feist crow::openbmc_mapper::GetSubTreeType subtree; 116673df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 116773df0db0SJames Feist }; 116873df0db0SJames Feist 116973df0db0SJames Feist struct SetPIDValues : std::enable_shared_from_this<SetPIDValues> 117073df0db0SJames Feist { 117173df0db0SJames Feist 1172271584abSEd Tanous SetPIDValues(const std::shared_ptr<AsyncResp>& asyncRespIn, 117373df0db0SJames Feist nlohmann::json& data) : 1174271584abSEd Tanous asyncResp(asyncRespIn) 117573df0db0SJames Feist { 117673df0db0SJames Feist 117773df0db0SJames Feist std::optional<nlohmann::json> pidControllers; 117873df0db0SJames Feist std::optional<nlohmann::json> fanControllers; 117973df0db0SJames Feist std::optional<nlohmann::json> fanZones; 118073df0db0SJames Feist std::optional<nlohmann::json> stepwiseControllers; 118173df0db0SJames Feist 118273df0db0SJames Feist if (!redfish::json_util::readJson( 118373df0db0SJames Feist data, asyncResp->res, "PidControllers", pidControllers, 118473df0db0SJames Feist "FanControllers", fanControllers, "FanZones", fanZones, 118573df0db0SJames Feist "StepwiseControllers", stepwiseControllers, "Profile", profile)) 118673df0db0SJames Feist { 118773df0db0SJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 118873df0db0SJames Feist << data.dump(); 118973df0db0SJames Feist return; 119073df0db0SJames Feist } 119173df0db0SJames Feist configuration.emplace_back("PidControllers", std::move(pidControllers)); 119273df0db0SJames Feist configuration.emplace_back("FanControllers", std::move(fanControllers)); 119373df0db0SJames Feist configuration.emplace_back("FanZones", std::move(fanZones)); 119473df0db0SJames Feist configuration.emplace_back("StepwiseControllers", 119573df0db0SJames Feist std::move(stepwiseControllers)); 119673df0db0SJames Feist } 119773df0db0SJames Feist void run() 119873df0db0SJames Feist { 119973df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 120073df0db0SJames Feist { 120173df0db0SJames Feist return; 120273df0db0SJames Feist } 120373df0db0SJames Feist 120473df0db0SJames Feist std::shared_ptr<SetPIDValues> self = shared_from_this(); 120573df0db0SJames Feist 120673df0db0SJames Feist // todo(james): might make sense to do a mapper call here if this 120773df0db0SJames Feist // interface gets more traction 120873df0db0SJames Feist crow::connections::systemBus->async_method_call( 120973df0db0SJames Feist [self](const boost::system::error_code ec, 1210271584abSEd Tanous dbus::utility::ManagedObjectType& mObj) { 121173df0db0SJames Feist if (ec) 121273df0db0SJames Feist { 121373df0db0SJames Feist BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; 121473df0db0SJames Feist messages::internalError(self->asyncResp->res); 121573df0db0SJames Feist return; 121673df0db0SJames Feist } 1217e69d9de2SJames Feist const std::array<const char*, 3> configurations = { 1218e69d9de2SJames Feist pidConfigurationIface, pidZoneConfigurationIface, 1219e69d9de2SJames Feist stepwiseConfigurationIface}; 1220e69d9de2SJames Feist 122114b0b8d5SJames Feist for (const auto& [path, object] : mObj) 1222e69d9de2SJames Feist { 122314b0b8d5SJames Feist for (const auto& [interface, _] : object) 1224e69d9de2SJames Feist { 1225e69d9de2SJames Feist if (std::find(configurations.begin(), 1226e69d9de2SJames Feist configurations.end(), 1227e69d9de2SJames Feist interface) != configurations.end()) 1228e69d9de2SJames Feist { 122914b0b8d5SJames Feist self->objectCount++; 1230e69d9de2SJames Feist break; 1231e69d9de2SJames Feist } 1232e69d9de2SJames Feist } 1233e69d9de2SJames Feist } 1234271584abSEd Tanous self->managedObj = std::move(mObj); 123573df0db0SJames Feist }, 123673df0db0SJames Feist "xyz.openbmc_project.EntityManager", "/", objectManagerIface, 123773df0db0SJames Feist "GetManagedObjects"); 123873df0db0SJames Feist 123973df0db0SJames Feist // at the same time get the profile information 124073df0db0SJames Feist crow::connections::systemBus->async_method_call( 124173df0db0SJames Feist [self](const boost::system::error_code ec, 124273df0db0SJames Feist const crow::openbmc_mapper::GetSubTreeType& subtree) { 124373df0db0SJames Feist if (ec || subtree.empty()) 124473df0db0SJames Feist { 124573df0db0SJames Feist return; 124673df0db0SJames Feist } 124773df0db0SJames Feist if (subtree[0].second.empty()) 124873df0db0SJames Feist { 124973df0db0SJames Feist // invalid mapper response, should never happen 125073df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Mapper Error"; 125173df0db0SJames Feist messages::internalError(self->asyncResp->res); 125273df0db0SJames Feist return; 125373df0db0SJames Feist } 125473df0db0SJames Feist 125573df0db0SJames Feist const std::string& path = subtree[0].first; 125673df0db0SJames Feist const std::string& owner = subtree[0].second[0].first; 125773df0db0SJames Feist crow::connections::systemBus->async_method_call( 125873df0db0SJames Feist [self, path, owner]( 125973df0db0SJames Feist const boost::system::error_code ec, 126073df0db0SJames Feist const boost::container::flat_map< 126173df0db0SJames Feist std::string, std::variant<std::vector<std::string>, 1262271584abSEd Tanous std::string>>& r) { 126373df0db0SJames Feist if (ec) 126473df0db0SJames Feist { 126573df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: Can't get " 126673df0db0SJames Feist "thermalModeIface " 126773df0db0SJames Feist << path; 126873df0db0SJames Feist messages::internalError(self->asyncResp->res); 126973df0db0SJames Feist return; 127073df0db0SJames Feist } 1271271584abSEd Tanous const std::string* current = nullptr; 1272271584abSEd Tanous const std::vector<std::string>* supported = nullptr; 1273271584abSEd Tanous for (auto& [key, value] : r) 127473df0db0SJames Feist { 127573df0db0SJames Feist if (key == "Current") 127673df0db0SJames Feist { 127773df0db0SJames Feist current = std::get_if<std::string>(&value); 127873df0db0SJames Feist if (current == nullptr) 127973df0db0SJames Feist { 128073df0db0SJames Feist BMCWEB_LOG_ERROR 128173df0db0SJames Feist << "SetPIDValues: thermal mode " 128273df0db0SJames Feist "iface invalid " 128373df0db0SJames Feist << path; 128473df0db0SJames Feist messages::internalError( 128573df0db0SJames Feist self->asyncResp->res); 128673df0db0SJames Feist return; 128773df0db0SJames Feist } 128873df0db0SJames Feist } 128973df0db0SJames Feist if (key == "Supported") 129073df0db0SJames Feist { 129173df0db0SJames Feist supported = 129273df0db0SJames Feist std::get_if<std::vector<std::string>>( 129373df0db0SJames Feist &value); 129473df0db0SJames Feist if (supported == nullptr) 129573df0db0SJames Feist { 129673df0db0SJames Feist BMCWEB_LOG_ERROR 129773df0db0SJames Feist << "SetPIDValues: thermal mode " 129873df0db0SJames Feist "iface invalid" 129973df0db0SJames Feist << path; 130073df0db0SJames Feist messages::internalError( 130173df0db0SJames Feist self->asyncResp->res); 130273df0db0SJames Feist return; 130373df0db0SJames Feist } 130473df0db0SJames Feist } 130573df0db0SJames Feist } 130673df0db0SJames Feist if (current == nullptr || supported == nullptr) 130773df0db0SJames Feist { 130873df0db0SJames Feist BMCWEB_LOG_ERROR << "SetPIDValues: thermal mode " 130973df0db0SJames Feist "iface invalid " 131073df0db0SJames Feist << path; 131173df0db0SJames Feist messages::internalError(self->asyncResp->res); 131273df0db0SJames Feist return; 131373df0db0SJames Feist } 131473df0db0SJames Feist self->currentProfile = *current; 131573df0db0SJames Feist self->supportedProfiles = *supported; 131673df0db0SJames Feist self->profileConnection = owner; 131773df0db0SJames Feist self->profilePath = path; 131873df0db0SJames Feist }, 131973df0db0SJames Feist owner, path, "org.freedesktop.DBus.Properties", "GetAll", 132073df0db0SJames Feist thermalModeIface); 13215b4aa86bSJames Feist }, 13225b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", 13235b4aa86bSJames Feist "/xyz/openbmc_project/object_mapper", 13245b4aa86bSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, 132573df0db0SJames Feist std::array<const char*, 1>{thermalModeIface}); 132673df0db0SJames Feist } 132773df0db0SJames Feist ~SetPIDValues() 132873df0db0SJames Feist { 132973df0db0SJames Feist if (asyncResp->res.result() != boost::beast::http::status::ok) 133073df0db0SJames Feist { 133173df0db0SJames Feist return; 13325b4aa86bSJames Feist } 13335b4aa86bSJames Feist 133473df0db0SJames Feist std::shared_ptr<AsyncResp> response = asyncResp; 133573df0db0SJames Feist 133673df0db0SJames Feist if (profile) 133773df0db0SJames Feist { 133873df0db0SJames Feist if (std::find(supportedProfiles.begin(), supportedProfiles.end(), 133973df0db0SJames Feist *profile) == supportedProfiles.end()) 134073df0db0SJames Feist { 134173df0db0SJames Feist messages::actionParameterUnknown(response->res, "Profile", 134273df0db0SJames Feist *profile); 134373df0db0SJames Feist return; 134473df0db0SJames Feist } 134573df0db0SJames Feist currentProfile = *profile; 134673df0db0SJames Feist crow::connections::systemBus->async_method_call( 134773df0db0SJames Feist [response](const boost::system::error_code ec) { 134873df0db0SJames Feist if (ec) 134973df0db0SJames Feist { 135073df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching profile" << ec; 135173df0db0SJames Feist messages::internalError(response->res); 135273df0db0SJames Feist } 135373df0db0SJames Feist }, 135473df0db0SJames Feist profileConnection, profilePath, 135573df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", thermalModeIface, 135673df0db0SJames Feist "Current", std::variant<std::string>(*profile)); 135773df0db0SJames Feist } 135873df0db0SJames Feist 135973df0db0SJames Feist for (auto& containerPair : configuration) 136073df0db0SJames Feist { 136173df0db0SJames Feist auto& container = containerPair.second; 136273df0db0SJames Feist if (!container) 136373df0db0SJames Feist { 136473df0db0SJames Feist continue; 136573df0db0SJames Feist } 13666ee7f774SJames Feist BMCWEB_LOG_DEBUG << *container; 13676ee7f774SJames Feist 136873df0db0SJames Feist std::string& type = containerPair.first; 136973df0db0SJames Feist 137073df0db0SJames Feist for (nlohmann::json::iterator it = container->begin(); 137173df0db0SJames Feist it != container->end(); it++) 137273df0db0SJames Feist { 137373df0db0SJames Feist const auto& name = it.key(); 13746ee7f774SJames Feist BMCWEB_LOG_DEBUG << "looking for " << name; 13756ee7f774SJames Feist 137673df0db0SJames Feist auto pathItr = 137773df0db0SJames Feist std::find_if(managedObj.begin(), managedObj.end(), 137873df0db0SJames Feist [&name](const auto& obj) { 137973df0db0SJames Feist return boost::algorithm::ends_with( 138073df0db0SJames Feist obj.first.str, "/" + name); 138173df0db0SJames Feist }); 138273df0db0SJames Feist boost::container::flat_map<std::string, 138373df0db0SJames Feist dbus::utility::DbusVariantType> 138473df0db0SJames Feist output; 138573df0db0SJames Feist 138673df0db0SJames Feist output.reserve(16); // The pid interface length 138773df0db0SJames Feist 138873df0db0SJames Feist // determines if we're patching entity-manager or 138973df0db0SJames Feist // creating a new object 139073df0db0SJames Feist bool createNewObject = (pathItr == managedObj.end()); 13916ee7f774SJames Feist BMCWEB_LOG_DEBUG << "Found = " << !createNewObject; 13926ee7f774SJames Feist 139373df0db0SJames Feist std::string iface; 139473df0db0SJames Feist if (type == "PidControllers" || type == "FanControllers") 139573df0db0SJames Feist { 139673df0db0SJames Feist iface = pidConfigurationIface; 139773df0db0SJames Feist if (!createNewObject && 139873df0db0SJames Feist pathItr->second.find(pidConfigurationIface) == 139973df0db0SJames Feist pathItr->second.end()) 140073df0db0SJames Feist { 140173df0db0SJames Feist createNewObject = true; 140273df0db0SJames Feist } 140373df0db0SJames Feist } 140473df0db0SJames Feist else if (type == "FanZones") 140573df0db0SJames Feist { 140673df0db0SJames Feist iface = pidZoneConfigurationIface; 140773df0db0SJames Feist if (!createNewObject && 140873df0db0SJames Feist pathItr->second.find(pidZoneConfigurationIface) == 140973df0db0SJames Feist pathItr->second.end()) 141073df0db0SJames Feist { 141173df0db0SJames Feist 141273df0db0SJames Feist createNewObject = true; 141373df0db0SJames Feist } 141473df0db0SJames Feist } 141573df0db0SJames Feist else if (type == "StepwiseControllers") 141673df0db0SJames Feist { 141773df0db0SJames Feist iface = stepwiseConfigurationIface; 141873df0db0SJames Feist if (!createNewObject && 141973df0db0SJames Feist pathItr->second.find(stepwiseConfigurationIface) == 142073df0db0SJames Feist pathItr->second.end()) 142173df0db0SJames Feist { 142273df0db0SJames Feist createNewObject = true; 142373df0db0SJames Feist } 142473df0db0SJames Feist } 14256ee7f774SJames Feist 14266ee7f774SJames Feist if (createNewObject && it.value() == nullptr) 14276ee7f774SJames Feist { 14286ee7f774SJames Feist // can't delete a non-existant object 14296ee7f774SJames Feist messages::invalidObject(response->res, name); 14306ee7f774SJames Feist continue; 14316ee7f774SJames Feist } 14326ee7f774SJames Feist 14336ee7f774SJames Feist std::string path; 14346ee7f774SJames Feist if (pathItr != managedObj.end()) 14356ee7f774SJames Feist { 14366ee7f774SJames Feist path = pathItr->first.str; 14376ee7f774SJames Feist } 14386ee7f774SJames Feist 143973df0db0SJames Feist BMCWEB_LOG_DEBUG << "Create new = " << createNewObject << "\n"; 1440e69d9de2SJames Feist 1441e69d9de2SJames Feist // arbitrary limit to avoid attacks 1442e69d9de2SJames Feist constexpr const size_t controllerLimit = 500; 144314b0b8d5SJames Feist if (createNewObject && objectCount >= controllerLimit) 1444e69d9de2SJames Feist { 1445e69d9de2SJames Feist messages::resourceExhaustion(response->res, type); 1446e69d9de2SJames Feist continue; 1447e69d9de2SJames Feist } 1448e69d9de2SJames Feist 144973df0db0SJames Feist output["Name"] = boost::replace_all_copy(name, "_", " "); 145073df0db0SJames Feist 145173df0db0SJames Feist std::string chassis; 145273df0db0SJames Feist CreatePIDRet ret = createPidInterface( 14536ee7f774SJames Feist response, type, it, path, managedObj, createNewObject, 14546ee7f774SJames Feist output, chassis, currentProfile); 145573df0db0SJames Feist if (ret == CreatePIDRet::fail) 145673df0db0SJames Feist { 145773df0db0SJames Feist return; 145873df0db0SJames Feist } 145973df0db0SJames Feist else if (ret == CreatePIDRet::del) 146073df0db0SJames Feist { 146173df0db0SJames Feist continue; 146273df0db0SJames Feist } 146373df0db0SJames Feist 146473df0db0SJames Feist if (!createNewObject) 146573df0db0SJames Feist { 146673df0db0SJames Feist for (const auto& property : output) 146773df0db0SJames Feist { 146873df0db0SJames Feist crow::connections::systemBus->async_method_call( 146973df0db0SJames Feist [response, 147073df0db0SJames Feist propertyName{std::string(property.first)}]( 147173df0db0SJames Feist const boost::system::error_code ec) { 147273df0db0SJames Feist if (ec) 147373df0db0SJames Feist { 147473df0db0SJames Feist BMCWEB_LOG_ERROR << "Error patching " 147573df0db0SJames Feist << propertyName << ": " 147673df0db0SJames Feist << ec; 147773df0db0SJames Feist messages::internalError(response->res); 147873df0db0SJames Feist return; 147973df0db0SJames Feist } 148073df0db0SJames Feist messages::success(response->res); 148173df0db0SJames Feist }, 14826ee7f774SJames Feist "xyz.openbmc_project.EntityManager", path, 148373df0db0SJames Feist "org.freedesktop.DBus.Properties", "Set", iface, 148473df0db0SJames Feist property.first, property.second); 148573df0db0SJames Feist } 148673df0db0SJames Feist } 148773df0db0SJames Feist else 148873df0db0SJames Feist { 148973df0db0SJames Feist if (chassis.empty()) 149073df0db0SJames Feist { 149173df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to get chassis from config"; 149273df0db0SJames Feist messages::invalidObject(response->res, name); 149373df0db0SJames Feist return; 149473df0db0SJames Feist } 149573df0db0SJames Feist 149673df0db0SJames Feist bool foundChassis = false; 149773df0db0SJames Feist for (const auto& obj : managedObj) 149873df0db0SJames Feist { 149973df0db0SJames Feist if (boost::algorithm::ends_with(obj.first.str, chassis)) 150073df0db0SJames Feist { 150173df0db0SJames Feist chassis = obj.first.str; 150273df0db0SJames Feist foundChassis = true; 150373df0db0SJames Feist break; 150473df0db0SJames Feist } 150573df0db0SJames Feist } 150673df0db0SJames Feist if (!foundChassis) 150773df0db0SJames Feist { 150873df0db0SJames Feist BMCWEB_LOG_ERROR << "Failed to find chassis on dbus"; 150973df0db0SJames Feist messages::resourceMissingAtURI( 151073df0db0SJames Feist response->res, "/redfish/v1/Chassis/" + chassis); 151173df0db0SJames Feist return; 151273df0db0SJames Feist } 151373df0db0SJames Feist 151473df0db0SJames Feist crow::connections::systemBus->async_method_call( 151573df0db0SJames Feist [response](const boost::system::error_code ec) { 151673df0db0SJames Feist if (ec) 151773df0db0SJames Feist { 151873df0db0SJames Feist BMCWEB_LOG_ERROR << "Error Adding Pid Object " 151973df0db0SJames Feist << ec; 152073df0db0SJames Feist messages::internalError(response->res); 152173df0db0SJames Feist return; 152273df0db0SJames Feist } 152373df0db0SJames Feist messages::success(response->res); 152473df0db0SJames Feist }, 152573df0db0SJames Feist "xyz.openbmc_project.EntityManager", chassis, 152673df0db0SJames Feist "xyz.openbmc_project.AddObject", "AddObject", output); 152773df0db0SJames Feist } 152873df0db0SJames Feist } 152973df0db0SJames Feist } 153073df0db0SJames Feist } 153173df0db0SJames Feist std::shared_ptr<AsyncResp> asyncResp; 153273df0db0SJames Feist std::vector<std::pair<std::string, std::optional<nlohmann::json>>> 153373df0db0SJames Feist configuration; 153473df0db0SJames Feist std::optional<std::string> profile; 153573df0db0SJames Feist dbus::utility::ManagedObjectType managedObj; 153673df0db0SJames Feist std::vector<std::string> supportedProfiles; 153773df0db0SJames Feist std::string currentProfile; 153873df0db0SJames Feist std::string profileConnection; 153973df0db0SJames Feist std::string profilePath; 154014b0b8d5SJames Feist size_t objectCount = 0; 154173df0db0SJames Feist }; 154273df0db0SJames Feist 154373df0db0SJames Feist class Manager : public Node 154473df0db0SJames Feist { 154573df0db0SJames Feist public: 154673df0db0SJames Feist Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") 154773df0db0SJames Feist { 154873df0db0SJames Feist uuid = app.template getMiddleware<crow::persistent_data::Middleware>() 154973df0db0SJames Feist .systemUuid; 155073df0db0SJames Feist entityPrivileges = { 155173df0db0SJames Feist {boost::beast::http::verb::get, {{"Login"}}}, 155273df0db0SJames Feist {boost::beast::http::verb::head, {{"Login"}}}, 155373df0db0SJames Feist {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 155473df0db0SJames Feist {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 155573df0db0SJames Feist {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 155673df0db0SJames Feist {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 155773df0db0SJames Feist } 155873df0db0SJames Feist 155973df0db0SJames Feist private: 156055c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 15611abe55efSEd Tanous const std::vector<std::string>& params) override 15621abe55efSEd Tanous { 15630f74e643SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc"; 15640f74e643SEd Tanous res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager"; 15650f74e643SEd Tanous res.jsonValue["Id"] = "bmc"; 15660f74e643SEd Tanous res.jsonValue["Name"] = "OpenBmc Manager"; 15670f74e643SEd Tanous res.jsonValue["Description"] = "Baseboard Management Controller"; 15680f74e643SEd Tanous res.jsonValue["PowerState"] = "On"; 1569029573d4SEd Tanous res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}}; 15700f74e643SEd Tanous res.jsonValue["ManagerType"] = "BMC"; 15713602e232SEd Tanous res.jsonValue["UUID"] = systemd_utils::getUuid(); 15723602e232SEd Tanous res.jsonValue["ServiceEntryPointUUID"] = uuid; 15730f74e643SEd Tanous res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model 15740f74e643SEd Tanous 15750f74e643SEd Tanous res.jsonValue["LogServices"] = { 15760f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}}; 15770f74e643SEd Tanous 15780f74e643SEd Tanous res.jsonValue["NetworkProtocol"] = { 15790f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}}; 15800f74e643SEd Tanous 15810f74e643SEd Tanous res.jsonValue["EthernetInterfaces"] = { 15820f74e643SEd Tanous {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; 1583107077deSPrzemyslaw Czarnowski 1584107077deSPrzemyslaw Czarnowski #ifdef BMCWEB_ENABLE_VM_NBDPROXY 1585107077deSPrzemyslaw Czarnowski res.jsonValue["VirtualMedia"] = { 1586107077deSPrzemyslaw Czarnowski {"@odata.id", "/redfish/v1/Managers/bmc/VirtualMedia"}}; 1587107077deSPrzemyslaw Czarnowski #endif // BMCWEB_ENABLE_VM_NBDPROXY 1588107077deSPrzemyslaw Czarnowski 15890f74e643SEd Tanous // default oem data 15900f74e643SEd Tanous nlohmann::json& oem = res.jsonValue["Oem"]; 15910f74e643SEd Tanous nlohmann::json& oemOpenbmc = oem["OpenBmc"]; 15920f74e643SEd Tanous oem["@odata.type"] = "#OemManager.Oem"; 15930f74e643SEd Tanous oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; 15940f74e643SEd Tanous oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; 15950f74e643SEd Tanous oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; 1596cfcd5f6bSMarri Devender Rao oemOpenbmc["Certificates"] = { 1597cfcd5f6bSMarri Devender Rao {"@odata.id", "/redfish/v1/Managers/bmc/Truststore/Certificates"}}; 15980f74e643SEd Tanous 1599*2a5c4407SGunnar Mills // Manager.Reset (an action) can be many values, OpenBMC only supports 1600*2a5c4407SGunnar Mills // BMC reboot. 1601*2a5c4407SGunnar Mills nlohmann::json& managerReset = 16020f74e643SEd Tanous res.jsonValue["Actions"]["#Manager.Reset"]; 1603*2a5c4407SGunnar Mills managerReset["target"] = 1604ed5befbdSJennifer Lee "/redfish/v1/Managers/bmc/Actions/Manager.Reset"; 1605*2a5c4407SGunnar Mills managerReset["ResetType@Redfish.AllowableValues"] = {"GracefulRestart"}; 1606ca537928SJennifer Lee 1607cb92c03bSAndrew Geissler res.jsonValue["DateTime"] = crow::utility::dateTimeNow(); 1608474bfad5SSantosh Puranik 1609f8c3e6f0SKuiying Wang // Fill in SerialConsole info 1610474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ServiceEnabled"] = true; 1611f8c3e6f0SKuiying Wang res.jsonValue["SerialConsole"]["MaxConcurrentSessions"] = 15; 1612474bfad5SSantosh Puranik res.jsonValue["SerialConsole"]["ConnectTypesSupported"] = {"IPMI", 1613474bfad5SSantosh Puranik "SSH"}; 1614ef47bb18SSantosh Puranik #ifdef BMCWEB_ENABLE_KVM 1615f8c3e6f0SKuiying Wang // Fill in GraphicalConsole info 1616ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ServiceEnabled"] = true; 1617704fae6cSJae Hyun Yoo res.jsonValue["GraphicalConsole"]["MaxConcurrentSessions"] = 4; 1618ef47bb18SSantosh Puranik res.jsonValue["GraphicalConsole"]["ConnectTypesSupported"] = {"KVMIP"}; 1619ef47bb18SSantosh Puranik #endif // BMCWEB_ENABLE_KVM 1620474bfad5SSantosh Puranik 1621603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers@odata.count"] = 1; 1622603a6640SGunnar Mills res.jsonValue["Links"]["ManagerForServers"] = { 1623603a6640SGunnar Mills {{"@odata.id", "/redfish/v1/Systems/system"}}}; 162426f03899SShawn McCarney 1625ed5befbdSJennifer Lee std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); 16265b4aa86bSJames Feist 1627b49ac873SJames Feist auto health = std::make_shared<HealthPopulate>(asyncResp); 1628b49ac873SJames Feist health->isManagersHealth = true; 1629b49ac873SJames Feist health->populate(); 1630b49ac873SJames Feist 1631e90c5052SAndrew Geissler fw_util::getActiveFwVersion(asyncResp, fw_util::bmcPurpose, 1632e90c5052SAndrew Geissler "FirmwareVersion"); 16330f6b00bdSJames Feist 163473df0db0SJames Feist auto pids = std::make_shared<GetPIDValues>(asyncResp); 163573df0db0SJames Feist pids->run(); 1636c5d03ff4SJennifer Lee 1637c5d03ff4SJennifer Lee getMainChassisId(asyncResp, [](const std::string& chassisId, 1638c5d03ff4SJennifer Lee const std::shared_ptr<AsyncResp> aRsp) { 1639c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis@odata.count"] = 1; 1640c5d03ff4SJennifer Lee aRsp->res.jsonValue["Links"]["ManagerForChassis"] = { 1641c5d03ff4SJennifer Lee {{"@odata.id", "/redfish/v1/Chassis/" + chassisId}}}; 16422c0feb00SJason M. Bills aRsp->res.jsonValue["Links"]["ManagerInChassis"] = { 16432c0feb00SJason M. Bills {"@odata.id", "/redfish/v1/Chassis/" + chassisId}}; 1644c5d03ff4SJennifer Lee }); 16450f6b00bdSJames Feist 16460f6b00bdSJames Feist static bool started = false; 16470f6b00bdSJames Feist 16480f6b00bdSJames Feist if (!started) 16490f6b00bdSJames Feist { 16500f6b00bdSJames Feist crow::connections::systemBus->async_method_call( 16510f6b00bdSJames Feist [asyncResp](const boost::system::error_code ec, 16520f6b00bdSJames Feist const std::variant<double>& resp) { 16530f6b00bdSJames Feist if (ec) 16540f6b00bdSJames Feist { 16550f6b00bdSJames Feist BMCWEB_LOG_ERROR << "Error while getting progress"; 16560f6b00bdSJames Feist messages::internalError(asyncResp->res); 16570f6b00bdSJames Feist return; 16580f6b00bdSJames Feist } 16590f6b00bdSJames Feist const double* val = std::get_if<double>(&resp); 16600f6b00bdSJames Feist if (val == nullptr) 16610f6b00bdSJames Feist { 16620f6b00bdSJames Feist BMCWEB_LOG_ERROR 16630f6b00bdSJames Feist << "Invalid response while getting progress"; 16640f6b00bdSJames Feist messages::internalError(asyncResp->res); 16650f6b00bdSJames Feist return; 16660f6b00bdSJames Feist } 16670f6b00bdSJames Feist if (*val < 1.0) 16680f6b00bdSJames Feist { 16690f6b00bdSJames Feist asyncResp->res.jsonValue["Status"]["State"] = 16700f6b00bdSJames Feist "Starting"; 16710f6b00bdSJames Feist started = true; 16720f6b00bdSJames Feist } 16730f6b00bdSJames Feist }, 16740f6b00bdSJames Feist "org.freedesktop.systemd1", "/org/freedesktop/systemd1", 16750f6b00bdSJames Feist "org.freedesktop.DBus.Properties", "Get", 16760f6b00bdSJames Feist "org.freedesktop.systemd1.Manager", "Progress"); 16770f6b00bdSJames Feist } 167883ff9ab6SJames Feist } 16795b4aa86bSJames Feist 16805b4aa86bSJames Feist void doPatch(crow::Response& res, const crow::Request& req, 16815b4aa86bSJames Feist const std::vector<std::string>& params) override 16825b4aa86bSJames Feist { 16830627a2c7SEd Tanous std::optional<nlohmann::json> oem; 1684af5d6058SSantosh Puranik std::optional<std::string> datetime; 168541352c24SSantosh Puranik std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); 16860627a2c7SEd Tanous 168741352c24SSantosh Puranik if (!json_util::readJson(req, response->res, "Oem", oem, "DateTime", 168841352c24SSantosh Puranik datetime)) 168983ff9ab6SJames Feist { 169083ff9ab6SJames Feist return; 169183ff9ab6SJames Feist } 16920627a2c7SEd Tanous 16930627a2c7SEd Tanous if (oem) 169483ff9ab6SJames Feist { 16955f2caaefSJames Feist std::optional<nlohmann::json> openbmc; 169643b761d0SEd Tanous if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc)) 169783ff9ab6SJames Feist { 169843b761d0SEd Tanous BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " 169943b761d0SEd Tanous << oem->dump(); 170083ff9ab6SJames Feist return; 170183ff9ab6SJames Feist } 17025f2caaefSJames Feist if (openbmc) 170383ff9ab6SJames Feist { 17045f2caaefSJames Feist std::optional<nlohmann::json> fan; 170543b761d0SEd Tanous if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan)) 170683ff9ab6SJames Feist { 17075f2caaefSJames Feist BMCWEB_LOG_ERROR << "Line:" << __LINE__ 17085f2caaefSJames Feist << ", Illegal Property " 17095f2caaefSJames Feist << openbmc->dump(); 171083ff9ab6SJames Feist return; 171183ff9ab6SJames Feist } 17125f2caaefSJames Feist if (fan) 171383ff9ab6SJames Feist { 171473df0db0SJames Feist auto pid = std::make_shared<SetPIDValues>(response, *fan); 171573df0db0SJames Feist pid->run(); 171683ff9ab6SJames Feist } 171783ff9ab6SJames Feist } 171883ff9ab6SJames Feist } 1719af5d6058SSantosh Puranik if (datetime) 1720af5d6058SSantosh Puranik { 1721af5d6058SSantosh Puranik setDateTime(response, std::move(*datetime)); 1722af5d6058SSantosh Puranik } 1723af5d6058SSantosh Puranik } 1724af5d6058SSantosh Puranik 1725af5d6058SSantosh Puranik void setDateTime(std::shared_ptr<AsyncResp> aResp, 1726af5d6058SSantosh Puranik std::string datetime) const 1727af5d6058SSantosh Puranik { 1728af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Set date time: " << datetime; 1729af5d6058SSantosh Puranik 1730af5d6058SSantosh Puranik std::stringstream stream(datetime); 1731af5d6058SSantosh Puranik // Convert from ISO 8601 to boost local_time 1732af5d6058SSantosh Puranik // (BMC only has time in UTC) 1733af5d6058SSantosh Puranik boost::posix_time::ptime posixTime; 1734af5d6058SSantosh Puranik boost::posix_time::ptime epoch(boost::gregorian::date(1970, 1, 1)); 1735af5d6058SSantosh Puranik // Facet gets deleted with the stringsteam 1736af5d6058SSantosh Puranik auto ifc = std::make_unique<boost::local_time::local_time_input_facet>( 1737af5d6058SSantosh Puranik "%Y-%m-%d %H:%M:%S%F %ZP"); 1738af5d6058SSantosh Puranik stream.imbue(std::locale(stream.getloc(), ifc.release())); 1739af5d6058SSantosh Puranik 1740af5d6058SSantosh Puranik boost::local_time::local_date_time ldt( 1741af5d6058SSantosh Puranik boost::local_time::not_a_date_time); 1742af5d6058SSantosh Puranik 1743af5d6058SSantosh Puranik if (stream >> ldt) 1744af5d6058SSantosh Puranik { 1745af5d6058SSantosh Puranik posixTime = ldt.utc_time(); 1746af5d6058SSantosh Puranik boost::posix_time::time_duration dur = posixTime - epoch; 1747af5d6058SSantosh Puranik uint64_t durMicroSecs = 1748af5d6058SSantosh Puranik static_cast<uint64_t>(dur.total_microseconds()); 1749af5d6058SSantosh Puranik crow::connections::systemBus->async_method_call( 1750af5d6058SSantosh Puranik [aResp{std::move(aResp)}, datetime{std::move(datetime)}]( 1751af5d6058SSantosh Puranik const boost::system::error_code ec) { 1752af5d6058SSantosh Puranik if (ec) 1753af5d6058SSantosh Puranik { 1754af5d6058SSantosh Puranik BMCWEB_LOG_DEBUG << "Failed to set elapsed time. " 1755af5d6058SSantosh Puranik "DBUS response error " 1756af5d6058SSantosh Puranik << ec; 1757af5d6058SSantosh Puranik messages::internalError(aResp->res); 1758af5d6058SSantosh Puranik return; 1759af5d6058SSantosh Puranik } 1760af5d6058SSantosh Puranik aResp->res.jsonValue["DateTime"] = datetime; 1761af5d6058SSantosh Puranik }, 1762af5d6058SSantosh Puranik "xyz.openbmc_project.Time.Manager", 1763af5d6058SSantosh Puranik "/xyz/openbmc_project/time/bmc", 1764af5d6058SSantosh Puranik "org.freedesktop.DBus.Properties", "Set", 1765af5d6058SSantosh Puranik "xyz.openbmc_project.Time.EpochTime", "Elapsed", 1766af5d6058SSantosh Puranik std::variant<uint64_t>(durMicroSecs)); 1767af5d6058SSantosh Puranik } 1768af5d6058SSantosh Puranik else 1769af5d6058SSantosh Puranik { 1770af5d6058SSantosh Puranik messages::propertyValueFormatError(aResp->res, datetime, 1771af5d6058SSantosh Puranik "DateTime"); 1772af5d6058SSantosh Puranik return; 1773af5d6058SSantosh Puranik } 177483ff9ab6SJames Feist } 17759c310685SBorawski.Lukasz 17760f74e643SEd Tanous std::string uuid; 17779c310685SBorawski.Lukasz }; 17789c310685SBorawski.Lukasz 17791abe55efSEd Tanous class ManagerCollection : public Node 17801abe55efSEd Tanous { 17819c310685SBorawski.Lukasz public: 17821abe55efSEd Tanous ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") 17831abe55efSEd Tanous { 1784a434f2bdSEd Tanous entityPrivileges = { 1785a434f2bdSEd Tanous {boost::beast::http::verb::get, {{"Login"}}}, 1786e0d918bcSEd Tanous {boost::beast::http::verb::head, {{"Login"}}}, 1787e0d918bcSEd Tanous {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, 1788e0d918bcSEd Tanous {boost::beast::http::verb::put, {{"ConfigureManager"}}}, 1789e0d918bcSEd Tanous {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, 1790e0d918bcSEd Tanous {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; 17919c310685SBorawski.Lukasz } 17929c310685SBorawski.Lukasz 17939c310685SBorawski.Lukasz private: 179455c7b7a2SEd Tanous void doGet(crow::Response& res, const crow::Request& req, 17951abe55efSEd Tanous const std::vector<std::string>& params) override 17961abe55efSEd Tanous { 179783ff9ab6SJames Feist // Collections don't include the static data added by SubRoute 179883ff9ab6SJames Feist // because it has a duplicate entry for members 179955c7b7a2SEd Tanous res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; 180055c7b7a2SEd Tanous res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; 180155c7b7a2SEd Tanous res.jsonValue["Name"] = "Manager Collection"; 180255c7b7a2SEd Tanous res.jsonValue["Members@odata.count"] = 1; 180355c7b7a2SEd Tanous res.jsonValue["Members"] = { 18045b4aa86bSJames Feist {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; 18059c310685SBorawski.Lukasz res.end(); 18069c310685SBorawski.Lukasz } 18079c310685SBorawski.Lukasz }; 18089c310685SBorawski.Lukasz } // namespace redfish 1809