blob: 611c7e77e97cdafe8c862060f14b17b7ba1d707c [file] [log] [blame]
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001/*
2// Copyright (c) 2019 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
20namespace redfish
21{
22class StorageCollection : public Node
23{
24 public:
25 StorageCollection(CrowApp &app) :
26 Node(app, "/redfish/v1/Systems/system/Storage/")
27 {
28 entityPrivileges = {
29 {boost::beast::http::verb::get, {{"Login"}}},
30 {boost::beast::http::verb::head, {{"Login"}}},
31 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
32 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
33 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
34 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
35 }
36
37 private:
38 void doGet(crow::Response &res, const crow::Request &req,
39 const std::vector<std::string> &params) override
40 {
41 res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection";
42 res.jsonValue["@odata.context"] =
43 "/redfish/v1/$metadata#StorageCollection.StorageCollection";
44 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage";
45 res.jsonValue["Name"] = "Storage Collection";
46 res.jsonValue["Members"] = {
47 {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}};
48 res.jsonValue["Members@odata.count"] = 1;
49 res.end();
50 }
51};
52
53class Storage : public Node
54{
55 public:
56 Storage(CrowApp &app) : Node(app, "/redfish/v1/Systems/system/Storage/1")
57 {
58 entityPrivileges = {
59 {boost::beast::http::verb::get, {{"Login"}}},
60 {boost::beast::http::verb::head, {{"Login"}}},
61 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
62 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
63 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
64 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
65 }
66
67 private:
68 void doGet(crow::Response &res, const crow::Request &req,
69 const std::vector<std::string> &params) override
70 {
71 res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
72 res.jsonValue["@odata.context"] =
73 "/redfish/v1/$metadata#Storage.Storage";
74 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
75 res.jsonValue["Name"] = "Storage Controller";
76 res.jsonValue["Id"] = "1";
77
78 auto asyncResp = std::make_shared<AsyncResp>(res);
79 crow::connections::systemBus->async_method_call(
80 [asyncResp](const boost::system::error_code ec,
81 const std::vector<std::string> &storageList) {
82 nlohmann::json &storageArray =
83 asyncResp->res.jsonValue["Drives"];
84 storageArray = nlohmann::json::array();
85 asyncResp->res.jsonValue["Drives@odata.count"] = 0;
86 if (ec)
87 {
88 BMCWEB_LOG_ERROR << "Drive mapper call error";
89 messages::internalError(asyncResp->res);
90 return;
91 }
92 for (const std::string &objpath : storageList)
93 {
94 std::size_t lastPos = objpath.rfind("/");
95 if (lastPos == std::string::npos ||
96 (objpath.size() <= lastPos + 1))
97 {
98 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
99 continue;
100 }
101
102 storageArray.push_back(
103 {{"@odata.id",
James Feistbe13cec2019-10-30 16:38:16 -0700104 "/redfish/v1/Systems/system/Storage/1/Drives/" +
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700105 objpath.substr(lastPos + 1)}});
106 }
107
108 asyncResp->res.jsonValue["Drives@odata.count"] =
109 storageArray.size();
110 },
111 "xyz.openbmc_project.ObjectMapper",
112 "/xyz/openbmc_project/object_mapper",
113 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
114 "/xyz/openbmc_project/inventory", int32_t(0),
115 std::array<const char *, 1>{
116 "xyz.openbmc_project.Inventory.Item.Drive"});
117 }
118};
119
120class Drive : public Node
121{
122 public:
123 Drive(CrowApp &app) :
James Feistbe13cec2019-10-30 16:38:16 -0700124 Node(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/",
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700125 std::string())
126 {
127 entityPrivileges = {
128 {boost::beast::http::verb::get, {{"Login"}}},
129 {boost::beast::http::verb::head, {{"Login"}}},
130 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
131 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
132 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
133 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
134 }
135
136 private:
137 void doGet(crow::Response &res, const crow::Request &req,
138 const std::vector<std::string> &params) override
139 {
140 const std::string &driveId = params[0];
141
142 auto asyncResp = std::make_shared<AsyncResp>(res);
143
144 crow::connections::systemBus->async_method_call(
145 [asyncResp, driveId](
146 const boost::system::error_code ec,
147 const std::vector<std::pair<
148 std::string, std::vector<std::pair<
149 std::string, std::vector<std::string>>>>>
150 &subtree) {
151 if (ec)
152 {
153 BMCWEB_LOG_ERROR << "Drive mapper call error";
154 messages::internalError(asyncResp->res);
155 return;
156 }
157
158 auto object = std::find_if(
159 subtree.begin(), subtree.end(), [&driveId](auto &object) {
160 const std::string &path = object.first;
161 return boost::ends_with(path, "/" + driveId);
162 });
163
164 if (object == subtree.end())
165 {
166 messages::resourceNotFound(asyncResp->res, "Drive",
167 driveId);
168 return;
169 }
170
171 const std::string &path = object->first;
172 const std::vector<
173 std::pair<std::string, std::vector<std::string>>>
174 &connectionNames = object->second;
175
176 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
177 asyncResp->res.jsonValue["@odata.context"] =
178 "/redfish/v1/$metadata#Drive.Drive";
179 asyncResp->res.jsonValue["@odata.id"] =
James Feistbe13cec2019-10-30 16:38:16 -0700180 "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700181
182 if (connectionNames.size() != 1)
183 {
184 BMCWEB_LOG_ERROR << "Connection size "
185 << connectionNames.size()
186 << ", greater than 1";
187 messages::internalError(asyncResp->res);
188 return;
189 }
190
191 getMainChassisId(
192 asyncResp, [](const std::string &chassisId,
193 std::shared_ptr<AsyncResp> aRsp) {
194 aRsp->res.jsonValue["Links"]["Chassis"] = {
195 {"@odata.id", "/redfish/v1/Chassis/" + chassisId}};
196 });
197
198 const std::string &connectionName = connectionNames[0].first;
199 crow::connections::systemBus->async_method_call(
200 [asyncResp,
201 driveId](const boost::system::error_code ec,
202 const std::vector<std::pair<
203 std::string,
204 std::variant<bool, std::string, uint64_t>>>
205 &propertiesList) {
206 if (ec)
207 {
208 // this interface isn't necessary
209 return;
210 }
211 for (const std::pair<std::string,
212 std::variant<bool, std::string,
213 uint64_t>> &property :
214 propertiesList)
215 {
216 // Store DBus properties that are also
217 // Redfish properties with same name and a
218 // string value
219 const std::string &propertyName = property.first;
220 if ((propertyName == "PartNumber") ||
221 (propertyName == "SerialNumber") ||
222 (propertyName == "Manufacturer") ||
223 (propertyName == "Model"))
224 {
225 const std::string *value =
226 std::get_if<std::string>(&property.second);
227 if (value == nullptr)
228 {
229 // illegal property
230 messages::internalError(asyncResp->res);
231 continue;
232 }
233 asyncResp->res.jsonValue[propertyName] = *value;
234 }
235 }
236 asyncResp->res.jsonValue["Name"] = driveId;
237 asyncResp->res.jsonValue["Id"] = driveId;
238 },
239 connectionName, path, "org.freedesktop.DBus.Properties",
240 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
241
242 // default it to Enabled
243 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
244
245 crow::connections::systemBus->async_method_call(
246 [asyncResp, path](const boost::system::error_code ec,
247 const std::variant<bool> present) {
248 // this interface isn't necessary, only check it if we
249 // get a good return
250 if (!ec)
251 {
252 const bool *enabled = std::get_if<bool>(&present);
253 if (enabled == nullptr)
254 {
255 BMCWEB_LOG_DEBUG << "Illegal property present";
256 messages::internalError(asyncResp->res);
257 return;
258 }
259 if (!(*enabled))
260 {
261 asyncResp->res.jsonValue["Status"]["State"] =
262 "Disabled";
263 return;
264 }
265 }
266
267 // only populate if Enabled, assume enabled unless item
268 // interface says otherwise
269 auto health =
270 std::make_shared<HealthPopulate>(asyncResp);
271 health->inventory = std::vector<std::string>{path};
272
273 health->populate();
274 },
275 connectionName, path, "org.freedesktop.DBus.Properties",
276 "Get", "xyz.openbmc_project.Inventory.Item", "Present");
James Feist22984072019-10-21 16:10:49 -0700277
278 crow::connections::systemBus->async_method_call(
279 [asyncResp](const boost::system::error_code ec,
280 const std::variant<bool> rebuilding) {
281 // this interface isn't necessary, only check it if we
282 // get a good return
283 if (ec)
284 {
285 return;
286 }
287 const bool *updating = std::get_if<bool>(&rebuilding);
288 if (updating == nullptr)
289 {
290 BMCWEB_LOG_DEBUG << "Illegal property present";
291 messages::internalError(asyncResp->res);
292 return;
293 }
294
295 // updating and disabled in the backend shouldn't be
296 // able to be set at the same time, so we don't need to
297 // check for the race condition of these two calls
298 if ((*updating))
299 {
300 asyncResp->res.jsonValue["Status"]["State"] =
301 "Updating";
302 }
303 },
304 connectionName, path, "org.freedesktop.DBus.Properties",
305 "Get", "xyz.openbmc_project.State.Drive", "Rebuilding");
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700306 },
307 "xyz.openbmc_project.ObjectMapper",
308 "/xyz/openbmc_project/object_mapper",
309 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
310 "/xyz/openbmc_project/inventory", int32_t(0),
311 std::array<const char *, 1>{
312 "xyz.openbmc_project.Inventory.Item.Drive"});
313 }
314};
315} // namespace redfish