blob: f11d7e8d8d78b169ac624793e2950c13c69ad9e7 [file] [log] [blame]
Ed Tanous2474adf2018-09-05 16:31:16 -07001/*
2// Copyright (c) 2018 Intel Corporation
3// Copyright (c) 2018 Ampere Computing LLC
4/
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16*/
17#pragma once
18
19#include "node.hpp"
20#include "sensors.hpp"
21
22namespace redfish
23{
24
25class Power : public Node
26{
27 public:
28 Power(CrowApp& app) :
29 Node((app), "/redfish/v1/Chassis/<str>/Power/", std::string())
30 {
Ed Tanous2474adf2018-09-05 16:31:16 -070031 entityPrivileges = {
32 {boost::beast::http::verb::get, {{"Login"}}},
33 {boost::beast::http::verb::head, {{"Login"}}},
jayaprakash Mutyala1b1b43f2020-03-28 22:56:06 +000034 {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
Ed Tanous2474adf2018-09-05 16:31:16 -070035 {boost::beast::http::verb::put, {{"ConfigureManager"}}},
36 {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
37 {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
38 }
39
40 private:
Ed Tanous85e14242019-06-27 15:04:09 -070041 std::vector<const char*> typeList = {"/xyz/openbmc_project/sensors/voltage",
42 "/xyz/openbmc_project/sensors/power"};
Carol Wang4bb3dc32019-10-17 18:15:02 +080043 void setPowerCapOverride(
44 std::shared_ptr<SensorsAsyncResp> asyncResp,
45 std::vector<nlohmann::json>& powerControlCollections)
46 {
47 auto getChassisPath =
48 [asyncResp, powerControlCollections](
49 const std::optional<std::string>& chassisPath) mutable {
50 if (!chassisPath)
51 {
52 BMCWEB_LOG_ERROR << "Don't find valid chassis path ";
53 messages::resourceNotFound(asyncResp->res, "Chassis",
54 asyncResp->chassisId);
55 return;
56 }
57
58 if (powerControlCollections.size() != 1)
59 {
60 BMCWEB_LOG_ERROR
61 << "Don't support multiple hosts at present ";
62 messages::resourceNotFound(asyncResp->res, "Power",
63 "PowerControl");
64 return;
65 }
66
67 auto& item = powerControlCollections[0];
68
69 std::optional<nlohmann::json> powerLimit;
70 if (!json_util::readJson(item, asyncResp->res, "PowerLimit",
71 powerLimit))
72 {
73 return;
74 }
75 if (!powerLimit)
76 {
77 return;
78 }
79 std::optional<uint32_t> value;
80 if (!json_util::readJson(*powerLimit, asyncResp->res,
81 "LimitInWatts", value))
82 {
83 return;
84 }
85 if (!value)
86 {
87 return;
88 }
89 auto valueHandler = [value, asyncResp](
90 const boost::system::error_code ec,
91 const SensorVariant& powerCapEnable) {
92 if (ec)
93 {
94 messages::internalError(asyncResp->res);
95 BMCWEB_LOG_ERROR
96 << "powerCapEnable Get handler: Dbus error " << ec;
97 return;
98 }
99 // Check PowerCapEnable
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500100 const bool* b = std::get_if<bool>(&powerCapEnable);
Carol Wang4bb3dc32019-10-17 18:15:02 +0800101 if (b == nullptr)
102 {
103 messages::internalError(asyncResp->res);
104 BMCWEB_LOG_ERROR
105 << "Fail to get PowerCapEnable status ";
106 return;
107 }
108 if (!(*b))
109 {
110 messages::actionNotSupported(
111 asyncResp->res,
112 "Setting LimitInWatts when PowerLimit "
113 "feature is disabled");
114 BMCWEB_LOG_ERROR << "PowerLimit feature is disabled ";
115 return;
116 }
117
118 crow::connections::systemBus->async_method_call(
119 [asyncResp](const boost::system::error_code ec) {
120 if (ec)
121 {
122 BMCWEB_LOG_DEBUG
123 << "Power Limit Set: Dbus error: " << ec;
124 messages::internalError(asyncResp->res);
125 return;
126 }
127 asyncResp->res.result(
128 boost::beast::http::status::no_content);
129 },
130 "xyz.openbmc_project.Settings",
131 "/xyz/openbmc_project/control/host0/power_cap",
132 "org.freedesktop.DBus.Properties", "Set",
133 "xyz.openbmc_project.Control.Power.Cap", "PowerCap",
134 sdbusplus::message::variant<uint32_t>(*value));
135 };
136 crow::connections::systemBus->async_method_call(
137 std::move(valueHandler), "xyz.openbmc_project.Settings",
138 "/xyz/openbmc_project/control/host0/power_cap",
139 "org.freedesktop.DBus.Properties", "Get",
140 "xyz.openbmc_project.Control.Power.Cap", "PowerCapEnable");
141 };
142 getValidChassisPath(asyncResp, std::move(getChassisPath));
143 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700144 void doGet(crow::Response& res, const crow::Request& req,
145 const std::vector<std::string>& params) override
146 {
147 if (params.size() != 1)
148 {
149 res.result(boost::beast::http::status::internal_server_error);
150 res.end();
151 return;
152 }
153 const std::string& chassis_name = params[0];
154
Jennifer Leec5d03ff2019-03-08 15:42:58 -0800155 res.jsonValue["PowerControl"] = nlohmann::json::array();
156
Ed Tanous2474adf2018-09-05 16:31:16 -0700157 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530158 res, chassis_name, typeList, "Power");
Eddie James028f7eb2019-05-17 21:24:36 +0000159
Ed Tanous2474adf2018-09-05 16:31:16 -0700160 getChassisData(sensorAsyncResp);
Eddie James028f7eb2019-05-17 21:24:36 +0000161
162 // This callback verifies that the power limit is only provided for the
163 // chassis that implements the Chassis inventory item. This prevents
164 // things like power supplies providing the chassis power limit
165 auto chassisHandler = [sensorAsyncResp](
Ed Tanous271584a2019-07-09 16:24:22 -0700166 const boost::system::error_code e,
Eddie James028f7eb2019-05-17 21:24:36 +0000167 const std::vector<std::string>&
168 chassisPaths) {
Ed Tanous271584a2019-07-09 16:24:22 -0700169 if (e)
Eddie James028f7eb2019-05-17 21:24:36 +0000170 {
171 BMCWEB_LOG_ERROR
Ed Tanous271584a2019-07-09 16:24:22 -0700172 << "Power Limit GetSubTreePaths handler Dbus error " << e;
Eddie James028f7eb2019-05-17 21:24:36 +0000173 return;
174 }
175
176 bool found = false;
177 for (const std::string& chassis : chassisPaths)
178 {
179 size_t len = std::string::npos;
180 size_t lastPos = chassis.rfind("/");
181 if (lastPos == std::string::npos)
182 {
183 continue;
184 }
185
186 if (lastPos == chassis.size() - 1)
187 {
188 size_t end = lastPos;
189 lastPos = chassis.rfind("/", lastPos - 1);
190 if (lastPos == std::string::npos)
191 {
192 continue;
193 }
194
195 len = end - (lastPos + 1);
196 }
197
198 std::string interfaceChassisName =
199 chassis.substr(lastPos + 1, len);
200 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId))
201 {
202 found = true;
203 break;
204 }
205 }
206
207 if (!found)
208 {
209 BMCWEB_LOG_DEBUG << "Power Limit not present for "
210 << sensorAsyncResp->chassisId;
211 return;
212 }
213
214 auto valueHandler =
215 [sensorAsyncResp](
216 const boost::system::error_code ec,
217 const std::vector<std::pair<std::string, SensorVariant>>&
218 properties) {
219 if (ec)
220 {
221 messages::internalError(sensorAsyncResp->res);
222 BMCWEB_LOG_ERROR
223 << "Power Limit GetAll handler: Dbus error " << ec;
224 return;
225 }
226
227 nlohmann::json& tempArray =
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500228 sensorAsyncResp->res.jsonValue["PowerControl"];
Eddie James028f7eb2019-05-17 21:24:36 +0000229
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500230 // Put multiple "sensors" into a single PowerControl, 0, so
231 // only create the first one
Eddie James028f7eb2019-05-17 21:24:36 +0000232 if (tempArray.empty())
233 {
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500234 // Mandatory properties odata.id and MemberId
235 // A warning without a odata.type
236 tempArray.push_back(
237 {{"@odata.type", "#Power.v1_0_0.PowerControl"},
238 {"@odata.id", "/redfish/v1/Chassis/" +
239 sensorAsyncResp->chassisId +
240 "/Power#/PowerControl/0"},
241 {"Name", "Chassis Power Control"},
242 {"MemberId", "0"}});
Eddie James028f7eb2019-05-17 21:24:36 +0000243 }
244
245 nlohmann::json& sensorJson = tempArray.back();
246 bool enabled = false;
247 double powerCap = 0.0;
248 int64_t scale = 0;
249
250 for (const std::pair<std::string, SensorVariant>& property :
251 properties)
252 {
253 if (!property.first.compare("Scale"))
254 {
255 const int64_t* i =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500256 std::get_if<int64_t>(&property.second);
Eddie James028f7eb2019-05-17 21:24:36 +0000257
258 if (i)
259 {
260 scale = *i;
261 }
262 }
263 else if (!property.first.compare("PowerCap"))
264 {
265 const double* d =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500266 std::get_if<double>(&property.second);
Eddie James028f7eb2019-05-17 21:24:36 +0000267 const int64_t* i =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500268 std::get_if<int64_t>(&property.second);
Eddie James028f7eb2019-05-17 21:24:36 +0000269 const uint32_t* u =
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500270 std::get_if<uint32_t>(&property.second);
Eddie James028f7eb2019-05-17 21:24:36 +0000271
272 if (d)
273 {
274 powerCap = *d;
275 }
276 else if (i)
277 {
Ed Tanous271584a2019-07-09 16:24:22 -0700278 powerCap = static_cast<double>(*i);
Eddie James028f7eb2019-05-17 21:24:36 +0000279 }
280 else if (u)
281 {
282 powerCap = *u;
283 }
284 }
285 else if (!property.first.compare("PowerCapEnable"))
286 {
Patrick Williams8d78b7a2020-05-13 11:24:20 -0500287 const bool* b = std::get_if<bool>(&property.second);
Eddie James028f7eb2019-05-17 21:24:36 +0000288
289 if (b)
290 {
291 enabled = *b;
292 }
293 }
294 }
295
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500296 nlohmann::json& value =
297 sensorJson["PowerLimit"]["LimitInWatts"];
Eddie James028f7eb2019-05-17 21:24:36 +0000298
Joshi-Mansi5a64a6f2020-03-14 02:08:19 +0530299 // LimitException is Mandatory attribute as per OCP Baseline
300 // Profile – v1.0.0, so currently making it "NoAction"
301 // as default value to make it OCP Compliant.
302 sensorJson["PowerLimit"]["LimitException"] = "NoAction";
303
Eddie James028f7eb2019-05-17 21:24:36 +0000304 if (enabled)
305 {
306 // Redfish specification indicates PowerLimit should be
307 // null if the limit is not enabled.
308 value = powerCap * std::pow(10, scale);
309 }
310 };
311
312 crow::connections::systemBus->async_method_call(
313 std::move(valueHandler), "xyz.openbmc_project.Settings",
314 "/xyz/openbmc_project/control/host0/power_cap",
315 "org.freedesktop.DBus.Properties", "GetAll",
316 "xyz.openbmc_project.Control.Power.Cap");
317 };
318
319 crow::connections::systemBus->async_method_call(
320 std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper",
321 "/xyz/openbmc_project/object_mapper",
322 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
Ed Tanous271584a2019-07-09 16:24:22 -0700323 "/xyz/openbmc_project/inventory", 0,
AppaRao Pulif857e9a2020-03-12 14:28:03 +0530324 std::array<const char*, 2>{
325 "xyz.openbmc_project.Inventory.Item.Board",
Eddie James028f7eb2019-05-17 21:24:36 +0000326 "xyz.openbmc_project.Inventory.Item.Chassis"});
Ed Tanous2474adf2018-09-05 16:31:16 -0700327 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530328 void doPatch(crow::Response& res, const crow::Request& req,
329 const std::vector<std::string>& params) override
330 {
Carol Wang4bb3dc32019-10-17 18:15:02 +0800331 if (params.size() != 1)
332 {
333 messages::internalError(res);
334 res.end();
335 return;
336 }
337
338 const std::string& chassisName = params[0];
339 auto asyncResp = std::make_shared<SensorsAsyncResp>(res, chassisName,
340 typeList, "Power");
341
342 std::optional<std::vector<nlohmann::json>> voltageCollections;
343 std::optional<std::vector<nlohmann::json>> powerCtlCollections;
344
345 if (!json_util::readJson(req, asyncResp->res, "PowerControl",
346 powerCtlCollections, "Voltages",
347 voltageCollections))
348 {
349 return;
350 }
351
352 if (powerCtlCollections)
353 {
354 setPowerCapOverride(asyncResp, *powerCtlCollections);
355 }
356 if (voltageCollections)
357 {
358 std::unordered_map<std::string, std::vector<nlohmann::json>>
359 allCollections;
360 allCollections.emplace("Voltages", *std::move(voltageCollections));
jayaprakash Mutyala397fd612020-02-06 23:33:34 +0000361 checkAndDoSensorsOverride(asyncResp, allCollections);
Carol Wang4bb3dc32019-10-17 18:15:02 +0800362 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530363 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700364};
365
366} // namespace redfish