blob: a276be12e2a3931f32ee8554e67167057631e6d7 [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
John Edward Broadbent7e860f12021-04-08 15:57:16 -070021#include <app.hpp>
Ed Tanous168e20c2021-12-13 14:39:53 -080022#include <dbus_utility.hpp>
Ed Tanous45ca1b82022-03-25 13:07:27 -070023#include <query.hpp>
Ed Tanoused398212021-06-09 17:05:54 -070024#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070025#include <sdbusplus/asio/property.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070026
27namespace redfish
28{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070029inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070030{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070031 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070032 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070033 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070034 [&app](const crow::Request& req,
35 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Ed Tanous002d39b2022-05-31 08:59:27 -070036 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
37 {
38 return;
39 }
40 asyncResp->res.jsonValue["@odata.type"] =
41 "#StorageCollection.StorageCollection";
42 asyncResp->res.jsonValue["@odata.id"] =
43 "/redfish/v1/Systems/system/Storage";
44 asyncResp->res.jsonValue["Name"] = "Storage Collection";
45 nlohmann::json::array_t members;
46 nlohmann::json::object_t member;
47 member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
48 members.emplace_back(member);
49 asyncResp->res.jsonValue["Members"] = std::move(members);
50 asyncResp->res.jsonValue["Members@odata.count"] = 1;
51 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -070052}
Nikhil Potadea25aecc2019-08-23 16:35:26 -070053
John Edward Broadbent7e860f12021-04-08 15:57:16 -070054inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070055{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070056 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
Ed Tanoused398212021-06-09 17:05:54 -070057 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -070058 .methods(boost::beast::http::verb::get)(
59 [&app](const crow::Request& req,
60 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
61 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
62 {
63 return;
64 }
65 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
66 asyncResp->res.jsonValue["@odata.id"] =
67 "/redfish/v1/Systems/system/Storage/1";
68 asyncResp->res.jsonValue["Name"] = "Storage";
69 asyncResp->res.jsonValue["Id"] = "1";
70 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
71
72 auto health = std::make_shared<HealthPopulate>(asyncResp);
73 health->populate();
74
75 crow::connections::systemBus->async_method_call(
76 [asyncResp,
77 health](const boost::system::error_code ec,
78 const dbus::utility::MapperGetSubTreePathsResponse&
79 storageList) {
80 nlohmann::json& storageArray = asyncResp->res.jsonValue["Drives"];
81 storageArray = nlohmann::json::array();
82 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
83 count = 0;
84
85 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -070086 {
Ed Tanous002d39b2022-05-31 08:59:27 -070087 BMCWEB_LOG_ERROR << "Drive mapper call error";
88 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -070089 return;
90 }
Nikhil Potadea25aecc2019-08-23 16:35:26 -070091
Ed Tanous002d39b2022-05-31 08:59:27 -070092 health->inventory.insert(health->inventory.end(),
93 storageList.begin(), storageList.end());
Nikhil Potadea25aecc2019-08-23 16:35:26 -070094
Ed Tanous002d39b2022-05-31 08:59:27 -070095 for (const std::string& objpath : storageList)
96 {
97 std::size_t lastPos = objpath.rfind('/');
98 if (lastPos == std::string::npos ||
99 (objpath.size() <= lastPos + 1))
100 {
101 BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
102 continue;
103 }
104 nlohmann::json::object_t storage;
105 storage["@odata.id"] =
106 "/redfish/v1/Systems/system/Storage/1/Drives/" +
107 objpath.substr(lastPos + 1);
108 storageArray.push_back(std::move(storage));
109 }
James Feiste284a7c2019-11-20 16:20:23 -0800110
Ed Tanous002d39b2022-05-31 08:59:27 -0700111 count = storageArray.size();
112 },
113 "xyz.openbmc_project.ObjectMapper",
114 "/xyz/openbmc_project/object_mapper",
115 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
116 "/xyz/openbmc_project/inventory", int32_t(0),
117 std::array<const char*, 1>{
118 "xyz.openbmc_project.Inventory.Item.Drive"});
119
120 crow::connections::systemBus->async_method_call(
121 [asyncResp,
122 health](const boost::system::error_code ec,
123 const dbus::utility::MapperGetSubTreeResponse& subtree) {
124 if (ec || subtree.empty())
125 {
126 // doesn't have to be there
127 return;
128 }
129
130 nlohmann::json& root =
131 asyncResp->res.jsonValue["StorageControllers"];
132 root = nlohmann::json::array();
133 for (const auto& [path, interfaceDict] : subtree)
134 {
135 std::size_t lastPos = path.rfind('/');
136 if (lastPos == std::string::npos ||
137 (path.size() <= lastPos + 1))
138 {
139 BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
140 return;
141 }
142
143 if (interfaceDict.size() != 1)
144 {
145 BMCWEB_LOG_ERROR << "Connection size "
146 << interfaceDict.size()
147 << ", greater than 1";
148 messages::internalError(asyncResp->res);
149 return;
150 }
151
152 const std::string& connectionName = interfaceDict.front().first;
153
154 size_t index = root.size();
155 nlohmann::json& storageController =
156 root.emplace_back(nlohmann::json::object());
157
158 std::string id = path.substr(lastPos + 1);
159
160 storageController["@odata.type"] =
161 "#Storage.v1_7_0.StorageController";
162 storageController["@odata.id"] =
163 "/redfish/v1/Systems/system/Storage/1#/StorageControllers/" +
164 std::to_string(index);
165 storageController["Name"] = id;
166 storageController["MemberId"] = id;
167 storageController["Status"]["State"] = "Enabled";
168
169 sdbusplus::asio::getProperty<bool>(
170 *crow::connections::systemBus, connectionName, path,
171 "xyz.openbmc_project.Inventory.Item", "Present",
172 [asyncResp, index](const boost::system::error_code ec2,
173 bool enabled) {
174 // this interface isn't necessary, only check it
175 // if we get a good return
176 if (ec2)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700177 {
James Feiste284a7c2019-11-20 16:20:23 -0800178 return;
179 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700180 if (!enabled)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700181 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700182 asyncResp->res.jsonValue["StorageControllers"][index]
183 ["Status"]["State"] =
184 "Disabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700185 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700186 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700187
Ed Tanous002d39b2022-05-31 08:59:27 -0700188 crow::connections::systemBus->async_method_call(
189 [asyncResp,
190 index](const boost::system::error_code ec2,
191 const std::vector<std::pair<
192 std::string, dbus::utility::DbusVariantType>>&
193 propertiesList) {
194 if (ec2)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700195 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700196 // this interface isn't necessary
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700197 return;
198 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700199 for (const std::pair<std::string,
Ed Tanous168e20c2021-12-13 14:39:53 -0800200 dbus::utility::DbusVariantType>&
Ed Tanous002d39b2022-05-31 08:59:27 -0700201 property : propertiesList)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700202 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700203 // Store DBus properties that are also
204 // Redfish properties with same name and a
205 // string value
206 const std::string& propertyName = property.first;
207 nlohmann::json& object =
208 asyncResp->res
209 .jsonValue["StorageControllers"][index];
210 if ((propertyName == "PartNumber") ||
211 (propertyName == "SerialNumber") ||
212 (propertyName == "Manufacturer") ||
213 (propertyName == "Model"))
214 {
215 const std::string* value =
216 std::get_if<std::string>(&property.second);
217 if (value == nullptr)
218 {
219 // illegal property
220 messages::internalError(asyncResp->res);
221 return;
222 }
223 object[propertyName] = *value;
224 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700225 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700226 },
227 connectionName, path, "org.freedesktop.DBus.Properties",
228 "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
229 }
230
231 // this is done after we know the json array will no longer
232 // be resized, as json::array uses vector underneath and we
233 // need references to its members that won't change
234 size_t count = 0;
235 // Pointer based on |asyncResp->res.jsonValue|
236 nlohmann::json::json_pointer rootPtr =
237 "/StorageControllers"_json_pointer;
238 for (const auto& [path, interfaceDict] : subtree)
239 {
240 auto subHealth = std::make_shared<HealthPopulate>(
241 asyncResp, rootPtr / count / "Status");
242 subHealth->inventory.emplace_back(path);
243 health->inventory.emplace_back(path);
244 health->children.emplace_back(subHealth);
245 count++;
246 }
247 },
248 "xyz.openbmc_project.ObjectMapper",
249 "/xyz/openbmc_project/object_mapper",
250 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
251 "/xyz/openbmc_project/inventory", int32_t(0),
252 std::array<const char*, 1>{
253 "xyz.openbmc_project.Inventory.Item.StorageController"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700254 });
255}
256
Willy Tu03913172021-11-08 02:03:19 -0800257inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
258 const std::string& connectionName,
259 const std::string& path)
260{
261 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -0800262 [asyncResp](const boost::system::error_code ec,
263 const std::vector<
264 std::pair<std::string, dbus::utility::DbusVariantType>>&
265 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700266 if (ec)
267 {
268 // this interface isn't necessary
269 return;
270 }
271 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
272 property : propertiesList)
273 {
274 // Store DBus properties that are also
275 // Redfish properties with same name and a
276 // string value
277 const std::string& propertyName = property.first;
278 if ((propertyName == "PartNumber") ||
279 (propertyName == "SerialNumber") ||
280 (propertyName == "Manufacturer") || (propertyName == "Model"))
Willy Tu03913172021-11-08 02:03:19 -0800281 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700282 const std::string* value =
283 std::get_if<std::string>(&property.second);
284 if (value == nullptr)
Willy Tu03913172021-11-08 02:03:19 -0800285 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700286 // illegal property
287 messages::internalError(asyncResp->res);
288 return;
Willy Tu03913172021-11-08 02:03:19 -0800289 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700290 asyncResp->res.jsonValue[propertyName] = *value;
Willy Tu03913172021-11-08 02:03:19 -0800291 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700292 }
Willy Tu03913172021-11-08 02:03:19 -0800293 },
294 connectionName, path, "org.freedesktop.DBus.Properties", "GetAll",
295 "xyz.openbmc_project.Inventory.Decorator.Asset");
296}
297
298inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
299 const std::string& connectionName,
300 const std::string& path)
301{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700302 sdbusplus::asio::getProperty<bool>(
303 *crow::connections::systemBus, connectionName, path,
304 "xyz.openbmc_project.Inventory.Item", "Present",
Willy Tu03913172021-11-08 02:03:19 -0800305 [asyncResp, path](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700306 const bool enabled) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700307 // this interface isn't necessary, only check it if
308 // we get a good return
309 if (ec)
310 {
311 return;
312 }
Willy Tu03913172021-11-08 02:03:19 -0800313
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 if (!enabled)
315 {
316 asyncResp->res.jsonValue["Status"]["State"] = "Disabled";
317 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700318 });
Willy Tu03913172021-11-08 02:03:19 -0800319}
320
321inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
322 const std::string& connectionName,
323 const std::string& path)
324{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700325 sdbusplus::asio::getProperty<bool>(
326 *crow::connections::systemBus, connectionName, path,
327 "xyz.openbmc_project.State.Drive", "Rebuilding",
328 [asyncResp](const boost::system::error_code ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700329 // this interface isn't necessary, only check it
330 // if we get a good return
331 if (ec)
332 {
333 return;
334 }
Willy Tu03913172021-11-08 02:03:19 -0800335
Ed Tanous002d39b2022-05-31 08:59:27 -0700336 // updating and disabled in the backend shouldn't be
337 // able to be set at the same time, so we don't need
338 // to check for the race condition of these two
339 // calls
340 if (updating)
341 {
342 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
343 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700344 });
Willy Tu03913172021-11-08 02:03:19 -0800345}
346
Willy Tu19b8e9a2021-11-08 02:55:03 -0800347inline std::optional<std::string> convertDriveType(const std::string& type)
348{
349 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
350 {
351 return "HDD";
352 }
353 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
354 {
355 return "SSD";
356 }
357
358 return std::nullopt;
359}
360
361inline std::optional<std::string> convertDriveProtocol(const std::string& proto)
362{
363 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
364 {
365 return "SAS";
366 }
367 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
368 {
369 return "SATA";
370 }
371 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
372 {
373 return "NVMe";
374 }
375 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
376 {
377 return "FC";
378 }
379
380 return std::nullopt;
381}
382
383inline void
384 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
385 const std::string& connectionName,
386 const std::string& path)
387{
388 sdbusplus::asio::getAllProperties(
389 *crow::connections::systemBus, connectionName, path,
390 "xyz.openbmc_project.Inventory.Item.Drive",
391 [asyncResp](const boost::system::error_code ec,
392 const std::vector<
393 std::pair<std::string, dbus::utility::DbusVariantType>>&
394 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700395 if (ec)
396 {
397 // this interface isn't required
398 return;
399 }
400 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
401 property : propertiesList)
402 {
403 const std::string& propertyName = property.first;
404 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800405 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700406 const std::string* value =
407 std::get_if<std::string>(&property.second);
408 if (value == nullptr)
409 {
410 // illegal property
411 BMCWEB_LOG_ERROR << "Illegal property: Type";
412 messages::internalError(asyncResp->res);
413 return;
414 }
415
416 std::optional<std::string> mediaType = convertDriveType(*value);
417 if (!mediaType)
418 {
419 BMCWEB_LOG_ERROR << "Unsupported DriveType Interface: "
420 << *value;
421 messages::internalError(asyncResp->res);
422 return;
423 }
424
425 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800426 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700427 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800428 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700429 const uint64_t* capacity =
430 std::get_if<uint64_t>(&property.second);
431 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800432 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700433 BMCWEB_LOG_ERROR << "Illegal property: Capacity";
434 messages::internalError(asyncResp->res);
435 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800436 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700437 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800438 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700439 // drive capacity not known
440 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800441 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800442
Ed Tanous002d39b2022-05-31 08:59:27 -0700443 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800444 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700445 else if (propertyName == "Protocol")
446 {
447 const std::string* value =
448 std::get_if<std::string>(&property.second);
449 if (value == nullptr)
450 {
451 BMCWEB_LOG_ERROR << "Illegal property: Protocol";
452 messages::internalError(asyncResp->res);
453 return;
454 }
455
456 std::optional<std::string> proto = convertDriveProtocol(*value);
457 if (!proto)
458 {
459 BMCWEB_LOG_ERROR << "Unsupported DrivePrototype Interface: "
460 << *value;
461 messages::internalError(asyncResp->res);
462 return;
463 }
464 asyncResp->res.jsonValue["Protocol"] = *proto;
465 }
466 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800467 });
468}
469
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700470inline void requestRoutesDrive(App& app)
471{
472 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700473 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700474 .methods(boost::beast::http::verb::get)(
475 [&app](const crow::Request& req,
476 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
477 const std::string& driveId) {
478 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
479 {
480 return;
481 }
482 crow::connections::systemBus->async_method_call(
483 [asyncResp,
484 driveId](const boost::system::error_code ec,
485 const dbus::utility::MapperGetSubTreeResponse& subtree) {
486 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700487 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700488 BMCWEB_LOG_ERROR << "Drive mapper call error";
489 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700490 return;
491 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700492
Ed Tanous002d39b2022-05-31 08:59:27 -0700493 auto drive = std::find_if(
494 subtree.begin(), subtree.end(),
495 [&driveId](
496 const std::pair<
497 std::string,
498 std::vector<std::pair<
499 std::string, std::vector<std::string>>>>& object) {
500 return sdbusplus::message::object_path(object.first)
501 .filename() == driveId;
502 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700503
Ed Tanous002d39b2022-05-31 08:59:27 -0700504 if (drive == subtree.end())
505 {
506 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
507 return;
508 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700509
Ed Tanous002d39b2022-05-31 08:59:27 -0700510 const std::string& path = drive->first;
511 const std::vector<std::pair<std::string, std::vector<std::string>>>&
512 connectionNames = drive->second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700513
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
515 asyncResp->res.jsonValue["@odata.id"] =
516 "/redfish/v1/Systems/system/Storage/1/Drives/" + driveId;
517 asyncResp->res.jsonValue["Name"] = driveId;
518 asyncResp->res.jsonValue["Id"] = driveId;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700519
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 if (connectionNames.size() != 1)
521 {
522 BMCWEB_LOG_ERROR << "Connection size " << connectionNames.size()
523 << ", not equal to 1";
524 messages::internalError(asyncResp->res);
525 return;
526 }
James Feiste284a7c2019-11-20 16:20:23 -0800527
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 getMainChassisId(
529 asyncResp, [](const std::string& chassisId,
530 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
531 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
532 "/redfish/v1/Chassis/" + chassisId;
533 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700534
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 // default it to Enabled
536 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700537
Ed Tanous002d39b2022-05-31 08:59:27 -0700538 auto health = std::make_shared<HealthPopulate>(asyncResp);
539 health->inventory.emplace_back(path);
540 health->populate();
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700541
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 const std::string& connectionName = connectionNames[0].first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700543
Ed Tanous002d39b2022-05-31 08:59:27 -0700544 for (const std::string& interface : connectionNames[0].second)
545 {
546 if (interface ==
547 "xyz.openbmc_project.Inventory.Decorator.Asset")
548 {
549 getDriveAsset(asyncResp, connectionName, path);
550 }
551 else if (interface == "xyz.openbmc_project.Inventory.Item")
552 {
553 getDrivePresent(asyncResp, connectionName, path);
554 }
555 else if (interface == "xyz.openbmc_project.State.Drive")
556 {
557 getDriveState(asyncResp, connectionName, path);
558 }
559 else if (interface ==
560 "xyz.openbmc_project.Inventory.Item.Drive")
561 {
562 getDriveItemProperties(asyncResp, connectionName, path);
563 }
564 }
565 },
566 "xyz.openbmc_project.ObjectMapper",
567 "/xyz/openbmc_project/object_mapper",
568 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
569 "/xyz/openbmc_project/inventory", int32_t(0),
570 std::array<const char*, 1>{
571 "xyz.openbmc_project.Inventory.Item.Drive"});
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700572 });
573}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700574
575/**
576 * Chassis drives, this URL will show all the DriveCollection
577 * information
578 */
579void chassisDriveCollectionGet(
580 crow::App& app, const crow::Request& req,
581 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
582 const std::string& chassisId)
583{
584 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
585 {
586 return;
587 }
588
589 // mapper call lambda
590 crow::connections::systemBus->async_method_call(
591 [asyncResp,
592 chassisId](const boost::system::error_code ec,
593 const dbus::utility::MapperGetSubTreeResponse& subtree) {
594 if (ec)
595 {
596 if (ec == boost::system::errc::host_unreachable)
597 {
598 messages::resourceNotFound(asyncResp->res, "Chassis",
599 chassisId);
600 return;
601 }
602 messages::internalError(asyncResp->res);
603 return;
604 }
605
606 // Iterate over all retrieved ObjectPaths.
607 for (const std::pair<
608 std::string,
609 std::vector<std::pair<std::string, std::vector<std::string>>>>&
610 object : subtree)
611 {
612 const std::string& path = object.first;
613 const dbus::utility::MapperGetObject& connectionNames =
614 object.second;
615
616 sdbusplus::message::object_path objPath(path);
617 if (objPath.filename() != chassisId)
618 {
619 continue;
620 }
621
622 if (connectionNames.empty())
623 {
624 BMCWEB_LOG_ERROR << "Got 0 Connection names";
625 continue;
626 }
627
628 asyncResp->res.jsonValue["@odata.type"] =
629 "#DriveCollection.DriveCollection";
630 asyncResp->res.jsonValue["@odata.id"] =
631 crow::utility::urlFromPieces("redfish", "v1",
632 "Chassis" + chassisId + "Drives");
633 asyncResp->res.jsonValue["Name"] = "Drive Collection";
634
635 // Association lambda
636 sdbusplus::asio::getProperty<std::vector<std::string>>(
637 *crow::connections::systemBus,
638 "xyz.openbmc_project.ObjectMapper", path + "/drive",
639 "xyz.openbmc_project.Association", "endpoints",
640 [asyncResp, chassisId](const boost::system::error_code ec3,
641 const std::vector<std::string>& resp) {
642 if (ec3)
643 {
644 BMCWEB_LOG_ERROR << "Error in chassis Drive association ";
645 }
646 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
647 // important if array is empty
648 members = nlohmann::json::array();
649
650 std::vector<std::string> leafNames;
651 for (const auto& drive : resp)
652 {
653 sdbusplus::message::object_path path(drive);
654 leafNames.push_back(path.filename());
655 }
656
657 std::sort(leafNames.begin(), leafNames.end(),
658 AlphanumLess<std::string>());
659
660 for (const auto& leafName : leafNames)
661 {
662 nlohmann::json::object_t member;
663 member["@odata.id"] = crow::utility::urlFromPieces(
664 "redfish", "v1", "Chassis", chassisId, "Drives",
665 leafName);
666 members.push_back(std::move(member));
667 // navigation links will be registered in next patch set
668 }
669 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
670 }); // end association lambda
671
672 } // end Iterate over all retrieved ObjectPaths
673 },
674 "xyz.openbmc_project.ObjectMapper",
675 "/xyz/openbmc_project/object_mapper",
676 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
677 "/xyz/openbmc_project/inventory", 0,
678 std::array<const char*, 2>{
679 "xyz.openbmc_project.Inventory.Item.Board",
680 "xyz.openbmc_project.Inventory.Item.Chassis"});
681}
682
683inline void requestRoutesChassisDrive(App& app)
684{
685 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
686 .privileges(redfish::privileges::getDriveCollection)
687 .methods(boost::beast::http::verb::get)(
688 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
689}
690
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700691} // namespace redfish