blob: 922d323f25c10978bd2307f4800d03575fbe2ce2 [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"
James Feiste284a7c2019-11-20 16:20:23 -080019#include "openbmc_dbus_rest.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070020
Nikhil Potadea25aecc2019-08-23 16:35:26 -070021#include <node.hpp>
22
23namespace redfish
24{
25class StorageCollection : public Node
26{
27 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -050028 StorageCollection(CrowApp& app) :
Nikhil Potadea25aecc2019-08-23 16:35:26 -070029 Node(app, "/redfish/v1/Systems/system/Storage/")
30 {
31 entityPrivileges = {
32 {boost::beast::http::verb::get, {{"Login"}}},
33 {boost::beast::http::verb::head, {{"Login"}}},
34 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
35 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
36 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
37 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
38 }
39
40 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -050041 void doGet(crow::Response& res, const crow::Request& req,
42 const std::vector<std::string>& params) override
Nikhil Potadea25aecc2019-08-23 16:35:26 -070043 {
44 res.jsonValue["@odata.type"] = "#StorageCollection.StorageCollection";
Nikhil Potadea25aecc2019-08-23 16:35:26 -070045 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage";
46 res.jsonValue["Name"] = "Storage Collection";
47 res.jsonValue["Members"] = {
48 {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}};
49 res.jsonValue["Members@odata.count"] = 1;
50 res.end();
51 }
52};
53
54class Storage : public Node
55{
56 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -050057 Storage(CrowApp& app) : Node(app, "/redfish/v1/Systems/system/Storage/1/")
Nikhil Potadea25aecc2019-08-23 16:35:26 -070058 {
59 entityPrivileges = {
60 {boost::beast::http::verb::get, {{"Login"}}},
61 {boost::beast::http::verb::head, {{"Login"}}},
62 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
63 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
64 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
65 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
66 }
67
68 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -050069 void doGet(crow::Response& res, const crow::Request& req,
70 const std::vector<std::string>& params) override
Nikhil Potadea25aecc2019-08-23 16:35:26 -070071 {
72 res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
Nikhil Potadea25aecc2019-08-23 16:35:26 -070073 res.jsonValue["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
James Feiste284a7c2019-11-20 16:20:23 -080074 res.jsonValue["Name"] = "Storage";
Nikhil Potadea25aecc2019-08-23 16:35:26 -070075 res.jsonValue["Id"] = "1";
James Feist2ad9c2f2019-10-29 16:26:48 -070076 res.jsonValue["Status"]["State"] = "Enabled";
Nikhil Potadea25aecc2019-08-23 16:35:26 -070077
78 auto asyncResp = std::make_shared<AsyncResp>(res);
James Feiste284a7c2019-11-20 16:20:23 -080079 auto health = std::make_shared<HealthPopulate>(asyncResp);
80 health->populate();
81
Nikhil Potadea25aecc2019-08-23 16:35:26 -070082 crow::connections::systemBus->async_method_call(
James Feiste284a7c2019-11-20 16:20:23 -080083 [asyncResp, health](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050084 const std::vector<std::string>& storageList) {
85 nlohmann::json& storageArray =
Nikhil Potadea25aecc2019-08-23 16:35:26 -070086 asyncResp->res.jsonValue["Drives"];
87 storageArray = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -050088 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
James Feiste284a7c2019-11-20 16:20:23 -080089 count = 0;
James Feist2ad9c2f2019-10-29 16:26:48 -070090
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
James Feiste284a7c2019-11-20 16:20:23 -080098 health->inventory.insert(health->inventory.end(),
99 storageList.begin(),
100 storageList.end());
James Feist2ad9c2f2019-10-29 16:26:48 -0700101
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500102 for (const std::string& objpath : storageList)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700103 {
104 std::size_t lastPos = objpath.rfind("/");
105 if (lastPos == std::string::npos ||
106 (objpath.size() <= lastPos + 1))
107 {
108 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
109 continue;
110 }
111
112 storageArray.push_back(
113 {{"@odata.id",
James Feistbe13cec2019-10-30 16:38:16 -0700114 "/redfish/v1/Systems/system/Storage/1/Drives/" +
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700115 objpath.substr(lastPos + 1)}});
116 }
117
James Feiste284a7c2019-11-20 16:20:23 -0800118 count = storageArray.size();
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700119 },
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),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500124 std::array<const char*, 1>{
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700125 "xyz.openbmc_project.Inventory.Item.Drive"});
James Feiste284a7c2019-11-20 16:20:23 -0800126
127 crow::connections::systemBus->async_method_call(
128 [asyncResp,
129 health](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500130 const crow::openbmc_mapper::GetSubTreeType& subtree) {
James Feiste284a7c2019-11-20 16:20:23 -0800131 if (ec || !subtree.size())
132 {
James Feistd819a422019-11-27 10:36:36 -0800133 // doesn't have to be there
James Feiste284a7c2019-11-20 16:20:23 -0800134 return;
135 }
136
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500137 nlohmann::json& root =
James Feiste284a7c2019-11-20 16:20:23 -0800138 asyncResp->res.jsonValue["StorageControllers"];
139 root = nlohmann::json::array();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500140 for (const auto& [path, interfaceDict] : subtree)
James Feiste284a7c2019-11-20 16:20:23 -0800141 {
142 std::size_t lastPos = path.rfind("/");
143 if (lastPos == std::string::npos ||
144 (path.size() <= lastPos + 1))
145 {
146 BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
147 return;
148 }
149
150 if (interfaceDict.size() != 1)
151 {
152 BMCWEB_LOG_ERROR << "Connection size "
153 << interfaceDict.size()
154 << ", greater than 1";
155 messages::internalError(asyncResp->res);
156 return;
157 }
158
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500159 const std::string& connectionName =
James Feiste284a7c2019-11-20 16:20:23 -0800160 interfaceDict.front().first;
161
162 size_t index = root.size();
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500163 nlohmann::json& storageController =
James Feiste284a7c2019-11-20 16:20:23 -0800164 root.emplace_back(nlohmann::json::object());
165
166 std::string id = path.substr(lastPos + 1);
167
168 storageController["@odata.type"] =
169 "#Storage.v1_7_0.StorageController";
James Feiste284a7c2019-11-20 16:20:23 -0800170 storageController["@odata.id"] =
171 "/redfish/v1/Systems/system/Storage/1"
172 "#/StorageControllers/" +
173 std::to_string(index);
174 storageController["Name"] = id;
175 storageController["MemberId"] = id;
176 storageController["Status"]["State"] = "Enabled";
177
178 crow::connections::systemBus->async_method_call(
179 [asyncResp, index](const boost::system::error_code ec,
180 const std::variant<bool> present) {
181 // this interface isn't necessary, only check it if
182 // we get a good return
183 if (ec)
184 {
185 return;
186 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 const bool* enabled = std::get_if<bool>(&present);
James Feiste284a7c2019-11-20 16:20:23 -0800188 if (enabled == nullptr)
189 {
190 BMCWEB_LOG_DEBUG << "Illegal property present";
191 messages::internalError(asyncResp->res);
192 return;
193 }
194 if (!(*enabled))
195 {
196 asyncResp->res
197 .jsonValue["StorageControllers"][index]
198 ["Status"]["State"] = "Disabled";
199 }
200 },
201 connectionName, path, "org.freedesktop.DBus.Properties",
202 "Get", "xyz.openbmc_project.Inventory.Item", "Present");
203
204 crow::connections::systemBus->async_method_call(
205 [asyncResp,
206 index](const boost::system::error_code ec,
207 const std::vector<std::pair<
208 std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500209 std::variant<bool, std::string, uint64_t>>>&
210 propertiesList) {
James Feiste284a7c2019-11-20 16:20:23 -0800211 if (ec)
212 {
213 // this interface isn't necessary
214 return;
215 }
216 for (const std::pair<
217 std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500218 std::variant<bool, std::string, uint64_t>>&
219 property : propertiesList)
James Feiste284a7c2019-11-20 16:20:23 -0800220 {
221 // Store DBus properties that are also
222 // Redfish properties with same name and a
223 // string value
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500224 const std::string& propertyName =
James Feiste284a7c2019-11-20 16:20:23 -0800225 property.first;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500226 nlohmann::json& object =
James Feiste284a7c2019-11-20 16:20:23 -0800227 asyncResp->res
228 .jsonValue["StorageControllers"][index];
229 if ((propertyName == "PartNumber") ||
230 (propertyName == "SerialNumber") ||
231 (propertyName == "Manufacturer") ||
232 (propertyName == "Model"))
233 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500234 const std::string* value =
James Feiste284a7c2019-11-20 16:20:23 -0800235 std::get_if<std::string>(
236 &property.second);
237 if (value == nullptr)
238 {
239 // illegal property
240 messages::internalError(asyncResp->res);
241 continue;
242 }
243 object[propertyName] = *value;
244 }
245 }
246 },
247 connectionName, path, "org.freedesktop.DBus.Properties",
248 "GetAll",
249 "xyz.openbmc_project.Inventory.Decorator.Asset");
250 }
251
252 // this is done after we know the json array will no longer be
253 // resized, as json::array uses vector underneath and we need
254 // references to its members that won't change
255 size_t count = 0;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500256 for (const auto& [path, interfaceDict] : subtree)
James Feiste284a7c2019-11-20 16:20:23 -0800257 {
258 auto subHealth = std::make_shared<HealthPopulate>(
259 asyncResp, root[count]["Status"]);
260 subHealth->inventory.emplace_back(path);
261 health->inventory.emplace_back(path);
262 health->children.emplace_back(subHealth);
263 count++;
264 }
265 },
266 "xyz.openbmc_project.ObjectMapper",
267 "/xyz/openbmc_project/object_mapper",
268 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
269 "/xyz/openbmc_project/inventory", int32_t(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500270 std::array<const char*, 1>{
James Feiste284a7c2019-11-20 16:20:23 -0800271 "xyz.openbmc_project.Inventory.Item.StorageController"});
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700272 }
273};
274
275class Drive : public Node
276{
277 public:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500278 Drive(CrowApp& app) :
James Feistbe13cec2019-10-30 16:38:16 -0700279 Node(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/",
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700280 std::string())
281 {
282 entityPrivileges = {
283 {boost::beast::http::verb::get, {{"Login"}}},
284 {boost::beast::http::verb::head, {{"Login"}}},
285 {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
286 {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
287 {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
288 {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
289 }
290
291 private:
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500292 void doGet(crow::Response& res, const crow::Request& req,
293 const std::vector<std::string>& params) override
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700294 {
James Feiste284a7c2019-11-20 16:20:23 -0800295 auto asyncResp = std::make_shared<AsyncResp>(res);
296 if (params.size() != 1)
297 {
298 messages::internalError(asyncResp->res);
299 return;
300 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500301 const std::string& driveId = params[0];
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700302
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700303 crow::connections::systemBus->async_method_call(
James Feiste284a7c2019-11-20 16:20:23 -0800304 [asyncResp,
305 driveId](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500306 const crow::openbmc_mapper::GetSubTreeType& subtree) {
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700307 if (ec)
308 {
309 BMCWEB_LOG_ERROR << "Drive mapper call error";
310 messages::internalError(asyncResp->res);
311 return;
312 }
313
314 auto object = std::find_if(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500315 subtree.begin(), subtree.end(), [&driveId](auto& object) {
316 const std::string& path = object.first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700317 return boost::ends_with(path, "/" + driveId);
318 });
319
320 if (object == subtree.end())
321 {
322 messages::resourceNotFound(asyncResp->res, "Drive",
323 driveId);
324 return;
325 }
326
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500327 const std::string& path = object->first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700328 const std::vector<
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500329 std::pair<std::string, std::vector<std::string>>>&
330 connectionNames = object->second;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700331
332 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700333 asyncResp->res.jsonValue["@odata.id"] =
James Feistbe13cec2019-10-30 16:38:16 -0700334 "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId;
James Feist2ad9c2f2019-10-29 16:26:48 -0700335 asyncResp->res.jsonValue["Name"] = driveId;
336 asyncResp->res.jsonValue["Id"] = driveId;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700337
338 if (connectionNames.size() != 1)
339 {
340 BMCWEB_LOG_ERROR << "Connection size "
341 << connectionNames.size()
342 << ", greater than 1";
343 messages::internalError(asyncResp->res);
344 return;
345 }
346
347 getMainChassisId(
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500348 asyncResp, [](const std::string& chassisId,
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700349 std::shared_ptr<AsyncResp> aRsp) {
350 aRsp->res.jsonValue["Links"]["Chassis"] = {
351 {"@odata.id", "/redfish/v1/Chassis/" + chassisId}};
352 });
353
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500354 const std::string& connectionName = connectionNames[0].first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700355 crow::connections::systemBus->async_method_call(
James Feist2ad9c2f2019-10-29 16:26:48 -0700356 [asyncResp](const boost::system::error_code ec,
357 const std::vector<std::pair<
358 std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500359 std::variant<bool, std::string, uint64_t>>>&
360 propertiesList) {
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700361 if (ec)
362 {
363 // this interface isn't necessary
364 return;
365 }
366 for (const std::pair<std::string,
367 std::variant<bool, std::string,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500368 uint64_t>>& property :
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700369 propertiesList)
370 {
371 // Store DBus properties that are also
372 // Redfish properties with same name and a
373 // string value
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500374 const std::string& propertyName = property.first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700375 if ((propertyName == "PartNumber") ||
376 (propertyName == "SerialNumber") ||
377 (propertyName == "Manufacturer") ||
378 (propertyName == "Model"))
379 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500380 const std::string* value =
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700381 std::get_if<std::string>(&property.second);
382 if (value == nullptr)
383 {
384 // illegal property
385 messages::internalError(asyncResp->res);
386 continue;
387 }
388 asyncResp->res.jsonValue[propertyName] = *value;
389 }
390 }
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700391 },
392 connectionName, path, "org.freedesktop.DBus.Properties",
393 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
394
395 // default it to Enabled
396 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
397
James Feist2ad9c2f2019-10-29 16:26:48 -0700398 auto health = std::make_shared<HealthPopulate>(asyncResp);
James Feiste284a7c2019-11-20 16:20:23 -0800399 health->inventory.emplace_back(path);
James Feist2ad9c2f2019-10-29 16:26:48 -0700400 health->populate();
401
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700402 crow::connections::systemBus->async_method_call(
403 [asyncResp, path](const boost::system::error_code ec,
404 const std::variant<bool> present) {
405 // this interface isn't necessary, only check it if we
406 // get a good return
James Feist2ad9c2f2019-10-29 16:26:48 -0700407 if (ec)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700408 {
James Feist2ad9c2f2019-10-29 16:26:48 -0700409 return;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700410 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500411 const bool* enabled = std::get_if<bool>(&present);
James Feist2ad9c2f2019-10-29 16:26:48 -0700412 if (enabled == nullptr)
413 {
414 BMCWEB_LOG_DEBUG << "Illegal property present";
415 messages::internalError(asyncResp->res);
416 return;
417 }
418 if (!(*enabled))
419 {
420 asyncResp->res.jsonValue["Status"]["State"] =
421 "Disabled";
422 }
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700423 },
424 connectionName, path, "org.freedesktop.DBus.Properties",
425 "Get", "xyz.openbmc_project.Inventory.Item", "Present");
James Feist22984072019-10-21 16:10:49 -0700426
427 crow::connections::systemBus->async_method_call(
428 [asyncResp](const boost::system::error_code ec,
429 const std::variant<bool> rebuilding) {
430 // this interface isn't necessary, only check it if we
431 // get a good return
432 if (ec)
433 {
434 return;
435 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500436 const bool* updating = std::get_if<bool>(&rebuilding);
James Feist22984072019-10-21 16:10:49 -0700437 if (updating == nullptr)
438 {
439 BMCWEB_LOG_DEBUG << "Illegal property present";
440 messages::internalError(asyncResp->res);
441 return;
442 }
443
444 // updating and disabled in the backend shouldn't be
445 // able to be set at the same time, so we don't need to
446 // check for the race condition of these two calls
447 if ((*updating))
448 {
449 asyncResp->res.jsonValue["Status"]["State"] =
450 "Updating";
451 }
452 },
453 connectionName, path, "org.freedesktop.DBus.Properties",
454 "Get", "xyz.openbmc_project.State.Drive", "Rebuilding");
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700455 },
456 "xyz.openbmc_project.ObjectMapper",
457 "/xyz/openbmc_project/object_mapper",
458 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
459 "/xyz/openbmc_project/inventory", int32_t(0),
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500460 std::array<const char*, 1>{
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700461 "xyz.openbmc_project.Inventory.Item.Drive"});
462 }
463};
464} // namespace redfish