blob: 8c3927b8d096eabe41ffecb44a71b467bbf24551 [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"}}},
Richard Marian Thomaiyar6f4fd472019-02-13 10:10:59 +053034 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
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"};
Ed Tanous2474adf2018-09-05 16:31:16 -070043 void doGet(crow::Response& res, const crow::Request& req,
44 const std::vector<std::string>& params) override
45 {
46 if (params.size() != 1)
47 {
48 res.result(boost::beast::http::status::internal_server_error);
49 res.end();
50 return;
51 }
52 const std::string& chassis_name = params[0];
53
Jennifer Leec5d03ff2019-03-08 15:42:58 -080054 res.jsonValue["PowerControl"] = nlohmann::json::array();
55
Ed Tanous2474adf2018-09-05 16:31:16 -070056 auto sensorAsyncResp = std::make_shared<SensorsAsyncResp>(
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +053057 res, chassis_name, typeList, "Power");
Eddie James028f7eb2019-05-17 21:24:36 +000058
Ed Tanous2474adf2018-09-05 16:31:16 -070059 getChassisData(sensorAsyncResp);
Eddie James028f7eb2019-05-17 21:24:36 +000060
61 // This callback verifies that the power limit is only provided for the
62 // chassis that implements the Chassis inventory item. This prevents
63 // things like power supplies providing the chassis power limit
64 auto chassisHandler = [sensorAsyncResp](
65 const boost::system::error_code ec,
66 const std::vector<std::string>&
67 chassisPaths) {
68 if (ec)
69 {
70 BMCWEB_LOG_ERROR
71 << "Power Limit GetSubTreePaths handler Dbus error " << ec;
72 return;
73 }
74
75 bool found = false;
76 for (const std::string& chassis : chassisPaths)
77 {
78 size_t len = std::string::npos;
79 size_t lastPos = chassis.rfind("/");
80 if (lastPos == std::string::npos)
81 {
82 continue;
83 }
84
85 if (lastPos == chassis.size() - 1)
86 {
87 size_t end = lastPos;
88 lastPos = chassis.rfind("/", lastPos - 1);
89 if (lastPos == std::string::npos)
90 {
91 continue;
92 }
93
94 len = end - (lastPos + 1);
95 }
96
97 std::string interfaceChassisName =
98 chassis.substr(lastPos + 1, len);
99 if (!interfaceChassisName.compare(sensorAsyncResp->chassisId))
100 {
101 found = true;
102 break;
103 }
104 }
105
106 if (!found)
107 {
108 BMCWEB_LOG_DEBUG << "Power Limit not present for "
109 << sensorAsyncResp->chassisId;
110 return;
111 }
112
113 auto valueHandler =
114 [sensorAsyncResp](
115 const boost::system::error_code ec,
116 const std::vector<std::pair<std::string, SensorVariant>>&
117 properties) {
118 if (ec)
119 {
120 messages::internalError(sensorAsyncResp->res);
121 BMCWEB_LOG_ERROR
122 << "Power Limit GetAll handler: Dbus error " << ec;
123 return;
124 }
125
126 nlohmann::json& tempArray =
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500127 sensorAsyncResp->res.jsonValue["PowerControl"];
Eddie James028f7eb2019-05-17 21:24:36 +0000128
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500129 // Put multiple "sensors" into a single PowerControl, 0, so
130 // only create the first one
Eddie James028f7eb2019-05-17 21:24:36 +0000131 if (tempArray.empty())
132 {
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500133 // Mandatory properties odata.id and MemberId
134 // A warning without a odata.type
135 tempArray.push_back(
136 {{"@odata.type", "#Power.v1_0_0.PowerControl"},
137 {"@odata.id", "/redfish/v1/Chassis/" +
138 sensorAsyncResp->chassisId +
139 "/Power#/PowerControl/0"},
140 {"Name", "Chassis Power Control"},
141 {"MemberId", "0"}});
Eddie James028f7eb2019-05-17 21:24:36 +0000142 }
143
144 nlohmann::json& sensorJson = tempArray.back();
145 bool enabled = false;
146 double powerCap = 0.0;
147 int64_t scale = 0;
148
149 for (const std::pair<std::string, SensorVariant>& property :
150 properties)
151 {
152 if (!property.first.compare("Scale"))
153 {
154 const int64_t* i =
155 sdbusplus::message::variant_ns::get_if<int64_t>(
156 &property.second);
157
158 if (i)
159 {
160 scale = *i;
161 }
162 }
163 else if (!property.first.compare("PowerCap"))
164 {
165 const double* d =
166 sdbusplus::message::variant_ns::get_if<double>(
167 &property.second);
168 const int64_t* i =
169 sdbusplus::message::variant_ns::get_if<int64_t>(
170 &property.second);
171 const uint32_t* u =
172 sdbusplus::message::variant_ns::get_if<
173 uint32_t>(&property.second);
174
175 if (d)
176 {
177 powerCap = *d;
178 }
179 else if (i)
180 {
181 powerCap = *i;
182 }
183 else if (u)
184 {
185 powerCap = *u;
186 }
187 }
188 else if (!property.first.compare("PowerCapEnable"))
189 {
190 const bool* b =
191 sdbusplus::message::variant_ns::get_if<bool>(
192 &property.second);
193
194 if (b)
195 {
196 enabled = *b;
197 }
198 }
199 }
200
Gunnar Mills7ab06f42019-07-02 13:07:16 -0500201 nlohmann::json& value =
202 sensorJson["PowerLimit"]["LimitInWatts"];
Eddie James028f7eb2019-05-17 21:24:36 +0000203
204 if (enabled)
205 {
206 // Redfish specification indicates PowerLimit should be
207 // null if the limit is not enabled.
208 value = powerCap * std::pow(10, scale);
209 }
210 };
211
212 crow::connections::systemBus->async_method_call(
213 std::move(valueHandler), "xyz.openbmc_project.Settings",
214 "/xyz/openbmc_project/control/host0/power_cap",
215 "org.freedesktop.DBus.Properties", "GetAll",
216 "xyz.openbmc_project.Control.Power.Cap");
217 };
218
219 crow::connections::systemBus->async_method_call(
220 std::move(chassisHandler), "xyz.openbmc_project.ObjectMapper",
221 "/xyz/openbmc_project/object_mapper",
222 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
223 "/xyz/openbmc_project/inventory", int32_t(0),
224 std::array<const char*, 1>{
225 "xyz.openbmc_project.Inventory.Item.Chassis"});
Ed Tanous2474adf2018-09-05 16:31:16 -0700226 }
Richard Marian Thomaiyar413961d2019-02-01 00:43:39 +0530227 void doPatch(crow::Response& res, const crow::Request& req,
228 const std::vector<std::string>& params) override
229 {
230 setSensorOverride(res, req, params, typeList, "Power");
231 }
Ed Tanous2474adf2018-09-05 16:31:16 -0700232};
233
234} // namespace redfish