blob: a77bb91d86a1671b62d794605f83f79908b81294 [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
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080018#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080019#include "dbus_utility.hpp"
John Edward Broadbente5029d82022-06-08 14:35:21 -070020#include "generated/enums/drive.hpp"
George Liudde9bc12023-02-22 09:35:51 +080021#include "generated/enums/protocol.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070022#include "health.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080023#include "human_sort.hpp"
James Feiste284a7c2019-11-20 16:20:23 -080024#include "openbmc_dbus_rest.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080025#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080026#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080027#include "registries/privilege_registry.hpp"
28#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070029
George Liue99073f2022-12-09 11:06:16 +080030#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070031#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070032#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020033#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070034
George Liu7a1dbc42022-12-07 16:03:22 +080035#include <array>
36#include <string_view>
37
Nikhil Potadea25aecc2019-08-23 16:35:26 -070038namespace redfish
39{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070040inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070041{
Ed Tanous22d268c2022-05-19 09:39:07 -070042 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070043 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070044 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070045 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -070046 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
47 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +000048 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070049 {
50 return;
51 }
Ed Tanous22d268c2022-05-19 09:39:07 -070052 if (systemName != "system")
53 {
54 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
55 systemName);
56 return;
57 }
58
Ed Tanous002d39b2022-05-31 08:59:27 -070059 asyncResp->res.jsonValue["@odata.type"] =
60 "#StorageCollection.StorageCollection";
61 asyncResp->res.jsonValue["@odata.id"] =
62 "/redfish/v1/Systems/system/Storage";
63 asyncResp->res.jsonValue["Name"] = "Storage Collection";
64 nlohmann::json::array_t members;
65 nlohmann::json::object_t member;
66 member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
67 members.emplace_back(member);
68 asyncResp->res.jsonValue["Members"] = std::move(members);
69 asyncResp->res.jsonValue["Members@odata.count"] = 1;
70 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -070071}
Nikhil Potadea25aecc2019-08-23 16:35:26 -070072
Willy Tua85afbe2021-12-28 14:43:47 -080073inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
74 const std::shared_ptr<HealthPopulate>& health)
75{
George Liu7a1dbc42022-12-07 16:03:22 +080076 const std::array<std::string_view, 1> interfaces = {
77 "xyz.openbmc_project.Inventory.Item.Drive"};
78 dbus::utility::getSubTreePaths(
79 "/xyz/openbmc_project/inventory", 0, interfaces,
Willy Tua85afbe2021-12-28 14:43:47 -080080 [asyncResp, health](
George Liu7a1dbc42022-12-07 16:03:22 +080081 const boost::system::error_code& ec,
Willy Tua85afbe2021-12-28 14:43:47 -080082 const dbus::utility::MapperGetSubTreePathsResponse& driveList) {
83 if (ec)
84 {
85 BMCWEB_LOG_ERROR << "Drive mapper call error";
86 messages::internalError(asyncResp->res);
87 return;
88 }
89
90 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
91 driveArray = nlohmann::json::array();
92 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
93 count = 0;
94
95 health->inventory.insert(health->inventory.end(), driveList.begin(),
96 driveList.end());
97
98 for (const std::string& drive : driveList)
99 {
100 sdbusplus::message::object_path object(drive);
101 if (object.filename().empty())
102 {
103 BMCWEB_LOG_ERROR << "Failed to find filename in " << drive;
104 return;
105 }
106
107 nlohmann::json::object_t driveJson;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700108 driveJson["@odata.id"] = boost::urls::format(
109 "/redfish/v1/Systems/system/Storage/1/Drives/{}",
Willy Tueddfc432022-09-26 16:46:38 +0000110 object.filename());
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500111 driveArray.emplace_back(std::move(driveJson));
Willy Tua85afbe2021-12-28 14:43:47 -0800112 }
113
114 count = driveArray.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800115 });
Willy Tua85afbe2021-12-28 14:43:47 -0800116}
117
118inline void
119 getStorageControllers(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
120 const std::shared_ptr<HealthPopulate>& health)
121{
George Liue99073f2022-12-09 11:06:16 +0800122 constexpr std::array<std::string_view, 1> interfaces = {
123 "xyz.openbmc_project.Inventory.Item.StorageController"};
124 dbus::utility::getSubTree(
125 "/xyz/openbmc_project/inventory", 0, interfaces,
Willy Tua85afbe2021-12-28 14:43:47 -0800126 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800127 health](const boost::system::error_code& ec,
Willy Tua85afbe2021-12-28 14:43:47 -0800128 const dbus::utility::MapperGetSubTreeResponse& subtree) {
129 if (ec || subtree.empty())
130 {
131 // doesn't have to be there
132 return;
133 }
134
135 nlohmann::json& root = asyncResp->res.jsonValue["StorageControllers"];
136 root = nlohmann::json::array();
137 for (const auto& [path, interfaceDict] : subtree)
138 {
139 sdbusplus::message::object_path object(path);
140 std::string id = object.filename();
141 if (id.empty())
142 {
143 BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
144 return;
145 }
146
147 if (interfaceDict.size() != 1)
148 {
149 BMCWEB_LOG_ERROR << "Connection size " << interfaceDict.size()
150 << ", greater than 1";
151 messages::internalError(asyncResp->res);
152 return;
153 }
154
155 const std::string& connectionName = interfaceDict.front().first;
156
157 size_t index = root.size();
158 nlohmann::json& storageController =
159 root.emplace_back(nlohmann::json::object());
160
161 storageController["@odata.type"] =
162 "#Storage.v1_7_0.StorageController";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700163 storageController["@odata.id"] = boost::urls::format(
164 "/redfish/v1/Systems/system/Storage/1#{}",
165 ("/StorageControllers"_json_pointer / index).to_string());
Willy Tua85afbe2021-12-28 14:43:47 -0800166 storageController["Name"] = id;
167 storageController["MemberId"] = id;
168 storageController["Status"]["State"] = "Enabled";
169
170 sdbusplus::asio::getProperty<bool>(
171 *crow::connections::systemBus, connectionName, path,
172 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800173 [asyncResp, index](const boost::system::error_code& ec2,
Willy Tucef57e82022-12-15 16:42:02 -0800174 bool isPresent) {
Willy Tua85afbe2021-12-28 14:43:47 -0800175 // this interface isn't necessary, only check it
176 // if we get a good return
177 if (ec2)
178 {
179 return;
180 }
Willy Tucef57e82022-12-15 16:42:02 -0800181 if (!isPresent)
Willy Tua85afbe2021-12-28 14:43:47 -0800182 {
183 asyncResp->res.jsonValue["StorageControllers"][index]
Willy Tucef57e82022-12-15 16:42:02 -0800184 ["Status"]["State"] = "Absent";
Willy Tua85afbe2021-12-28 14:43:47 -0800185 }
186 });
187
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200188 sdbusplus::asio::getAllProperties(
189 *crow::connections::systemBus, connectionName, path,
190 "xyz.openbmc_project.Inventory.Decorator.Asset",
Willy Tua85afbe2021-12-28 14:43:47 -0800191 [asyncResp, index](
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800192 const boost::system::error_code& ec2,
Willy Tua85afbe2021-12-28 14:43:47 -0800193 const std::vector<
194 std::pair<std::string, dbus::utility::DbusVariantType>>&
195 propertiesList) {
196 if (ec2)
197 {
198 // this interface isn't necessary
199 return;
200 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200201
202 const std::string* partNumber = nullptr;
203 const std::string* serialNumber = nullptr;
204 const std::string* manufacturer = nullptr;
205 const std::string* model = nullptr;
206
207 const bool success = sdbusplus::unpackPropertiesNoThrow(
208 dbus_utils::UnpackErrorPrinter(), propertiesList,
209 "PartNumber", partNumber, "SerialNumber", serialNumber,
210 "Manufacturer", manufacturer, "Model", model);
211
212 if (!success)
Willy Tua85afbe2021-12-28 14:43:47 -0800213 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200214 messages::internalError(asyncResp->res);
215 return;
Willy Tua85afbe2021-12-28 14:43:47 -0800216 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200217
218 nlohmann::json& controller =
219 asyncResp->res.jsonValue["StorageControllers"][index];
220
221 if (partNumber != nullptr)
222 {
223 controller["PartNumber"] = *partNumber;
224 }
225
226 if (serialNumber != nullptr)
227 {
228 controller["SerialNumber"] = *serialNumber;
229 }
230
231 if (manufacturer != nullptr)
232 {
233 controller["Manufacturer"] = *manufacturer;
234 }
235
236 if (model != nullptr)
237 {
238 controller["Model"] = *model;
239 }
240 });
Willy Tua85afbe2021-12-28 14:43:47 -0800241 }
242
243 // this is done after we know the json array will no longer
244 // be resized, as json::array uses vector underneath and we
245 // need references to its members that won't change
246 size_t count = 0;
247 // Pointer based on |asyncResp->res.jsonValue|
248 nlohmann::json::json_pointer rootPtr =
249 "/StorageControllers"_json_pointer;
250 for (const auto& [path, interfaceDict] : subtree)
251 {
252 auto subHealth = std::make_shared<HealthPopulate>(
253 asyncResp, rootPtr / count / "Status");
254 subHealth->inventory.emplace_back(path);
255 health->inventory.emplace_back(path);
256 health->children.emplace_back(subHealth);
257 count++;
258 }
George Liue99073f2022-12-09 11:06:16 +0800259 });
Willy Tua85afbe2021-12-28 14:43:47 -0800260}
261
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700262inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700263{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700264 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
Ed Tanoused398212021-06-09 17:05:54 -0700265 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700266 .methods(boost::beast::http::verb::get)(
267 [&app](const crow::Request& req,
268 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000269 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700270 {
271 return;
272 }
273 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
274 asyncResp->res.jsonValue["@odata.id"] =
275 "/redfish/v1/Systems/system/Storage/1";
276 asyncResp->res.jsonValue["Name"] = "Storage";
277 asyncResp->res.jsonValue["Id"] = "1";
278 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
279
280 auto health = std::make_shared<HealthPopulate>(asyncResp);
281 health->populate();
282
Willy Tua85afbe2021-12-28 14:43:47 -0800283 getDrives(asyncResp, health);
284 getStorageControllers(asyncResp, health);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700285 });
286}
287
Willy Tu03913172021-11-08 02:03:19 -0800288inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
289 const std::string& connectionName,
290 const std::string& path)
291{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200292 sdbusplus::asio::getAllProperties(
293 *crow::connections::systemBus, connectionName, path,
294 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800295 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800296 const std::vector<
297 std::pair<std::string, dbus::utility::DbusVariantType>>&
298 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700299 if (ec)
300 {
301 // this interface isn't necessary
302 return;
303 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200304
305 const std::string* partNumber = nullptr;
306 const std::string* serialNumber = nullptr;
307 const std::string* manufacturer = nullptr;
308 const std::string* model = nullptr;
309
310 const bool success = sdbusplus::unpackPropertiesNoThrow(
311 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
312 partNumber, "SerialNumber", serialNumber, "Manufacturer",
313 manufacturer, "Model", model);
314
315 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700316 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200317 messages::internalError(asyncResp->res);
318 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700319 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200320
321 if (partNumber != nullptr)
322 {
323 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
324 }
325
326 if (serialNumber != nullptr)
327 {
328 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
329 }
330
331 if (manufacturer != nullptr)
332 {
333 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
334 }
335
336 if (model != nullptr)
337 {
338 asyncResp->res.jsonValue["Model"] = *model;
339 }
340 });
Willy Tu03913172021-11-08 02:03:19 -0800341}
342
343inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
344 const std::string& connectionName,
345 const std::string& path)
346{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700347 sdbusplus::asio::getProperty<bool>(
348 *crow::connections::systemBus, connectionName, path,
349 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800350 [asyncResp, path](const boost::system::error_code& ec,
Willy Tucef57e82022-12-15 16:42:02 -0800351 const bool isPresent) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700352 // this interface isn't necessary, only check it if
353 // we get a good return
354 if (ec)
355 {
356 return;
357 }
Willy Tu03913172021-11-08 02:03:19 -0800358
Willy Tucef57e82022-12-15 16:42:02 -0800359 if (!isPresent)
Ed Tanous002d39b2022-05-31 08:59:27 -0700360 {
Willy Tucef57e82022-12-15 16:42:02 -0800361 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Ed Tanous002d39b2022-05-31 08:59:27 -0700362 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700363 });
Willy Tu03913172021-11-08 02:03:19 -0800364}
365
366inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
367 const std::string& connectionName,
368 const std::string& path)
369{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700370 sdbusplus::asio::getProperty<bool>(
371 *crow::connections::systemBus, connectionName, path,
372 "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800373 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700374 // this interface isn't necessary, only check it
375 // if we get a good return
376 if (ec)
377 {
378 return;
379 }
Willy Tu03913172021-11-08 02:03:19 -0800380
Ed Tanous002d39b2022-05-31 08:59:27 -0700381 // updating and disabled in the backend shouldn't be
382 // able to be set at the same time, so we don't need
383 // to check for the race condition of these two
384 // calls
385 if (updating)
386 {
387 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
388 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700389 });
Willy Tu03913172021-11-08 02:03:19 -0800390}
391
George Liudde9bc12023-02-22 09:35:51 +0800392inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800393{
394 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
395 {
George Liudde9bc12023-02-22 09:35:51 +0800396 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800397 }
398 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
399 {
George Liudde9bc12023-02-22 09:35:51 +0800400 return drive::MediaType::SSD;
401 }
402 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
403 {
404 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800405 }
406
George Liudde9bc12023-02-22 09:35:51 +0800407 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800408}
409
George Liudde9bc12023-02-22 09:35:51 +0800410inline std::optional<protocol::Protocol>
411 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800412{
413 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
414 {
George Liudde9bc12023-02-22 09:35:51 +0800415 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800416 }
417 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
418 {
George Liudde9bc12023-02-22 09:35:51 +0800419 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800420 }
421 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
422 {
George Liudde9bc12023-02-22 09:35:51 +0800423 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800424 }
425 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
426 {
George Liudde9bc12023-02-22 09:35:51 +0800427 return protocol::Protocol::FC;
428 }
429 if (proto ==
430 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
431 {
432 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800433 }
434
George Liudde9bc12023-02-22 09:35:51 +0800435 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800436}
437
438inline void
439 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
440 const std::string& connectionName,
441 const std::string& path)
442{
443 sdbusplus::asio::getAllProperties(
444 *crow::connections::systemBus, connectionName, path,
445 "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800446 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800447 const std::vector<
448 std::pair<std::string, dbus::utility::DbusVariantType>>&
449 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700450 if (ec)
451 {
452 // this interface isn't required
453 return;
454 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700455 const std::string* encryptionStatus = nullptr;
456 const bool* isLocked = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700457 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
458 property : propertiesList)
459 {
460 const std::string& propertyName = property.first;
461 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800462 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700463 const std::string* value =
464 std::get_if<std::string>(&property.second);
465 if (value == nullptr)
466 {
467 // illegal property
468 BMCWEB_LOG_ERROR << "Illegal property: Type";
469 messages::internalError(asyncResp->res);
470 return;
471 }
472
George Liudde9bc12023-02-22 09:35:51 +0800473 std::optional<drive::MediaType> mediaType =
474 convertDriveType(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700475 if (!mediaType)
476 {
George Liudde9bc12023-02-22 09:35:51 +0800477 BMCWEB_LOG_WARNING << "UnknownDriveType Interface: "
478 << *value;
479 continue;
480 }
481 if (*mediaType == drive::MediaType::Invalid)
482 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700483 messages::internalError(asyncResp->res);
484 return;
485 }
486
487 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800488 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700489 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800490 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700491 const uint64_t* capacity =
492 std::get_if<uint64_t>(&property.second);
493 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800494 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700495 BMCWEB_LOG_ERROR << "Illegal property: Capacity";
496 messages::internalError(asyncResp->res);
497 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800498 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700499 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800500 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700501 // drive capacity not known
502 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800503 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800504
Ed Tanous002d39b2022-05-31 08:59:27 -0700505 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800506 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700507 else if (propertyName == "Protocol")
508 {
509 const std::string* value =
510 std::get_if<std::string>(&property.second);
511 if (value == nullptr)
512 {
513 BMCWEB_LOG_ERROR << "Illegal property: Protocol";
514 messages::internalError(asyncResp->res);
515 return;
516 }
517
George Liudde9bc12023-02-22 09:35:51 +0800518 std::optional<protocol::Protocol> proto =
519 convertDriveProtocol(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 if (!proto)
521 {
George Liudde9bc12023-02-22 09:35:51 +0800522 BMCWEB_LOG_WARNING << "Unknown DrivePrototype Interface: "
523 << *value;
524 continue;
525 }
526 if (*proto == protocol::Protocol::Invalid)
527 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700528 messages::internalError(asyncResp->res);
529 return;
530 }
531 asyncResp->res.jsonValue["Protocol"] = *proto;
532 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700533 else if (propertyName == "PredictedMediaLifeLeftPercent")
534 {
535 const uint8_t* lifeLeft =
536 std::get_if<uint8_t>(&property.second);
537 if (lifeLeft == nullptr)
538 {
539 BMCWEB_LOG_ERROR
540 << "Illegal property: PredictedMediaLifeLeftPercent";
541 messages::internalError(asyncResp->res);
542 return;
543 }
544 // 255 means reading the value is not supported
545 if (*lifeLeft != 255)
546 {
547 asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
548 *lifeLeft;
549 }
550 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700551 else if (propertyName == "EncryptionStatus")
552 {
553 encryptionStatus = std::get_if<std::string>(&property.second);
554 if (encryptionStatus == nullptr)
555 {
556 BMCWEB_LOG_ERROR << "Illegal property: EncryptionStatus";
557 messages::internalError(asyncResp->res);
558 return;
559 }
560 }
561 else if (propertyName == "Locked")
562 {
563 isLocked = std::get_if<bool>(&property.second);
564 if (isLocked == nullptr)
565 {
566 BMCWEB_LOG_ERROR << "Illegal property: Locked";
567 messages::internalError(asyncResp->res);
568 return;
569 }
570 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700571 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700572
573 if (encryptionStatus == nullptr || isLocked == nullptr ||
574 *encryptionStatus ==
575 "xyz.openbmc_project.Drive.DriveEncryptionState.Unknown")
576 {
577 return;
578 }
579 if (*encryptionStatus !=
580 "xyz.openbmc_project.Drive.DriveEncryptionState.Encrypted")
581 {
582 //"The drive is not currently encrypted."
583 asyncResp->res.jsonValue["EncryptionStatus"] =
584 drive::EncryptionStatus::Unencrypted;
585 return;
586 }
587 if (*isLocked)
588 {
589 //"The drive is currently encrypted and the data is not
590 // accessible to the user."
591 asyncResp->res.jsonValue["EncryptionStatus"] =
592 drive::EncryptionStatus::Locked;
593 return;
594 }
595 // if not locked
596 // "The drive is currently encrypted but the data is accessible
597 // to the user in unencrypted form."
598 asyncResp->res.jsonValue["EncryptionStatus"] =
599 drive::EncryptionStatus::Unlocked;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800600 });
601}
602
Nan Zhoub53dcd92022-06-21 17:47:50 +0000603static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
604 const std::string& connectionName,
605 const std::string& path,
606 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700607{
608 for (const std::string& interface : interfaces)
609 {
610 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
611 {
612 getDriveAsset(asyncResp, connectionName, path);
613 }
614 else if (interface == "xyz.openbmc_project.Inventory.Item")
615 {
616 getDrivePresent(asyncResp, connectionName, path);
617 }
618 else if (interface == "xyz.openbmc_project.State.Drive")
619 {
620 getDriveState(asyncResp, connectionName, path);
621 }
622 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
623 {
624 getDriveItemProperties(asyncResp, connectionName, path);
625 }
626 }
627}
628
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700629inline void requestRoutesDrive(App& app)
630{
Ed Tanous22d268c2022-05-19 09:39:07 -0700631 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700632 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700633 .methods(boost::beast::http::verb::get)(
634 [&app](const crow::Request& req,
635 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -0700636 const std::string& systemName, const std::string& driveId) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000637 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700638 {
639 return;
640 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700641 if (systemName != "system")
642 {
643 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
644 systemName);
645 return;
646 }
647
George Liue99073f2022-12-09 11:06:16 +0800648 constexpr std::array<std::string_view, 1> interfaces = {
649 "xyz.openbmc_project.Inventory.Item.Drive"};
650 dbus::utility::getSubTree(
651 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700652 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800653 driveId](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700654 const dbus::utility::MapperGetSubTreeResponse& subtree) {
655 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700656 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700657 BMCWEB_LOG_ERROR << "Drive mapper call error";
658 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700659 return;
660 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700661
Ed Tanous002d39b2022-05-31 08:59:27 -0700662 auto drive = std::find_if(
663 subtree.begin(), subtree.end(),
664 [&driveId](
Nan Zhou8cb65f82022-06-15 05:12:24 +0000665 const std::pair<std::string,
666 dbus::utility::MapperServiceMap>& object) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700667 return sdbusplus::message::object_path(object.first)
668 .filename() == driveId;
669 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700670
Ed Tanous002d39b2022-05-31 08:59:27 -0700671 if (drive == subtree.end())
672 {
673 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
674 return;
675 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700676
Ed Tanous002d39b2022-05-31 08:59:27 -0700677 const std::string& path = drive->first;
Nan Zhou8cb65f82022-06-15 05:12:24 +0000678 const dbus::utility::MapperServiceMap& connectionNames =
679 drive->second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700680
Ed Tanous002d39b2022-05-31 08:59:27 -0700681 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700682 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
683 "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700684 asyncResp->res.jsonValue["Name"] = driveId;
685 asyncResp->res.jsonValue["Id"] = driveId;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700686
Ed Tanous002d39b2022-05-31 08:59:27 -0700687 if (connectionNames.size() != 1)
688 {
689 BMCWEB_LOG_ERROR << "Connection size " << connectionNames.size()
690 << ", not equal to 1";
691 messages::internalError(asyncResp->res);
692 return;
693 }
James Feiste284a7c2019-11-20 16:20:23 -0800694
Ed Tanous002d39b2022-05-31 08:59:27 -0700695 getMainChassisId(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700696 asyncResp,
697 [](const std::string& chassisId,
698 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
699 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
700 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700701 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700702
Ed Tanous002d39b2022-05-31 08:59:27 -0700703 // default it to Enabled
704 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700705
Ed Tanous002d39b2022-05-31 08:59:27 -0700706 auto health = std::make_shared<HealthPopulate>(asyncResp);
707 health->inventory.emplace_back(path);
708 health->populate();
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700709
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700710 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
711 connectionNames[0].second);
George Liue99073f2022-12-09 11:06:16 +0800712 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700713 });
714}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700715
716/**
717 * Chassis drives, this URL will show all the DriveCollection
718 * information
719 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000720inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700721 crow::App& app, const crow::Request& req,
722 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
723 const std::string& chassisId)
724{
Carson Labrado3ba00072022-06-06 19:40:56 +0000725 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700726 {
727 return;
728 }
729
730 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800731 constexpr std::array<std::string_view, 2> interfaces = {
732 "xyz.openbmc_project.Inventory.Item.Board",
733 "xyz.openbmc_project.Inventory.Item.Chassis"};
734 dbus::utility::getSubTree(
735 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700736 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800737 chassisId](const boost::system::error_code& ec,
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700738 const dbus::utility::MapperGetSubTreeResponse& subtree) {
739 if (ec)
740 {
741 if (ec == boost::system::errc::host_unreachable)
742 {
743 messages::resourceNotFound(asyncResp->res, "Chassis",
744 chassisId);
745 return;
746 }
747 messages::internalError(asyncResp->res);
748 return;
749 }
750
751 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000752 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700753 {
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700754 sdbusplus::message::object_path objPath(path);
755 if (objPath.filename() != chassisId)
756 {
757 continue;
758 }
759
760 if (connectionNames.empty())
761 {
762 BMCWEB_LOG_ERROR << "Got 0 Connection names";
763 continue;
764 }
765
766 asyncResp->res.jsonValue["@odata.type"] =
767 "#DriveCollection.DriveCollection";
768 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700769 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700770 asyncResp->res.jsonValue["Name"] = "Drive Collection";
771
772 // Association lambda
George Liu6c3e9452023-03-03 13:55:29 +0800773 dbus::utility::getAssociationEndPoints(
774 path + "/drive",
775 [asyncResp,
776 chassisId](const boost::system::error_code& ec3,
777 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700778 if (ec3)
779 {
780 BMCWEB_LOG_ERROR << "Error in chassis Drive association ";
781 }
782 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
783 // important if array is empty
784 members = nlohmann::json::array();
785
786 std::vector<std::string> leafNames;
787 for (const auto& drive : resp)
788 {
Ed Tanous8a592812022-06-04 09:06:59 -0700789 sdbusplus::message::object_path drivePath(drive);
790 leafNames.push_back(drivePath.filename());
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700791 }
792
793 std::sort(leafNames.begin(), leafNames.end(),
794 AlphanumLess<std::string>());
795
796 for (const auto& leafName : leafNames)
797 {
798 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700799 member["@odata.id"] =
800 boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}",
801 chassisId, leafName);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500802 members.emplace_back(std::move(member));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700803 // navigation links will be registered in next patch set
804 }
805 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
806 }); // end association lambda
807
Patrick Williams89492a12023-05-10 07:51:34 -0500808 } // end Iterate over all retrieved ObjectPaths
George Liue99073f2022-12-09 11:06:16 +0800809 });
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700810}
811
812inline void requestRoutesChassisDrive(App& app)
813{
814 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
815 .privileges(redfish::privileges::getDriveCollection)
816 .methods(boost::beast::http::verb::get)(
817 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
818}
819
Nan Zhoub53dcd92022-06-21 17:47:50 +0000820inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
821 const std::string& chassisId,
822 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800823 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000824 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700825{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700826 if (ec)
827 {
828 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
829 messages::internalError(asyncResp->res);
830 return;
831 }
832
833 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000834 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700835 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700836 sdbusplus::message::object_path objPath(path);
837 if (objPath.filename() != driveName)
838 {
839 continue;
840 }
841
842 if (connectionNames.empty())
843 {
844 BMCWEB_LOG_ERROR << "Got 0 Connection names";
845 continue;
846 }
847
Ed Tanousef4c65b2023-04-24 15:28:50 -0700848 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
849 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700850
851 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700852 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700853 asyncResp->res.jsonValue["Id"] = driveName;
854 // default it to Enabled
855 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
856
857 nlohmann::json::object_t linkChassisNav;
858 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700859 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700860 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
861
862 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
863 connectionNames[0].second);
864 }
865}
866
Nan Zhoub53dcd92022-06-21 17:47:50 +0000867inline void
868 matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
869 const std::string& chassisId,
870 const std::string& driveName,
871 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700872{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700873 for (const std::string& drivePath : resp)
874 {
875 sdbusplus::message::object_path path(drivePath);
876 std::string leaf = path.filename();
877 if (leaf != driveName)
878 {
879 continue;
880 }
881 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800882 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700883 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800884 dbus::utility::getSubTree(
885 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700886 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800887 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700888 const dbus::utility::MapperGetSubTreeResponse& subtree) {
889 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
George Liue99073f2022-12-09 11:06:16 +0800890 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700891 }
892}
893
Nan Zhoub53dcd92022-06-21 17:47:50 +0000894inline void
895 handleChassisDriveGet(crow::App& app, const crow::Request& req,
896 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
897 const std::string& chassisId,
898 const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700899{
Michal Orzel03810a12022-06-15 14:04:28 +0200900 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700901 {
902 return;
903 }
George Liue99073f2022-12-09 11:06:16 +0800904 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700905 "xyz.openbmc_project.Inventory.Item.Board",
906 "xyz.openbmc_project.Inventory.Item.Chassis"};
907
908 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800909 dbus::utility::getSubTree(
910 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700911 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800912 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700913 const dbus::utility::MapperGetSubTreeResponse& subtree) {
914 if (ec)
915 {
916 messages::internalError(asyncResp->res);
917 return;
918 }
919
920 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000921 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700922 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700923 sdbusplus::message::object_path objPath(path);
924 if (objPath.filename() != chassisId)
925 {
926 continue;
927 }
928
929 if (connectionNames.empty())
930 {
931 BMCWEB_LOG_ERROR << "Got 0 Connection names";
932 continue;
933 }
934
George Liu6c3e9452023-03-03 13:55:29 +0800935 dbus::utility::getAssociationEndPoints(
936 path + "/drive",
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700937 [asyncResp, chassisId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800938 driveName](const boost::system::error_code& ec3,
George Liu6c3e9452023-03-03 13:55:29 +0800939 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700940 if (ec3)
941 {
942 return; // no drives = no failures
943 }
944 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
945 });
946 break;
947 }
George Liue99073f2022-12-09 11:06:16 +0800948 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700949}
950
951/**
952 * This URL will show the drive interface for the specific drive in the chassis
953 */
954inline void requestRoutesChassisDriveName(App& app)
955{
956 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
957 .privileges(redfish::privileges::getChassis)
958 .methods(boost::beast::http::verb::get)(
959 std::bind_front(handleChassisDriveGet, std::ref(app)));
960}
961
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700962} // namespace redfish