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