| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 1 | /* | 
|  | 2 | // Copyright (c) 2018 Intel Corporation | 
|  | 3 | // | 
|  | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | // you may not use this file except in compliance with the License. | 
|  | 6 | // You may obtain a copy of the License at | 
|  | 7 | // | 
|  | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | // | 
|  | 10 | // Unless required by applicable law or agreed to in writing, software | 
|  | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | // See the License for the specific language governing permissions and | 
|  | 14 | // limitations under the License. | 
|  | 15 | */ | 
|  | 16 | #pragma once | 
|  | 17 |  | 
|  | 18 | #include "node.hpp" | 
|  | 19 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 20 | #include <boost/algorithm/string/replace.hpp> | 
|  | 21 | #include <dbus_utility.hpp> | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 22 | #include <variant> | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 23 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 24 | namespace redfish | 
|  | 25 | { | 
| Jennifer Lee | ed5befb | 2018-08-10 11:29:45 -0700 | [diff] [blame] | 26 |  | 
|  | 27 | /** | 
|  | 28 | * ManagerActionsReset class supports handle POST method for Reset action. | 
|  | 29 | * The class retrieves and sends data directly to dbus. | 
|  | 30 | */ | 
|  | 31 | class ManagerActionsReset : public Node | 
|  | 32 | { | 
|  | 33 | public: | 
|  | 34 | ManagerActionsReset(CrowApp& app) : | 
|  | 35 | Node(app, "/redfish/v1/Managers/bmc/Actions/Manager.Reset/") | 
|  | 36 | { | 
|  | 37 | entityPrivileges = { | 
|  | 38 | {boost::beast::http::verb::get, {{"Login"}}}, | 
|  | 39 | {boost::beast::http::verb::head, {{"Login"}}}, | 
|  | 40 | {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, | 
|  | 41 | {boost::beast::http::verb::put, {{"ConfigureManager"}}}, | 
|  | 42 | {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, | 
|  | 43 | {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; | 
|  | 44 | } | 
|  | 45 |  | 
|  | 46 | private: | 
|  | 47 | /** | 
| Jennifer Lee | ed5befb | 2018-08-10 11:29:45 -0700 | [diff] [blame] | 48 | * Function handles POST method request. | 
|  | 49 | * Analyzes POST body message before sends Reset request data to dbus. | 
|  | 50 | * OpenBMC allows for ResetType is GracefulRestart only. | 
|  | 51 | */ | 
|  | 52 | void doPost(crow::Response& res, const crow::Request& req, | 
|  | 53 | const std::vector<std::string>& params) override | 
|  | 54 | { | 
|  | 55 | std::string resetType; | 
|  | 56 |  | 
|  | 57 | if (!json_util::readJson(req, res, "ResetType", resetType)) | 
|  | 58 | { | 
|  | 59 | return; | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | if (resetType != "GracefulRestart") | 
|  | 63 | { | 
|  | 64 | res.result(boost::beast::http::status::bad_request); | 
|  | 65 | messages::actionParameterNotSupported(res, resetType, "ResetType"); | 
|  | 66 | BMCWEB_LOG_ERROR << "Request incorrect action parameter: " | 
|  | 67 | << resetType; | 
|  | 68 | res.end(); | 
|  | 69 | return; | 
|  | 70 | } | 
|  | 71 | doBMCGracefulRestart(res, req, params); | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | /** | 
|  | 75 | * Function transceives data with dbus directly. | 
|  | 76 | * All BMC state properties will be retrieved before sending reset request. | 
|  | 77 | */ | 
|  | 78 | void doBMCGracefulRestart(crow::Response& res, const crow::Request& req, | 
|  | 79 | const std::vector<std::string>& params) | 
|  | 80 | { | 
|  | 81 | const char* processName = "xyz.openbmc_project.State.BMC"; | 
|  | 82 | const char* objectPath = "/xyz/openbmc_project/state/bmc0"; | 
|  | 83 | const char* interfaceName = "xyz.openbmc_project.State.BMC"; | 
|  | 84 | const std::string& propertyValue = | 
|  | 85 | "xyz.openbmc_project.State.BMC.Transition.Reboot"; | 
|  | 86 | const char* destProperty = "RequestedBMCTransition"; | 
|  | 87 |  | 
|  | 88 | // Create the D-Bus variant for D-Bus call. | 
|  | 89 | VariantType dbusPropertyValue(propertyValue); | 
|  | 90 |  | 
|  | 91 | std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); | 
|  | 92 |  | 
|  | 93 | crow::connections::systemBus->async_method_call( | 
|  | 94 | [asyncResp](const boost::system::error_code ec) { | 
|  | 95 | // Use "Set" method to set the property value. | 
|  | 96 | if (ec) | 
|  | 97 | { | 
|  | 98 | BMCWEB_LOG_ERROR << "[Set] Bad D-Bus request error: " << ec; | 
|  | 99 | messages::internalError(asyncResp->res); | 
|  | 100 | return; | 
|  | 101 | } | 
|  | 102 |  | 
|  | 103 | messages::success(asyncResp->res); | 
|  | 104 | }, | 
|  | 105 | processName, objectPath, "org.freedesktop.DBus.Properties", "Set", | 
|  | 106 | interfaceName, destProperty, dbusPropertyValue); | 
|  | 107 | } | 
|  | 108 | }; | 
|  | 109 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 110 | static constexpr const char* objectManagerIface = | 
|  | 111 | "org.freedesktop.DBus.ObjectManager"; | 
|  | 112 | static constexpr const char* pidConfigurationIface = | 
|  | 113 | "xyz.openbmc_project.Configuration.Pid"; | 
|  | 114 | static constexpr const char* pidZoneConfigurationIface = | 
|  | 115 | "xyz.openbmc_project.Configuration.Pid.Zone"; | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 116 | static constexpr const char* stepwiseConfigurationIface = | 
|  | 117 | "xyz.openbmc_project.Configuration.Stepwise"; | 
| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 118 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 119 | static void asyncPopulatePid(const std::string& connection, | 
|  | 120 | const std::string& path, | 
|  | 121 | std::shared_ptr<AsyncResp> asyncResp) | 
|  | 122 | { | 
|  | 123 |  | 
|  | 124 | crow::connections::systemBus->async_method_call( | 
|  | 125 | [asyncResp](const boost::system::error_code ec, | 
|  | 126 | const dbus::utility::ManagedObjectType& managedObj) { | 
|  | 127 | if (ec) | 
|  | 128 | { | 
|  | 129 | BMCWEB_LOG_ERROR << ec; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 130 | asyncResp->res.jsonValue.clear(); | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 131 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 132 | return; | 
|  | 133 | } | 
|  | 134 | nlohmann::json& configRoot = | 
|  | 135 | asyncResp->res.jsonValue["Oem"]["OpenBmc"]["Fan"]; | 
|  | 136 | nlohmann::json& fans = configRoot["FanControllers"]; | 
|  | 137 | fans["@odata.type"] = "#OemManager.FanControllers"; | 
|  | 138 | fans["@odata.context"] = | 
|  | 139 | "/redfish/v1/$metadata#OemManager.FanControllers"; | 
|  | 140 | fans["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc/" | 
|  | 141 | "Fan/FanControllers"; | 
|  | 142 |  | 
|  | 143 | nlohmann::json& pids = configRoot["PidControllers"]; | 
|  | 144 | pids["@odata.type"] = "#OemManager.PidControllers"; | 
|  | 145 | pids["@odata.context"] = | 
|  | 146 | "/redfish/v1/$metadata#OemManager.PidControllers"; | 
|  | 147 | pids["@odata.id"] = | 
|  | 148 | "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/PidControllers"; | 
|  | 149 |  | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 150 | nlohmann::json& stepwise = configRoot["StepwiseControllers"]; | 
|  | 151 | stepwise["@odata.type"] = "#OemManager.StepwiseControllers"; | 
|  | 152 | stepwise["@odata.context"] = | 
|  | 153 | "/redfish/v1/$metadata#OemManager.StepwiseControllers"; | 
|  | 154 | stepwise["@odata.id"] = | 
|  | 155 | "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/StepwiseControllers"; | 
|  | 156 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 157 | nlohmann::json& zones = configRoot["FanZones"]; | 
|  | 158 | zones["@odata.id"] = | 
|  | 159 | "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones"; | 
|  | 160 | zones["@odata.type"] = "#OemManager.FanZones"; | 
|  | 161 | zones["@odata.context"] = | 
|  | 162 | "/redfish/v1/$metadata#OemManager.FanZones"; | 
|  | 163 | configRoot["@odata.id"] = | 
|  | 164 | "/redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan"; | 
|  | 165 | configRoot["@odata.type"] = "#OemManager.Fan"; | 
|  | 166 | configRoot["@odata.context"] = | 
|  | 167 | "/redfish/v1/$metadata#OemManager.Fan"; | 
|  | 168 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 169 | for (const auto& pathPair : managedObj) | 
|  | 170 | { | 
|  | 171 | for (const auto& intfPair : pathPair.second) | 
|  | 172 | { | 
|  | 173 | if (intfPair.first != pidConfigurationIface && | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 174 | intfPair.first != pidZoneConfigurationIface && | 
|  | 175 | intfPair.first != stepwiseConfigurationIface) | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 176 | { | 
|  | 177 | continue; | 
|  | 178 | } | 
|  | 179 | auto findName = intfPair.second.find("Name"); | 
|  | 180 | if (findName == intfPair.second.end()) | 
|  | 181 | { | 
|  | 182 | BMCWEB_LOG_ERROR << "Pid Field missing Name"; | 
| Jason M. Bills | a08b46c | 2018-11-06 15:01:08 -0800 | [diff] [blame] | 183 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 184 | return; | 
|  | 185 | } | 
|  | 186 | const std::string* namePtr = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 187 | std::get_if<std::string>(&findName->second); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 188 | if (namePtr == nullptr) | 
|  | 189 | { | 
|  | 190 | BMCWEB_LOG_ERROR << "Pid Name Field illegal"; | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 191 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 192 | return; | 
|  | 193 | } | 
|  | 194 |  | 
|  | 195 | std::string name = *namePtr; | 
|  | 196 | dbus::utility::escapePathForDbus(name); | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 197 | nlohmann::json* config = nullptr; | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 198 |  | 
|  | 199 | const std::string* classPtr = nullptr; | 
|  | 200 | auto findClass = intfPair.second.find("Class"); | 
|  | 201 | if (findClass != intfPair.second.end()) | 
|  | 202 | { | 
|  | 203 | classPtr = std::get_if<std::string>(&findClass->second); | 
|  | 204 | } | 
|  | 205 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 206 | if (intfPair.first == pidZoneConfigurationIface) | 
|  | 207 | { | 
|  | 208 | std::string chassis; | 
|  | 209 | if (!dbus::utility::getNthStringFromPath( | 
|  | 210 | pathPair.first.str, 5, chassis)) | 
|  | 211 | { | 
|  | 212 | chassis = "#IllegalValue"; | 
|  | 213 | } | 
|  | 214 | nlohmann::json& zone = zones[name]; | 
|  | 215 | zone["Chassis"] = { | 
|  | 216 | {"@odata.id", "/redfish/v1/Chassis/" + chassis}}; | 
|  | 217 | zone["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/" | 
|  | 218 | "OpenBmc/Fan/FanZones/" + | 
|  | 219 | name; | 
|  | 220 | zone["@odata.type"] = "#OemManager.FanZone"; | 
|  | 221 | zone["@odata.context"] = | 
|  | 222 | "/redfish/v1/$metadata#OemManager.FanZone"; | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 223 | config = &zone; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 224 | } | 
|  | 225 |  | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 226 | else if (intfPair.first == stepwiseConfigurationIface) | 
|  | 227 | { | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 228 | if (classPtr == nullptr) | 
|  | 229 | { | 
|  | 230 | BMCWEB_LOG_ERROR << "Pid Class Field illegal"; | 
|  | 231 | messages::internalError(asyncResp->res); | 
|  | 232 | return; | 
|  | 233 | } | 
|  | 234 |  | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 235 | nlohmann::json& controller = stepwise[name]; | 
|  | 236 | config = &controller; | 
|  | 237 |  | 
|  | 238 | controller["@odata.id"] = | 
|  | 239 | "/redfish/v1/Managers/bmc#/Oem/" | 
|  | 240 | "OpenBmc/Fan/StepwiseControllers/" + | 
|  | 241 | std::string(name); | 
|  | 242 | controller["@odata.type"] = | 
|  | 243 | "#OemManager.StepwiseController"; | 
|  | 244 |  | 
|  | 245 | controller["@odata.context"] = | 
|  | 246 | "/redfish/v1/" | 
|  | 247 | "$metadata#OemManager.StepwiseController"; | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 248 | controller["Direction"] = *classPtr; | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 249 | } | 
|  | 250 |  | 
|  | 251 | // pid and fans are off the same configuration | 
|  | 252 | else if (intfPair.first == pidConfigurationIface) | 
|  | 253 | { | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 254 |  | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 255 | if (classPtr == nullptr) | 
|  | 256 | { | 
|  | 257 | BMCWEB_LOG_ERROR << "Pid Class Field illegal"; | 
|  | 258 | messages::internalError(asyncResp->res); | 
|  | 259 | return; | 
|  | 260 | } | 
|  | 261 | bool isFan = *classPtr == "fan"; | 
|  | 262 | nlohmann::json& element = | 
|  | 263 | isFan ? fans[name] : pids[name]; | 
|  | 264 | config = &element; | 
|  | 265 | if (isFan) | 
|  | 266 | { | 
|  | 267 | element["@odata.id"] = | 
|  | 268 | "/redfish/v1/Managers/bmc#/Oem/" | 
|  | 269 | "OpenBmc/Fan/FanControllers/" + | 
|  | 270 | std::string(name); | 
|  | 271 | element["@odata.type"] = | 
|  | 272 | "#OemManager.FanController"; | 
|  | 273 |  | 
|  | 274 | element["@odata.context"] = | 
|  | 275 | "/redfish/v1/" | 
|  | 276 | "$metadata#OemManager.FanController"; | 
|  | 277 | } | 
|  | 278 | else | 
|  | 279 | { | 
|  | 280 | element["@odata.id"] = | 
|  | 281 | "/redfish/v1/Managers/bmc#/Oem/" | 
|  | 282 | "OpenBmc/Fan/PidControllers/" + | 
|  | 283 | std::string(name); | 
|  | 284 | element["@odata.type"] = | 
|  | 285 | "#OemManager.PidController"; | 
|  | 286 | element["@odata.context"] = | 
|  | 287 | "/redfish/v1/$metadata" | 
|  | 288 | "#OemManager.PidController"; | 
|  | 289 | } | 
|  | 290 | } | 
|  | 291 | else | 
|  | 292 | { | 
|  | 293 | BMCWEB_LOG_ERROR << "Unexpected configuration"; | 
|  | 294 | messages::internalError(asyncResp->res); | 
|  | 295 | return; | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | // used for making maps out of 2 vectors | 
|  | 299 | const std::vector<double>* keys = nullptr; | 
|  | 300 | const std::vector<double>* values = nullptr; | 
|  | 301 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 302 | for (const auto& propertyPair : intfPair.second) | 
|  | 303 | { | 
|  | 304 | if (propertyPair.first == "Type" || | 
|  | 305 | propertyPair.first == "Class" || | 
|  | 306 | propertyPair.first == "Name") | 
|  | 307 | { | 
|  | 308 | continue; | 
|  | 309 | } | 
|  | 310 |  | 
|  | 311 | // zones | 
|  | 312 | if (intfPair.first == pidZoneConfigurationIface) | 
|  | 313 | { | 
| Ed Tanous | 1b6b96c | 2018-11-30 11:35:41 -0800 | [diff] [blame] | 314 | const double* ptr = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 315 | std::get_if<double>(&propertyPair.second); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 316 | if (ptr == nullptr) | 
|  | 317 | { | 
|  | 318 | BMCWEB_LOG_ERROR << "Field Illegal " | 
|  | 319 | << propertyPair.first; | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 320 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 321 | return; | 
|  | 322 | } | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 323 | (*config)[propertyPair.first] = *ptr; | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | if (intfPair.first == stepwiseConfigurationIface) | 
|  | 327 | { | 
|  | 328 | if (propertyPair.first == "Reading" || | 
|  | 329 | propertyPair.first == "Output") | 
|  | 330 | { | 
|  | 331 | const std::vector<double>* ptr = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 332 | std::get_if<std::vector<double>>( | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 333 | &propertyPair.second); | 
|  | 334 |  | 
|  | 335 | if (ptr == nullptr) | 
|  | 336 | { | 
|  | 337 | BMCWEB_LOG_ERROR << "Field Illegal " | 
|  | 338 | << propertyPair.first; | 
|  | 339 | messages::internalError(asyncResp->res); | 
|  | 340 | return; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 | if (propertyPair.first == "Reading") | 
|  | 344 | { | 
|  | 345 | keys = ptr; | 
|  | 346 | } | 
|  | 347 | else | 
|  | 348 | { | 
|  | 349 | values = ptr; | 
|  | 350 | } | 
|  | 351 | if (keys && values) | 
|  | 352 | { | 
|  | 353 | if (keys->size() != values->size()) | 
|  | 354 | { | 
|  | 355 | BMCWEB_LOG_ERROR | 
|  | 356 | << "Reading and Output size don't " | 
|  | 357 | "match "; | 
|  | 358 | messages::internalError(asyncResp->res); | 
|  | 359 | return; | 
|  | 360 | } | 
|  | 361 | nlohmann::json& steps = (*config)["Steps"]; | 
|  | 362 | steps = nlohmann::json::array(); | 
|  | 363 | for (size_t ii = 0; ii < keys->size(); ii++) | 
|  | 364 | { | 
|  | 365 | steps.push_back( | 
|  | 366 | {{"Target", (*keys)[ii]}, | 
|  | 367 | {"Output", (*values)[ii]}}); | 
|  | 368 | } | 
|  | 369 | } | 
|  | 370 | } | 
|  | 371 | if (propertyPair.first == "NegativeHysteresis" || | 
|  | 372 | propertyPair.first == "PositiveHysteresis") | 
|  | 373 | { | 
|  | 374 | const double* ptr = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 375 | std::get_if<double>(&propertyPair.second); | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 376 | if (ptr == nullptr) | 
|  | 377 | { | 
|  | 378 | BMCWEB_LOG_ERROR << "Field Illegal " | 
|  | 379 | << propertyPair.first; | 
|  | 380 | messages::internalError(asyncResp->res); | 
|  | 381 | return; | 
|  | 382 | } | 
|  | 383 | (*config)[propertyPair.first] = *ptr; | 
|  | 384 | } | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 385 | } | 
|  | 386 |  | 
|  | 387 | // pid and fans are off the same configuration | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 388 | if (intfPair.first == pidConfigurationIface || | 
|  | 389 | intfPair.first == stepwiseConfigurationIface) | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 390 | { | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 391 |  | 
|  | 392 | if (propertyPair.first == "Zones") | 
|  | 393 | { | 
|  | 394 | const std::vector<std::string>* inputs = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 395 | std::get_if<std::vector<std::string>>( | 
| Ed Tanous | 1b6b96c | 2018-11-30 11:35:41 -0800 | [diff] [blame] | 396 | &propertyPair.second); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 397 |  | 
|  | 398 | if (inputs == nullptr) | 
|  | 399 | { | 
|  | 400 | BMCWEB_LOG_ERROR | 
|  | 401 | << "Zones Pid Field Illegal"; | 
| Jason M. Bills | a08b46c | 2018-11-06 15:01:08 -0800 | [diff] [blame] | 402 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 403 | return; | 
|  | 404 | } | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 405 | auto& data = (*config)[propertyPair.first]; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 406 | data = nlohmann::json::array(); | 
|  | 407 | for (std::string itemCopy : *inputs) | 
|  | 408 | { | 
|  | 409 | dbus::utility::escapePathForDbus(itemCopy); | 
|  | 410 | data.push_back( | 
|  | 411 | {{"@odata.id", | 
|  | 412 | "/redfish/v1/Managers/bmc#/Oem/" | 
|  | 413 | "OpenBmc/Fan/FanZones/" + | 
|  | 414 | itemCopy}}); | 
|  | 415 | } | 
|  | 416 | } | 
|  | 417 | // todo(james): may never happen, but this | 
|  | 418 | // assumes configuration data referenced in the | 
|  | 419 | // PID config is provided by the same daemon, we | 
|  | 420 | // could add another loop to cover all cases, | 
|  | 421 | // but I'm okay kicking this can down the road a | 
|  | 422 | // bit | 
|  | 423 |  | 
|  | 424 | else if (propertyPair.first == "Inputs" || | 
|  | 425 | propertyPair.first == "Outputs") | 
|  | 426 | { | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 427 | auto& data = (*config)[propertyPair.first]; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 428 | const std::vector<std::string>* inputs = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 429 | std::get_if<std::vector<std::string>>( | 
| Ed Tanous | 1b6b96c | 2018-11-30 11:35:41 -0800 | [diff] [blame] | 430 | &propertyPair.second); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 431 |  | 
|  | 432 | if (inputs == nullptr) | 
|  | 433 | { | 
|  | 434 | BMCWEB_LOG_ERROR << "Field Illegal " | 
|  | 435 | << propertyPair.first; | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 436 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 437 | return; | 
|  | 438 | } | 
|  | 439 | data = *inputs; | 
|  | 440 | } // doubles | 
|  | 441 | else if (propertyPair.first == | 
|  | 442 | "FFGainCoefficient" || | 
|  | 443 | propertyPair.first == "FFOffCoefficient" || | 
|  | 444 | propertyPair.first == "ICoefficient" || | 
|  | 445 | propertyPair.first == "ILimitMax" || | 
|  | 446 | propertyPair.first == "ILimitMin" || | 
| James Feist | aad1a25 | 2019-02-19 10:13:52 -0800 | [diff] [blame] | 447 | propertyPair.first == | 
|  | 448 | "PositiveHysteresis" || | 
|  | 449 | propertyPair.first == | 
|  | 450 | "NegativeHysteresis" || | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 451 | propertyPair.first == "OutLimitMax" || | 
|  | 452 | propertyPair.first == "OutLimitMin" || | 
|  | 453 | propertyPair.first == "PCoefficient" || | 
| James Feist | 7625cb8 | 2019-01-23 11:58:21 -0800 | [diff] [blame] | 454 | propertyPair.first == "SetPoint" || | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 455 | propertyPair.first == "SlewNeg" || | 
|  | 456 | propertyPair.first == "SlewPos") | 
|  | 457 | { | 
|  | 458 | const double* ptr = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 459 | std::get_if<double>(&propertyPair.second); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 460 | if (ptr == nullptr) | 
|  | 461 | { | 
|  | 462 | BMCWEB_LOG_ERROR << "Field Illegal " | 
|  | 463 | << propertyPair.first; | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 464 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 465 | return; | 
|  | 466 | } | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 467 | (*config)[propertyPair.first] = *ptr; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 468 | } | 
|  | 469 | } | 
|  | 470 | } | 
|  | 471 | } | 
|  | 472 | } | 
|  | 473 | }, | 
|  | 474 | connection, path, objectManagerIface, "GetManagedObjects"); | 
|  | 475 | } | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 476 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 477 | enum class CreatePIDRet | 
|  | 478 | { | 
|  | 479 | fail, | 
|  | 480 | del, | 
|  | 481 | patch | 
|  | 482 | }; | 
|  | 483 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 484 | static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response, | 
|  | 485 | std::vector<nlohmann::json>& config, | 
|  | 486 | std::vector<std::string>& zones) | 
|  | 487 | { | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 488 | if (config.empty()) | 
|  | 489 | { | 
|  | 490 | BMCWEB_LOG_ERROR << "Empty Zones"; | 
|  | 491 | messages::propertyValueFormatError(response->res, | 
|  | 492 | nlohmann::json::array(), "Zones"); | 
|  | 493 | return false; | 
|  | 494 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 495 | for (auto& odata : config) | 
|  | 496 | { | 
|  | 497 | std::string path; | 
|  | 498 | if (!redfish::json_util::readJson(odata, response->res, "@odata.id", | 
|  | 499 | path)) | 
|  | 500 | { | 
|  | 501 | return false; | 
|  | 502 | } | 
|  | 503 | std::string input; | 
| James Feist | 61adbda | 2019-03-25 13:03:51 -0700 | [diff] [blame] | 504 |  | 
|  | 505 | // 8 below comes from | 
|  | 506 | // /redfish/v1/Managers/bmc#/Oem/OpenBmc/Fan/FanZones/Left | 
|  | 507 | //     0    1     2      3    4    5      6     7      8 | 
|  | 508 | if (!dbus::utility::getNthStringFromPath(path, 8, input)) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 509 | { | 
|  | 510 | BMCWEB_LOG_ERROR << "Got invalid path " << path; | 
|  | 511 | BMCWEB_LOG_ERROR << "Illegal Type Zones"; | 
|  | 512 | messages::propertyValueFormatError(response->res, odata.dump(), | 
|  | 513 | "Zones"); | 
|  | 514 | return false; | 
|  | 515 | } | 
|  | 516 | boost::replace_all(input, "_", " "); | 
|  | 517 | zones.emplace_back(std::move(input)); | 
|  | 518 | } | 
|  | 519 | return true; | 
|  | 520 | } | 
|  | 521 |  | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 522 | static bool findChassis(const dbus::utility::ManagedObjectType& managedObj, | 
|  | 523 | const std::string& value, std::string& chassis) | 
|  | 524 | { | 
|  | 525 | BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n"; | 
|  | 526 |  | 
|  | 527 | std::string escaped = boost::replace_all_copy(value, " ", "_"); | 
|  | 528 | escaped = "/" + escaped; | 
|  | 529 | auto it = std::find_if( | 
|  | 530 | managedObj.begin(), managedObj.end(), [&escaped](const auto& obj) { | 
|  | 531 | if (boost::algorithm::ends_with(obj.first.str, escaped)) | 
|  | 532 | { | 
|  | 533 | BMCWEB_LOG_DEBUG << "Matched " << obj.first.str << "\n"; | 
|  | 534 | return true; | 
|  | 535 | } | 
|  | 536 | return false; | 
|  | 537 | }); | 
|  | 538 |  | 
|  | 539 | if (it == managedObj.end()) | 
|  | 540 | { | 
|  | 541 | return false; | 
|  | 542 | } | 
|  | 543 | // 5 comes from <chassis-name> being the 5th element | 
|  | 544 | // /xyz/openbmc_project/inventory/system/chassis/<chassis-name> | 
|  | 545 | return dbus::utility::getNthStringFromPath(it->first.str, 5, chassis); | 
|  | 546 | } | 
|  | 547 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 548 | static CreatePIDRet createPidInterface( | 
|  | 549 | const std::shared_ptr<AsyncResp>& response, const std::string& type, | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 550 | nlohmann::json::iterator it, const std::string& path, | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 551 | const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, | 
|  | 552 | boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& | 
|  | 553 | output, | 
|  | 554 | std::string& chassis) | 
|  | 555 | { | 
|  | 556 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 557 | // common deleter | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 558 | if (it.value() == nullptr) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 559 | { | 
|  | 560 | std::string iface; | 
|  | 561 | if (type == "PidControllers" || type == "FanControllers") | 
|  | 562 | { | 
|  | 563 | iface = pidConfigurationIface; | 
|  | 564 | } | 
|  | 565 | else if (type == "FanZones") | 
|  | 566 | { | 
|  | 567 | iface = pidZoneConfigurationIface; | 
|  | 568 | } | 
|  | 569 | else if (type == "StepwiseControllers") | 
|  | 570 | { | 
|  | 571 | iface = stepwiseConfigurationIface; | 
|  | 572 | } | 
|  | 573 | else | 
|  | 574 | { | 
|  | 575 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " | 
|  | 576 | << type; | 
|  | 577 | messages::propertyUnknown(response->res, type); | 
|  | 578 | return CreatePIDRet::fail; | 
|  | 579 | } | 
|  | 580 | // delete interface | 
|  | 581 | crow::connections::systemBus->async_method_call( | 
|  | 582 | [response, path](const boost::system::error_code ec) { | 
|  | 583 | if (ec) | 
|  | 584 | { | 
|  | 585 | BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec; | 
|  | 586 | messages::internalError(response->res); | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 587 | return; | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 588 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 589 | messages::success(response->res); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 590 | }, | 
|  | 591 | "xyz.openbmc_project.EntityManager", path, iface, "Delete"); | 
|  | 592 | return CreatePIDRet::del; | 
|  | 593 | } | 
|  | 594 |  | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 595 | if (!createNewObject) | 
|  | 596 | { | 
|  | 597 | // if we aren't creating a new object, we should be able to find it on | 
|  | 598 | // d-bus | 
|  | 599 | if (!findChassis(managedObj, it.key(), chassis)) | 
|  | 600 | { | 
|  | 601 | BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; | 
|  | 602 | messages::invalidObject(response->res, it.key()); | 
|  | 603 | return CreatePIDRet::fail; | 
|  | 604 | } | 
|  | 605 | } | 
|  | 606 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 607 | if (type == "PidControllers" || type == "FanControllers") | 
|  | 608 | { | 
|  | 609 | if (createNewObject) | 
|  | 610 | { | 
|  | 611 | output["Class"] = type == "PidControllers" ? std::string("temp") | 
|  | 612 | : std::string("fan"); | 
|  | 613 | output["Type"] = std::string("Pid"); | 
|  | 614 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 615 |  | 
|  | 616 | std::optional<std::vector<nlohmann::json>> zones; | 
|  | 617 | std::optional<std::vector<std::string>> inputs; | 
|  | 618 | std::optional<std::vector<std::string>> outputs; | 
|  | 619 | std::map<std::string, std::optional<double>> doubles; | 
|  | 620 | if (!redfish::json_util::readJson( | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 621 | it.value(), response->res, "Inputs", inputs, "Outputs", outputs, | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 622 | "Zones", zones, "FFGainCoefficient", | 
|  | 623 | doubles["FFGainCoefficient"], "FFOffCoefficient", | 
|  | 624 | doubles["FFOffCoefficient"], "ICoefficient", | 
|  | 625 | doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], | 
|  | 626 | "ILimitMin", doubles["ILimitMin"], "OutLimitMax", | 
|  | 627 | doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], | 
|  | 628 | "PCoefficient", doubles["PCoefficient"], "SetPoint", | 
|  | 629 | doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos", | 
| James Feist | aad1a25 | 2019-02-19 10:13:52 -0800 | [diff] [blame] | 630 | doubles["SlewPos"], "PositiveHysteresis", | 
|  | 631 | doubles["PositiveHysteresis"], "NegativeHysteresis", | 
|  | 632 | doubles["NegativeHysteresis"])) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 633 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 634 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 635 | << it.value().dump(); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 636 | return CreatePIDRet::fail; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 637 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 638 | if (zones) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 639 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 640 | std::vector<std::string> zonesStr; | 
|  | 641 | if (!getZonesFromJsonReq(response, *zones, zonesStr)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 642 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 643 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; | 
|  | 644 | return CreatePIDRet::fail; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 645 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 646 | if (chassis.empty() && | 
|  | 647 | !findChassis(managedObj, zonesStr[0], chassis)) | 
|  | 648 | { | 
|  | 649 | BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; | 
|  | 650 | messages::invalidObject(response->res, it.key()); | 
|  | 651 | return CreatePIDRet::fail; | 
|  | 652 | } | 
|  | 653 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 654 | output["Zones"] = std::move(zonesStr); | 
|  | 655 | } | 
|  | 656 | if (inputs || outputs) | 
|  | 657 | { | 
|  | 658 | std::array<std::optional<std::vector<std::string>>*, 2> containers = | 
|  | 659 | {&inputs, &outputs}; | 
|  | 660 | size_t index = 0; | 
|  | 661 | for (const auto& containerPtr : containers) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 662 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 663 | std::optional<std::vector<std::string>>& container = | 
|  | 664 | *containerPtr; | 
|  | 665 | if (!container) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 666 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 667 | index++; | 
|  | 668 | continue; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 669 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 670 |  | 
|  | 671 | for (std::string& value : *container) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 672 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 673 | boost::replace_all(value, "_", " "); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 674 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 675 | std::string key; | 
|  | 676 | if (index == 0) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 677 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 678 | key = "Inputs"; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 679 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 680 | else | 
|  | 681 | { | 
|  | 682 | key = "Outputs"; | 
|  | 683 | } | 
|  | 684 | output[key] = *container; | 
|  | 685 | index++; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 686 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 687 | } | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 688 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 689 | // doubles | 
|  | 690 | for (const auto& pairs : doubles) | 
|  | 691 | { | 
|  | 692 | if (!pairs.second) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 693 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 694 | continue; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 695 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 696 | BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second; | 
|  | 697 | output[pairs.first] = *(pairs.second); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 698 | } | 
|  | 699 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 700 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 701 | else if (type == "FanZones") | 
|  | 702 | { | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 703 | output["Type"] = std::string("Pid.Zone"); | 
|  | 704 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 705 | std::optional<nlohmann::json> chassisContainer; | 
|  | 706 | std::optional<double> failSafePercent; | 
| James Feist | d3ec07f | 2019-02-25 14:51:15 -0800 | [diff] [blame] | 707 | std::optional<double> minThermalOutput; | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 708 | if (!redfish::json_util::readJson(it.value(), response->res, "Chassis", | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 709 | chassisContainer, "FailSafePercent", | 
| James Feist | d3ec07f | 2019-02-25 14:51:15 -0800 | [diff] [blame] | 710 | failSafePercent, "MinThermalOutput", | 
|  | 711 | minThermalOutput)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 712 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 713 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 714 | << it.value().dump(); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 715 | return CreatePIDRet::fail; | 
|  | 716 | } | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 717 |  | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 718 | if (chassisContainer) | 
|  | 719 | { | 
|  | 720 |  | 
|  | 721 | std::string chassisId; | 
|  | 722 | if (!redfish::json_util::readJson(*chassisContainer, response->res, | 
|  | 723 | "@odata.id", chassisId)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 724 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 725 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " | 
|  | 726 | << chassisContainer->dump(); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 727 | return CreatePIDRet::fail; | 
|  | 728 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 729 |  | 
|  | 730 | // /refish/v1/chassis/chassis_name/ | 
|  | 731 | if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis)) | 
|  | 732 | { | 
|  | 733 | BMCWEB_LOG_ERROR << "Got invalid path " << chassisId; | 
|  | 734 | messages::invalidObject(response->res, chassisId); | 
|  | 735 | return CreatePIDRet::fail; | 
|  | 736 | } | 
|  | 737 | } | 
| James Feist | d3ec07f | 2019-02-25 14:51:15 -0800 | [diff] [blame] | 738 | if (minThermalOutput) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 739 | { | 
| James Feist | d3ec07f | 2019-02-25 14:51:15 -0800 | [diff] [blame] | 740 | output["MinThermalOutput"] = *minThermalOutput; | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 741 | } | 
|  | 742 | if (failSafePercent) | 
|  | 743 | { | 
|  | 744 | output["FailSafePercent"] = *failSafePercent; | 
|  | 745 | } | 
|  | 746 | } | 
|  | 747 | else if (type == "StepwiseControllers") | 
|  | 748 | { | 
|  | 749 | output["Type"] = std::string("Stepwise"); | 
|  | 750 |  | 
|  | 751 | std::optional<std::vector<nlohmann::json>> zones; | 
|  | 752 | std::optional<std::vector<nlohmann::json>> steps; | 
|  | 753 | std::optional<std::vector<std::string>> inputs; | 
|  | 754 | std::optional<double> positiveHysteresis; | 
|  | 755 | std::optional<double> negativeHysteresis; | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 756 | std::optional<std::string> direction; // upper clipping curve vs lower | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 757 | if (!redfish::json_util::readJson( | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 758 | it.value(), response->res, "Zones", zones, "Steps", steps, | 
|  | 759 | "Inputs", inputs, "PositiveHysteresis", positiveHysteresis, | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 760 | "NegativeHysteresis", negativeHysteresis, "Direction", | 
|  | 761 | direction)) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 762 | { | 
|  | 763 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 764 | << it.value().dump(); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 765 | return CreatePIDRet::fail; | 
|  | 766 | } | 
|  | 767 |  | 
|  | 768 | if (zones) | 
|  | 769 | { | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 770 | std::vector<std::string> zonesStrs; | 
|  | 771 | if (!getZonesFromJsonReq(response, *zones, zonesStrs)) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 772 | { | 
|  | 773 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; | 
|  | 774 | return CreatePIDRet::fail; | 
|  | 775 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 776 | if (chassis.empty() && | 
|  | 777 | !findChassis(managedObj, zonesStrs[0], chassis)) | 
|  | 778 | { | 
|  | 779 | BMCWEB_LOG_ERROR << "Failed to get chassis from config patch"; | 
|  | 780 | messages::invalidObject(response->res, it.key()); | 
|  | 781 | return CreatePIDRet::fail; | 
|  | 782 | } | 
|  | 783 | output["Zones"] = std::move(zonesStrs); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 784 | } | 
|  | 785 | if (steps) | 
|  | 786 | { | 
|  | 787 | std::vector<double> readings; | 
|  | 788 | std::vector<double> outputs; | 
|  | 789 | for (auto& step : *steps) | 
|  | 790 | { | 
|  | 791 | double target; | 
| Ed Tanous | b01bf29 | 2019-03-25 19:25:26 +0000 | [diff] [blame] | 792 | double output; | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 793 |  | 
|  | 794 | if (!redfish::json_util::readJson(step, response->res, "Target", | 
| Ed Tanous | b01bf29 | 2019-03-25 19:25:26 +0000 | [diff] [blame] | 795 | target, "Output", output)) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 796 | { | 
|  | 797 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 798 | << ", Illegal Property " | 
|  | 799 | << it.value().dump(); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 800 | return CreatePIDRet::fail; | 
|  | 801 | } | 
|  | 802 | readings.emplace_back(target); | 
| Ed Tanous | b01bf29 | 2019-03-25 19:25:26 +0000 | [diff] [blame] | 803 | outputs.emplace_back(output); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 804 | } | 
|  | 805 | output["Reading"] = std::move(readings); | 
|  | 806 | output["Output"] = std::move(outputs); | 
|  | 807 | } | 
|  | 808 | if (inputs) | 
|  | 809 | { | 
|  | 810 | for (std::string& value : *inputs) | 
|  | 811 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 812 | boost::replace_all(value, "_", " "); | 
|  | 813 | } | 
|  | 814 | output["Inputs"] = std::move(*inputs); | 
|  | 815 | } | 
|  | 816 | if (negativeHysteresis) | 
|  | 817 | { | 
|  | 818 | output["NegativeHysteresis"] = *negativeHysteresis; | 
|  | 819 | } | 
|  | 820 | if (positiveHysteresis) | 
|  | 821 | { | 
|  | 822 | output["PositiveHysteresis"] = *positiveHysteresis; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 823 | } | 
| James Feist | c33a90e | 2019-03-01 10:17:44 -0800 | [diff] [blame] | 824 | if (direction) | 
|  | 825 | { | 
|  | 826 | constexpr const std::array<const char*, 2> allowedDirections = { | 
|  | 827 | "Ceiling", "Floor"}; | 
|  | 828 | if (std::find(allowedDirections.begin(), allowedDirections.end(), | 
|  | 829 | *direction) == allowedDirections.end()) | 
|  | 830 | { | 
|  | 831 | messages::propertyValueTypeError(response->res, "Direction", | 
|  | 832 | *direction); | 
|  | 833 | return CreatePIDRet::fail; | 
|  | 834 | } | 
|  | 835 | output["Class"] = *direction; | 
|  | 836 | } | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 837 | } | 
|  | 838 | else | 
|  | 839 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 840 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 841 | messages::propertyUnknown(response->res, type); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 842 | return CreatePIDRet::fail; | 
|  | 843 | } | 
|  | 844 | return CreatePIDRet::patch; | 
|  | 845 | } | 
|  | 846 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 847 | class Manager : public Node | 
|  | 848 | { | 
|  | 849 | public: | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 850 | Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/bmc/") | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 851 | { | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 852 | uuid = app.template getMiddleware<crow::persistent_data::Middleware>() | 
|  | 853 | .systemUuid; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 854 | entityPrivileges = { | 
|  | 855 | {boost::beast::http::verb::get, {{"Login"}}}, | 
|  | 856 | {boost::beast::http::verb::head, {{"Login"}}}, | 
|  | 857 | {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, | 
|  | 858 | {boost::beast::http::verb::put, {{"ConfigureManager"}}}, | 
|  | 859 | {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, | 
|  | 860 | {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; | 
| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 861 | } | 
|  | 862 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 863 | private: | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 864 | void getPidValues(std::shared_ptr<AsyncResp> asyncResp) | 
|  | 865 | { | 
|  | 866 | crow::connections::systemBus->async_method_call( | 
|  | 867 | [asyncResp](const boost::system::error_code ec, | 
|  | 868 | const crow::openbmc_mapper::GetSubTreeType& subtree) { | 
|  | 869 | if (ec) | 
|  | 870 | { | 
|  | 871 | BMCWEB_LOG_ERROR << ec; | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 872 | messages::internalError(asyncResp->res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 873 | return; | 
|  | 874 | } | 
|  | 875 |  | 
|  | 876 | // create map of <connection, path to objMgr>> | 
|  | 877 | boost::container::flat_map<std::string, std::string> | 
|  | 878 | objectMgrPaths; | 
| James Feist | 6bce33b | 2018-10-22 12:05:56 -0700 | [diff] [blame] | 879 | boost::container::flat_set<std::string> calledConnections; | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 880 | for (const auto& pathGroup : subtree) | 
|  | 881 | { | 
|  | 882 | for (const auto& connectionGroup : pathGroup.second) | 
|  | 883 | { | 
| James Feist | 6bce33b | 2018-10-22 12:05:56 -0700 | [diff] [blame] | 884 | auto findConnection = | 
|  | 885 | calledConnections.find(connectionGroup.first); | 
|  | 886 | if (findConnection != calledConnections.end()) | 
|  | 887 | { | 
|  | 888 | break; | 
|  | 889 | } | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 890 | for (const std::string& interface : | 
|  | 891 | connectionGroup.second) | 
|  | 892 | { | 
|  | 893 | if (interface == objectManagerIface) | 
|  | 894 | { | 
|  | 895 | objectMgrPaths[connectionGroup.first] = | 
|  | 896 | pathGroup.first; | 
|  | 897 | } | 
|  | 898 | // this list is alphabetical, so we | 
|  | 899 | // should have found the objMgr by now | 
|  | 900 | if (interface == pidConfigurationIface || | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 901 | interface == pidZoneConfigurationIface || | 
|  | 902 | interface == stepwiseConfigurationIface) | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 903 | { | 
|  | 904 | auto findObjMgr = | 
|  | 905 | objectMgrPaths.find(connectionGroup.first); | 
|  | 906 | if (findObjMgr == objectMgrPaths.end()) | 
|  | 907 | { | 
|  | 908 | BMCWEB_LOG_DEBUG << connectionGroup.first | 
|  | 909 | << "Has no Object Manager"; | 
|  | 910 | continue; | 
|  | 911 | } | 
| James Feist | 6bce33b | 2018-10-22 12:05:56 -0700 | [diff] [blame] | 912 |  | 
|  | 913 | calledConnections.insert(connectionGroup.first); | 
|  | 914 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 915 | asyncPopulatePid(findObjMgr->first, | 
|  | 916 | findObjMgr->second, asyncResp); | 
|  | 917 | break; | 
|  | 918 | } | 
|  | 919 | } | 
|  | 920 | } | 
|  | 921 | } | 
|  | 922 | }, | 
|  | 923 | "xyz.openbmc_project.ObjectMapper", | 
|  | 924 | "/xyz/openbmc_project/object_mapper", | 
|  | 925 | "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0, | 
| James Feist | b7a08d0 | 2018-12-11 14:55:37 -0800 | [diff] [blame] | 926 | std::array<const char*, 4>{ | 
|  | 927 | pidConfigurationIface, pidZoneConfigurationIface, | 
|  | 928 | objectManagerIface, stepwiseConfigurationIface}); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 929 | } | 
|  | 930 |  | 
|  | 931 | void doGet(crow::Response& res, const crow::Request& req, | 
|  | 932 | const std::vector<std::string>& params) override | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 933 | { | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 934 | res.jsonValue["@odata.id"] = "/redfish/v1/Managers/bmc"; | 
|  | 935 | res.jsonValue["@odata.type"] = "#Manager.v1_3_0.Manager"; | 
|  | 936 | res.jsonValue["@odata.context"] = | 
|  | 937 | "/redfish/v1/$metadata#Manager.Manager"; | 
|  | 938 | res.jsonValue["Id"] = "bmc"; | 
|  | 939 | res.jsonValue["Name"] = "OpenBmc Manager"; | 
|  | 940 | res.jsonValue["Description"] = "Baseboard Management Controller"; | 
|  | 941 | res.jsonValue["PowerState"] = "On"; | 
| Ed Tanous | 029573d | 2019-02-01 10:57:49 -0800 | [diff] [blame] | 942 | res.jsonValue["Status"] = {{"State", "Enabled"}, {"Health", "OK"}}; | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 943 | res.jsonValue["ManagerType"] = "BMC"; | 
| Ed Tanous | 7517658 | 2018-12-14 08:14:34 -0800 | [diff] [blame] | 944 | res.jsonValue["UUID"] = uuid; | 
|  | 945 | res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 946 |  | 
|  | 947 | res.jsonValue["LogServices"] = { | 
|  | 948 | {"@odata.id", "/redfish/v1/Managers/bmc/LogServices"}}; | 
|  | 949 |  | 
|  | 950 | res.jsonValue["NetworkProtocol"] = { | 
|  | 951 | {"@odata.id", "/redfish/v1/Managers/bmc/NetworkProtocol"}}; | 
|  | 952 |  | 
|  | 953 | res.jsonValue["EthernetInterfaces"] = { | 
|  | 954 | {"@odata.id", "/redfish/v1/Managers/bmc/EthernetInterfaces"}}; | 
|  | 955 | // default oem data | 
|  | 956 | nlohmann::json& oem = res.jsonValue["Oem"]; | 
|  | 957 | nlohmann::json& oemOpenbmc = oem["OpenBmc"]; | 
|  | 958 | oem["@odata.type"] = "#OemManager.Oem"; | 
|  | 959 | oem["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem"; | 
|  | 960 | oem["@odata.context"] = "/redfish/v1/$metadata#OemManager.Oem"; | 
|  | 961 | oemOpenbmc["@odata.type"] = "#OemManager.OpenBmc"; | 
|  | 962 | oemOpenbmc["@odata.id"] = "/redfish/v1/Managers/bmc#/Oem/OpenBmc"; | 
|  | 963 | oemOpenbmc["@odata.context"] = | 
|  | 964 | "/redfish/v1/$metadata#OemManager.OpenBmc"; | 
|  | 965 |  | 
| Jennifer Lee | ed5befb | 2018-08-10 11:29:45 -0700 | [diff] [blame] | 966 | // Update Actions object. | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 967 | nlohmann::json& manager_reset = | 
|  | 968 | res.jsonValue["Actions"]["#Manager.Reset"]; | 
| Jennifer Lee | ed5befb | 2018-08-10 11:29:45 -0700 | [diff] [blame] | 969 | manager_reset["target"] = | 
|  | 970 | "/redfish/v1/Managers/bmc/Actions/Manager.Reset"; | 
|  | 971 | manager_reset["ResetType@Redfish.AllowableValues"] = { | 
|  | 972 | "GracefulRestart"}; | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 973 |  | 
| Andrew Geissler | cb92c03 | 2018-08-17 07:56:14 -0700 | [diff] [blame^] | 974 | res.jsonValue["DateTime"] = crow::utility::dateTimeNow(); | 
| Gunnar Mills | 603a664 | 2019-01-21 17:03:51 -0600 | [diff] [blame] | 975 | res.jsonValue["Links"]["ManagerForServers@odata.count"] = 1; | 
|  | 976 | res.jsonValue["Links"]["ManagerForServers"] = { | 
|  | 977 | {{"@odata.id", "/redfish/v1/Systems/system"}}}; | 
|  | 978 | #ifdef BMCWEB_ENABLE_REDFISH_ONE_CHASSIS | 
|  | 979 | res.jsonValue["Links"]["ManagerForChassis@odata.count"] = 1; | 
|  | 980 | res.jsonValue["Links"]["ManagerForChassis"] = { | 
|  | 981 | {{"@odata.id", "/redfish/v1/Chassis/chassis"}}}; | 
|  | 982 | #endif | 
| Jennifer Lee | ed5befb | 2018-08-10 11:29:45 -0700 | [diff] [blame] | 983 | std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 984 |  | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 985 | crow::connections::systemBus->async_method_call( | 
|  | 986 | [asyncResp](const boost::system::error_code ec, | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 987 | const dbus::utility::ManagedObjectType& resp) { | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 988 | if (ec) | 
|  | 989 | { | 
|  | 990 | BMCWEB_LOG_ERROR << "Error while getting Software Version"; | 
| Jason M. Bills | f12894f | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 991 | messages::internalError(asyncResp->res); | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 992 | return; | 
|  | 993 | } | 
|  | 994 |  | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 995 | for (auto& objpath : resp) | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 996 | { | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 997 | for (auto& interface : objpath.second) | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 998 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 999 | // If interface is | 
|  | 1000 | // xyz.openbmc_project.Software.Version, this is | 
|  | 1001 | // what we're looking for. | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 1002 | if (interface.first == | 
|  | 1003 | "xyz.openbmc_project.Software.Version") | 
|  | 1004 | { | 
|  | 1005 | // Cut out everyting until last "/", ... | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1006 | for (auto& property : interface.second) | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 1007 | { | 
|  | 1008 | if (property.first == "Version") | 
|  | 1009 | { | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1010 | const std::string* value = | 
| Ed Tanous | abf2add | 2019-01-22 16:40:12 -0800 | [diff] [blame] | 1011 | std::get_if<std::string>( | 
|  | 1012 | &property.second); | 
| Jennifer Lee | ca53792 | 2018-08-10 10:07:30 -0700 | [diff] [blame] | 1013 | if (value == nullptr) | 
|  | 1014 | { | 
|  | 1015 | continue; | 
|  | 1016 | } | 
|  | 1017 | asyncResp->res | 
|  | 1018 | .jsonValue["FirmwareVersion"] = *value; | 
|  | 1019 | } | 
|  | 1020 | } | 
|  | 1021 | } | 
|  | 1022 | } | 
|  | 1023 | } | 
|  | 1024 | }, | 
|  | 1025 | "xyz.openbmc_project.Software.BMC.Updater", | 
|  | 1026 | "/xyz/openbmc_project/software", | 
|  | 1027 | "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1028 | getPidValues(asyncResp); | 
|  | 1029 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1030 | void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1031 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1032 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1033 | // todo(james): might make sense to do a mapper call here if this | 
|  | 1034 | // interface gets more traction | 
|  | 1035 | crow::connections::systemBus->async_method_call( | 
|  | 1036 | [response, | 
|  | 1037 | data](const boost::system::error_code ec, | 
|  | 1038 | const dbus::utility::ManagedObjectType& managedObj) { | 
|  | 1039 | if (ec) | 
|  | 1040 | { | 
|  | 1041 | BMCWEB_LOG_ERROR << "Error communicating to Entity Manager"; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 1042 | messages::internalError(response->res); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1043 | return; | 
|  | 1044 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1045 |  | 
|  | 1046 | // todo(james) mutable doesn't work with asio bindings | 
|  | 1047 | nlohmann::json jsonData = data; | 
|  | 1048 |  | 
|  | 1049 | std::optional<nlohmann::json> pidControllers; | 
|  | 1050 | std::optional<nlohmann::json> fanControllers; | 
|  | 1051 | std::optional<nlohmann::json> fanZones; | 
|  | 1052 | std::optional<nlohmann::json> stepwiseControllers; | 
|  | 1053 | if (!redfish::json_util::readJson( | 
|  | 1054 | jsonData, response->res, "PidControllers", | 
|  | 1055 | pidControllers, "FanControllers", fanControllers, | 
|  | 1056 | "FanZones", fanZones, "StepwiseControllers", | 
|  | 1057 | stepwiseControllers)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1058 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1059 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ | 
|  | 1060 | << ", Illegal Property " | 
|  | 1061 | << jsonData.dump(); | 
|  | 1062 | return; | 
|  | 1063 | } | 
|  | 1064 | std::array< | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1065 | std::pair<std::string, std::optional<nlohmann::json>*>, 4> | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1066 | sections = { | 
|  | 1067 | std::make_pair("PidControllers", &pidControllers), | 
|  | 1068 | std::make_pair("FanControllers", &fanControllers), | 
|  | 1069 | std::make_pair("FanZones", &fanZones), | 
|  | 1070 | std::make_pair("StepwiseControllers", | 
|  | 1071 | &stepwiseControllers)}; | 
|  | 1072 |  | 
|  | 1073 | for (auto& containerPair : sections) | 
|  | 1074 | { | 
|  | 1075 | auto& container = *(containerPair.second); | 
|  | 1076 | if (!container) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1077 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1078 | continue; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1079 | } | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1080 | std::string& type = containerPair.first; | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1081 |  | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1082 | for (nlohmann::json::iterator it = container->begin(); | 
|  | 1083 | it != container->end(); it++) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1084 | { | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1085 | const auto& name = it.key(); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1086 | auto pathItr = | 
|  | 1087 | std::find_if(managedObj.begin(), managedObj.end(), | 
|  | 1088 | [&name](const auto& obj) { | 
|  | 1089 | return boost::algorithm::ends_with( | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1090 | obj.first.str, "/" + name); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1091 | }); | 
|  | 1092 | boost::container::flat_map< | 
|  | 1093 | std::string, dbus::utility::DbusVariantType> | 
|  | 1094 | output; | 
|  | 1095 |  | 
|  | 1096 | output.reserve(16); // The pid interface length | 
|  | 1097 |  | 
|  | 1098 | // determines if we're patching entity-manager or | 
|  | 1099 | // creating a new object | 
|  | 1100 | bool createNewObject = (pathItr == managedObj.end()); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1101 | std::string iface; | 
|  | 1102 | if (type == "PidControllers" || | 
|  | 1103 | type == "FanControllers") | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1104 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1105 | iface = pidConfigurationIface; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1106 | if (!createNewObject && | 
|  | 1107 | pathItr->second.find(pidConfigurationIface) == | 
|  | 1108 | pathItr->second.end()) | 
|  | 1109 | { | 
|  | 1110 | createNewObject = true; | 
|  | 1111 | } | 
|  | 1112 | } | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1113 | else if (type == "FanZones") | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1114 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1115 | iface = pidZoneConfigurationIface; | 
|  | 1116 | if (!createNewObject && | 
|  | 1117 | pathItr->second.find( | 
|  | 1118 | pidZoneConfigurationIface) == | 
|  | 1119 | pathItr->second.end()) | 
|  | 1120 | { | 
|  | 1121 |  | 
|  | 1122 | createNewObject = true; | 
|  | 1123 | } | 
|  | 1124 | } | 
|  | 1125 | else if (type == "StepwiseControllers") | 
|  | 1126 | { | 
|  | 1127 | iface = stepwiseConfigurationIface; | 
|  | 1128 | if (!createNewObject && | 
|  | 1129 | pathItr->second.find( | 
|  | 1130 | stepwiseConfigurationIface) == | 
|  | 1131 | pathItr->second.end()) | 
|  | 1132 | { | 
|  | 1133 | createNewObject = true; | 
|  | 1134 | } | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1135 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1136 | BMCWEB_LOG_DEBUG << "Create new = " << createNewObject | 
|  | 1137 | << "\n"; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1138 | output["Name"] = | 
|  | 1139 | boost::replace_all_copy(name, "_", " "); | 
|  | 1140 |  | 
|  | 1141 | std::string chassis; | 
|  | 1142 | CreatePIDRet ret = createPidInterface( | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1143 | response, type, it, pathItr->first.str, managedObj, | 
|  | 1144 | createNewObject, output, chassis); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1145 | if (ret == CreatePIDRet::fail) | 
|  | 1146 | { | 
|  | 1147 | return; | 
|  | 1148 | } | 
|  | 1149 | else if (ret == CreatePIDRet::del) | 
|  | 1150 | { | 
|  | 1151 | continue; | 
|  | 1152 | } | 
|  | 1153 |  | 
|  | 1154 | if (!createNewObject) | 
|  | 1155 | { | 
|  | 1156 | for (const auto& property : output) | 
|  | 1157 | { | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1158 | crow::connections::systemBus->async_method_call( | 
|  | 1159 | [response, | 
|  | 1160 | propertyName{std::string(property.first)}]( | 
|  | 1161 | const boost::system::error_code ec) { | 
|  | 1162 | if (ec) | 
|  | 1163 | { | 
|  | 1164 | BMCWEB_LOG_ERROR | 
|  | 1165 | << "Error patching " | 
|  | 1166 | << propertyName << ": " << ec; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 1167 | messages::internalError( | 
|  | 1168 | response->res); | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1169 | return; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1170 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1171 | messages::success(response->res); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1172 | }, | 
|  | 1173 | "xyz.openbmc_project.EntityManager", | 
|  | 1174 | pathItr->first.str, | 
|  | 1175 | "org.freedesktop.DBus.Properties", "Set", | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1176 | iface, property.first, property.second); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1177 | } | 
|  | 1178 | } | 
|  | 1179 | else | 
|  | 1180 | { | 
|  | 1181 | if (chassis.empty()) | 
|  | 1182 | { | 
|  | 1183 | BMCWEB_LOG_ERROR | 
|  | 1184 | << "Failed to get chassis from config"; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 1185 | messages::invalidObject(response->res, name); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1186 | return; | 
|  | 1187 | } | 
|  | 1188 |  | 
|  | 1189 | bool foundChassis = false; | 
|  | 1190 | for (const auto& obj : managedObj) | 
|  | 1191 | { | 
|  | 1192 | if (boost::algorithm::ends_with(obj.first.str, | 
|  | 1193 | chassis)) | 
|  | 1194 | { | 
|  | 1195 | chassis = obj.first.str; | 
|  | 1196 | foundChassis = true; | 
|  | 1197 | break; | 
|  | 1198 | } | 
|  | 1199 | } | 
|  | 1200 | if (!foundChassis) | 
|  | 1201 | { | 
|  | 1202 | BMCWEB_LOG_ERROR | 
|  | 1203 | << "Failed to find chassis on dbus"; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 1204 | messages::resourceMissingAtURI( | 
|  | 1205 | response->res, | 
|  | 1206 | "/redfish/v1/Chassis/" + chassis); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1207 | return; | 
|  | 1208 | } | 
|  | 1209 |  | 
|  | 1210 | crow::connections::systemBus->async_method_call( | 
|  | 1211 | [response](const boost::system::error_code ec) { | 
|  | 1212 | if (ec) | 
|  | 1213 | { | 
|  | 1214 | BMCWEB_LOG_ERROR | 
|  | 1215 | << "Error Adding Pid Object " << ec; | 
| Jason M. Bills | 35a62c7 | 2018-10-09 12:45:45 -0700 | [diff] [blame] | 1216 | messages::internalError(response->res); | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1217 | return; | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1218 | } | 
| James Feist | b6baeaa | 2019-02-21 10:41:40 -0800 | [diff] [blame] | 1219 | messages::success(response->res); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1220 | }, | 
|  | 1221 | "xyz.openbmc_project.EntityManager", chassis, | 
|  | 1222 | "xyz.openbmc_project.AddObject", "AddObject", | 
|  | 1223 | output); | 
|  | 1224 | } | 
|  | 1225 | } | 
|  | 1226 | } | 
|  | 1227 | }, | 
|  | 1228 | "xyz.openbmc_project.EntityManager", "/", objectManagerIface, | 
|  | 1229 | "GetManagedObjects"); | 
|  | 1230 | } | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1231 |  | 
|  | 1232 | void doPatch(crow::Response& res, const crow::Request& req, | 
|  | 1233 | const std::vector<std::string>& params) override | 
|  | 1234 | { | 
| Ed Tanous | 0627a2c | 2018-11-29 17:09:23 -0800 | [diff] [blame] | 1235 | std::optional<nlohmann::json> oem; | 
|  | 1236 |  | 
|  | 1237 | if (!json_util::readJson(req, res, "Oem", oem)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1238 | { | 
|  | 1239 | return; | 
|  | 1240 | } | 
| Ed Tanous | 0627a2c | 2018-11-29 17:09:23 -0800 | [diff] [blame] | 1241 |  | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1242 | std::shared_ptr<AsyncResp> response = std::make_shared<AsyncResp>(res); | 
| Ed Tanous | 0627a2c | 2018-11-29 17:09:23 -0800 | [diff] [blame] | 1243 |  | 
|  | 1244 | if (oem) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1245 | { | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1246 | std::optional<nlohmann::json> openbmc; | 
|  | 1247 | if (!redfish::json_util::readJson(*oem, res, "OpenBmc", openbmc)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1248 | { | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1249 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " | 
|  | 1250 | << oem->dump(); | 
|  | 1251 | return; | 
|  | 1252 | } | 
|  | 1253 | if (openbmc) | 
|  | 1254 | { | 
|  | 1255 | std::optional<nlohmann::json> fan; | 
|  | 1256 | if (!redfish::json_util::readJson(*openbmc, res, "Fan", fan)) | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1257 | { | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1258 | BMCWEB_LOG_ERROR << "Line:" << __LINE__ | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1259 | << ", Illegal Property " | 
|  | 1260 | << openbmc->dump(); | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1261 | return; | 
|  | 1262 | } | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1263 | if (fan) | 
| James Feist | 5f2caae | 2018-12-12 14:08:25 -0800 | [diff] [blame] | 1264 | { | 
| Ed Tanous | 43b761d | 2019-02-13 20:10:56 -0800 | [diff] [blame] | 1265 | setPidValues(response, *fan); | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1266 | } | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1267 | } | 
|  | 1268 | } | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1269 | } | 
|  | 1270 |  | 
| Ed Tanous | 0f74e64 | 2018-11-12 15:17:05 -0800 | [diff] [blame] | 1271 | std::string uuid; | 
| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 1272 | }; | 
|  | 1273 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1274 | class ManagerCollection : public Node | 
|  | 1275 | { | 
|  | 1276 | public: | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1277 | ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1278 | { | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1279 | entityPrivileges = { | 
|  | 1280 | {boost::beast::http::verb::get, {{"Login"}}}, | 
|  | 1281 | {boost::beast::http::verb::head, {{"Login"}}}, | 
|  | 1282 | {boost::beast::http::verb::patch, {{"ConfigureManager"}}}, | 
|  | 1283 | {boost::beast::http::verb::put, {{"ConfigureManager"}}}, | 
|  | 1284 | {boost::beast::http::verb::delete_, {{"ConfigureManager"}}}, | 
|  | 1285 | {boost::beast::http::verb::post, {{"ConfigureManager"}}}}; | 
|  | 1286 | } | 
| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 1287 |  | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1288 | private: | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1289 | void doGet(crow::Response& res, const crow::Request& req, | 
|  | 1290 | const std::vector<std::string>& params) override | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1291 | { | 
| James Feist | 83ff9ab | 2018-08-31 10:18:24 -0700 | [diff] [blame] | 1292 | // Collections don't include the static data added by SubRoute | 
|  | 1293 | // because it has a duplicate entry for members | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1294 | res.jsonValue["@odata.id"] = "/redfish/v1/Managers"; | 
|  | 1295 | res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection"; | 
|  | 1296 | res.jsonValue["@odata.context"] = | 
|  | 1297 | "/redfish/v1/$metadata#ManagerCollection.ManagerCollection"; | 
|  | 1298 | res.jsonValue["Name"] = "Manager Collection"; | 
|  | 1299 | res.jsonValue["Members@odata.count"] = 1; | 
|  | 1300 | res.jsonValue["Members"] = { | 
| James Feist | 5b4aa86 | 2018-08-16 14:07:01 -0700 | [diff] [blame] | 1301 | {{"@odata.id", "/redfish/v1/Managers/bmc"}}}; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1302 | res.end(); | 
|  | 1303 | } | 
| Borawski.Lukasz | 9c310685 | 2018-02-09 15:24:22 +0100 | [diff] [blame] | 1304 | }; | 
| Ed Tanous | 1abe55e | 2018-09-05 08:30:59 -0700 | [diff] [blame] | 1305 | } // namespace redfish |