blob: 6809958e052d3b189e8964af3db167c3d658caac [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 Tanoused398212021-06-09 17:05:54 -070023#include <registries/privilege_registry.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070024#include <sdbusplus/asio/property.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070025
26namespace redfish
27{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070028inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070029{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070030 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070031 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070032 .methods(boost::beast::http::verb::get)(
33 [](const crow::Request&,
34 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
35 asyncResp->res.jsonValue["@odata.type"] =
36 "#StorageCollection.StorageCollection";
37 asyncResp->res.jsonValue["@odata.id"] =
38 "/redfish/v1/Systems/system/Storage";
39 asyncResp->res.jsonValue["Name"] = "Storage Collection";
40 asyncResp->res.jsonValue["Members"] = {
41 {{"@odata.id", "/redfish/v1/Systems/system/Storage/1"}}};
42 asyncResp->res.jsonValue["Members@odata.count"] = 1;
43 });
44}
Nikhil Potadea25aecc2019-08-23 16:35:26 -070045
John Edward Broadbent7e860f12021-04-08 15:57:16 -070046inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070047{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070048 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
Ed Tanoused398212021-06-09 17:05:54 -070049 .privileges(redfish::privileges::getStorage)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070050 .methods(
51 boost::beast::http::verb::
52 get)([](const crow::Request&,
53 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
54 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_7_1.Storage";
55 asyncResp->res.jsonValue["@odata.id"] =
56 "/redfish/v1/Systems/system/Storage/1";
57 asyncResp->res.jsonValue["Name"] = "Storage";
58 asyncResp->res.jsonValue["Id"] = "1";
59 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Nikhil Potadea25aecc2019-08-23 16:35:26 -070060
John Edward Broadbent7e860f12021-04-08 15:57:16 -070061 auto health = std::make_shared<HealthPopulate>(asyncResp);
62 health->populate();
Nikhil Potadea25aecc2019-08-23 16:35:26 -070063
John Edward Broadbent7e860f12021-04-08 15:57:16 -070064 crow::connections::systemBus->async_method_call(
65 [asyncResp,
66 health](const boost::system::error_code ec,
Ed Tanousb9d36b42022-02-26 21:42:46 -080067 const dbus::utility::MapperGetSubTreePathsResponse&
68 storageList) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -070069 nlohmann::json& storageArray =
70 asyncResp->res.jsonValue["Drives"];
71 storageArray = nlohmann::json::array();
72 auto& count =
73 asyncResp->res.jsonValue["Drives@odata.count"];
74 count = 0;
James Feiste284a7c2019-11-20 16:20:23 -080075
John Edward Broadbent7e860f12021-04-08 15:57:16 -070076 if (ec)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070077 {
John Edward Broadbent7e860f12021-04-08 15:57:16 -070078 BMCWEB_LOG_ERROR << "Drive mapper call error";
79 messages::internalError(asyncResp->res);
James Feiste284a7c2019-11-20 16:20:23 -080080 return;
81 }
82
John Edward Broadbent7e860f12021-04-08 15:57:16 -070083 health->inventory.insert(health->inventory.end(),
84 storageList.begin(),
85 storageList.end());
86
87 for (const std::string& objpath : storageList)
88 {
89 std::size_t lastPos = objpath.rfind('/');
90 if (lastPos == std::string::npos ||
91 (objpath.size() <= lastPos + 1))
92 {
93 BMCWEB_LOG_ERROR << "Failed to find '/' in "
94 << objpath;
95 continue;
96 }
97
98 storageArray.push_back(
99 {{"@odata.id",
100 "/redfish/v1/Systems/system/Storage/1/Drives/" +
101 objpath.substr(lastPos + 1)}});
102 }
103
104 count = storageArray.size();
105 },
106 "xyz.openbmc_project.ObjectMapper",
107 "/xyz/openbmc_project/object_mapper",
108 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
109 "/xyz/openbmc_project/inventory", int32_t(0),
110 std::array<const char*, 1>{
111 "xyz.openbmc_project.Inventory.Item.Drive"});
112
113 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800114 [asyncResp, health](
115 const boost::system::error_code ec,
116 const dbus::utility::MapperGetSubTreeResponse& subtree) {
Ed Tanous26f69762022-01-25 09:49:11 -0800117 if (ec || subtree.empty())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700118 {
119 // doesn't have to be there
120 return;
121 }
122
123 nlohmann::json& root =
124 asyncResp->res.jsonValue["StorageControllers"];
125 root = nlohmann::json::array();
126 for (const auto& [path, interfaceDict] : subtree)
127 {
128 std::size_t lastPos = path.rfind('/');
129 if (lastPos == std::string::npos ||
130 (path.size() <= lastPos + 1))
131 {
132 BMCWEB_LOG_ERROR << "Failed to find '/' in "
133 << path;
134 return;
135 }
136
137 if (interfaceDict.size() != 1)
138 {
139 BMCWEB_LOG_ERROR << "Connection size "
140 << interfaceDict.size()
141 << ", greater than 1";
142 messages::internalError(asyncResp->res);
143 return;
144 }
145
146 const std::string& connectionName =
147 interfaceDict.front().first;
148
149 size_t index = root.size();
150 nlohmann::json& storageController =
151 root.emplace_back(nlohmann::json::object());
152
153 std::string id = path.substr(lastPos + 1);
154
155 storageController["@odata.type"] =
156 "#Storage.v1_7_0.StorageController";
157 storageController["@odata.id"] =
George Liu0fda0f12021-11-16 10:06:17 +0800158 "/redfish/v1/Systems/system/Storage/1#/StorageControllers/" +
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700159 std::to_string(index);
160 storageController["Name"] = id;
161 storageController["MemberId"] = id;
162 storageController["Status"]["State"] = "Enabled";
163
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700164 sdbusplus::asio::getProperty<bool>(
165 *crow::connections::systemBus, connectionName, path,
166 "xyz.openbmc_project.Inventory.Item", "Present",
167 [asyncResp,
168 index](const boost::system::error_code ec2,
169 bool enabled) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700170 // this interface isn't necessary, only check it
171 // if we get a good return
172 if (ec2)
173 {
174 return;
175 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700176 if (!enabled)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700177 {
178 asyncResp->res
179 .jsonValue["StorageControllers"][index]
180 ["Status"]["State"] =
181 "Disabled";
182 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700183 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700184
185 crow::connections::systemBus->async_method_call(
186 [asyncResp, index](
187 const boost::system::error_code ec2,
Ed Tanous168e20c2021-12-13 14:39:53 -0800188 const std::vector<
189 std::pair<std::string,
190 dbus::utility::DbusVariantType>>&
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700191 propertiesList) {
192 if (ec2)
193 {
194 // this interface isn't necessary
195 return;
196 }
197 for (const std::pair<
198 std::string,
Ed Tanous168e20c2021-12-13 14:39:53 -0800199 dbus::utility::DbusVariantType>&
200 property : propertiesList)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700201 {
202 // Store DBus properties that are also
203 // Redfish properties with same name and a
204 // string value
205 const std::string& propertyName =
206 property.first;
207 nlohmann::json& object =
208 asyncResp->res
209 .jsonValue["StorageControllers"]
210 [index];
211 if ((propertyName == "PartNumber") ||
212 (propertyName == "SerialNumber") ||
213 (propertyName == "Manufacturer") ||
214 (propertyName == "Model"))
215 {
216 const std::string* value =
217 std::get_if<std::string>(
218 &property.second);
219 if (value == nullptr)
220 {
221 // illegal property
222 messages::internalError(
223 asyncResp->res);
224 return;
225 }
226 object[propertyName] = *value;
227 }
228 }
229 },
230 connectionName, path,
231 "org.freedesktop.DBus.Properties", "GetAll",
232 "xyz.openbmc_project.Inventory.Decorator.Asset");
233 }
234
235 // this is done after we know the json array will no longer
236 // be resized, as json::array uses vector underneath and we
237 // need references to its members that won't change
238 size_t count = 0;
239 for (const auto& [path, interfaceDict] : subtree)
240 {
241 auto subHealth = std::make_shared<HealthPopulate>(
242 asyncResp, root[count]["Status"]);
243 subHealth->inventory.emplace_back(path);
244 health->inventory.emplace_back(path);
245 health->children.emplace_back(subHealth);
246 count++;
247 }
248 },
249 "xyz.openbmc_project.ObjectMapper",
250 "/xyz/openbmc_project/object_mapper",
251 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
252 "/xyz/openbmc_project/inventory", int32_t(0),
253 std::array<const char*, 1>{
254 "xyz.openbmc_project.Inventory.Item.StorageController"});
255 });
256}
257
Willy Tu03913172021-11-08 02:03:19 -0800258inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
259 const std::string& connectionName,
260 const std::string& path)
261{
262 crow::connections::systemBus->async_method_call(
Ed Tanous168e20c2021-12-13 14:39:53 -0800263 [asyncResp](const boost::system::error_code ec,
264 const std::vector<
265 std::pair<std::string, dbus::utility::DbusVariantType>>&
266 propertiesList) {
Willy Tu03913172021-11-08 02:03:19 -0800267 if (ec)
268 {
269 // this interface isn't necessary
270 return;
271 }
Ed Tanous168e20c2021-12-13 14:39:53 -0800272 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
Willy Tu03913172021-11-08 02:03:19 -0800273 property : propertiesList)
274 {
275 // Store DBus properties that are also
276 // Redfish properties with same name and a
277 // string value
278 const std::string& propertyName = property.first;
279 if ((propertyName == "PartNumber") ||
280 (propertyName == "SerialNumber") ||
281 (propertyName == "Manufacturer") ||
282 (propertyName == "Model"))
283 {
284 const std::string* value =
285 std::get_if<std::string>(&property.second);
286 if (value == nullptr)
287 {
288 // illegal property
289 messages::internalError(asyncResp->res);
290 return;
291 }
292 asyncResp->res.jsonValue[propertyName] = *value;
293 }
294 }
295 },
296 connectionName, path, "org.freedesktop.DBus.Properties", "GetAll",
297 "xyz.openbmc_project.Inventory.Decorator.Asset");
298}
299
300inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
301 const std::string& connectionName,
302 const std::string& path)
303{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700304 sdbusplus::asio::getProperty<bool>(
305 *crow::connections::systemBus, connectionName, path,
306 "xyz.openbmc_project.Inventory.Item", "Present",
Willy Tu03913172021-11-08 02:03:19 -0800307 [asyncResp, path](const boost::system::error_code ec,
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700308 const bool enabled) {
Willy Tu03913172021-11-08 02:03:19 -0800309 // this interface isn't necessary, only check it if
310 // we get a good return
311 if (ec)
312 {
313 return;
314 }
315
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700316 if (!enabled)
Willy Tu03913172021-11-08 02:03:19 -0800317 {
318 asyncResp->res.jsonValue["Status"]["State"] = "Disabled";
319 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700320 });
Willy Tu03913172021-11-08 02:03:19 -0800321}
322
323inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
324 const std::string& connectionName,
325 const std::string& path)
326{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700327 sdbusplus::asio::getProperty<bool>(
328 *crow::connections::systemBus, connectionName, path,
329 "xyz.openbmc_project.State.Drive", "Rebuilding",
330 [asyncResp](const boost::system::error_code ec, const bool updating) {
Willy Tu03913172021-11-08 02:03:19 -0800331 // this interface isn't necessary, only check it
332 // if we get a good return
333 if (ec)
334 {
335 return;
336 }
337
Willy Tu03913172021-11-08 02:03:19 -0800338 // updating and disabled in the backend shouldn't be
339 // able to be set at the same time, so we don't need
340 // to check for the race condition of these two
341 // calls
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700342 if (updating)
Willy Tu03913172021-11-08 02:03:19 -0800343 {
344 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
345 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700346 });
Willy Tu03913172021-11-08 02:03:19 -0800347}
348
Willy Tu19b8e9a2021-11-08 02:55:03 -0800349inline std::optional<std::string> convertDriveType(const std::string& type)
350{
351 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
352 {
353 return "HDD";
354 }
355 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
356 {
357 return "SSD";
358 }
359
360 return std::nullopt;
361}
362
363inline std::optional<std::string> convertDriveProtocol(const std::string& proto)
364{
365 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
366 {
367 return "SAS";
368 }
369 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
370 {
371 return "SATA";
372 }
373 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
374 {
375 return "NVMe";
376 }
377 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
378 {
379 return "FC";
380 }
381
382 return std::nullopt;
383}
384
385inline void
386 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
387 const std::string& connectionName,
388 const std::string& path)
389{
390 sdbusplus::asio::getAllProperties(
391 *crow::connections::systemBus, connectionName, path,
392 "xyz.openbmc_project.Inventory.Item.Drive",
393 [asyncResp](const boost::system::error_code ec,
394 const std::vector<
395 std::pair<std::string, dbus::utility::DbusVariantType>>&
396 propertiesList) {
397 if (ec)
398 {
399 // this interface isn't required
400 return;
401 }
402 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
403 property : propertiesList)
404 {
405 const std::string& propertyName = property.first;
406 if (propertyName == "Type")
407 {
408 const std::string* value =
409 std::get_if<std::string>(&property.second);
410 if (value == nullptr)
411 {
412 // illegal property
413 BMCWEB_LOG_ERROR << "Illegal property: Type";
414 messages::internalError(asyncResp->res);
415 return;
416 }
417
418 std::optional<std::string> mediaType =
419 convertDriveType(*value);
420 if (!mediaType)
421 {
422 BMCWEB_LOG_ERROR << "Unsupported DriveType Interface: "
423 << *value;
424 messages::internalError(asyncResp->res);
425 return;
426 }
427
428 asyncResp->res.jsonValue["MediaType"] = *mediaType;
429 }
430 else if (propertyName == "Capacity")
431 {
432 const uint64_t* capacity =
433 std::get_if<uint64_t>(&property.second);
434 if (capacity == nullptr)
435 {
436 BMCWEB_LOG_ERROR << "Illegal property: Capacity";
437 messages::internalError(asyncResp->res);
438 return;
439 }
440 if (*capacity == 0)
441 {
442 // drive capacity not known
443 continue;
444 }
445
446 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
447 }
448 else if (propertyName == "Protocol")
449 {
450 const std::string* value =
451 std::get_if<std::string>(&property.second);
452 if (value == nullptr)
453 {
454 BMCWEB_LOG_ERROR << "Illegal property: Protocol";
455 messages::internalError(asyncResp->res);
456 return;
457 }
458
459 std::optional<std::string> proto =
460 convertDriveProtocol(*value);
461 if (!proto)
462 {
463 BMCWEB_LOG_ERROR
464 << "Unsupported DrivePrototype Interface: "
465 << *value;
466 messages::internalError(asyncResp->res);
467 return;
468 }
469 asyncResp->res.jsonValue["Protocol"] = *proto;
470 }
471 }
472 });
473}
474
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700475inline void requestRoutesDrive(App& app)
476{
477 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700478 .privileges(redfish::privileges::getDrive)
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700479 .methods(
480 boost::beast::http::verb::get)([](const crow::Request&,
481 const std::shared_ptr<
482 bmcweb::AsyncResp>& asyncResp,
483 const std::string& driveId) {
484 crow::connections::systemBus->async_method_call(
Ed Tanousb9d36b42022-02-26 21:42:46 -0800485 [asyncResp, driveId](
486 const boost::system::error_code ec,
487 const dbus::utility::MapperGetSubTreeResponse& subtree) {
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700488 if (ec)
489 {
490 BMCWEB_LOG_ERROR << "Drive mapper call error";
491 messages::internalError(asyncResp->res);
492 return;
493 }
494
Willy Tu03913172021-11-08 02:03:19 -0800495 auto drive = std::find_if(
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700496 subtree.begin(), subtree.end(),
Willy Tu03913172021-11-08 02:03:19 -0800497 [&driveId](const std::pair<
498 std::string,
499 std::vector<std::pair<
500 std::string, std::vector<std::string>>>>&
501 object) {
502 return sdbusplus::message::object_path(object.first)
503 .filename() == driveId;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700504 });
505
Willy Tu03913172021-11-08 02:03:19 -0800506 if (drive == subtree.end())
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700507 {
508 messages::resourceNotFound(asyncResp->res, "Drive",
509 driveId);
510 return;
511 }
512
Willy Tu03913172021-11-08 02:03:19 -0800513 const std::string& path = drive->first;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700514 const std::vector<
515 std::pair<std::string, std::vector<std::string>>>&
Willy Tu03913172021-11-08 02:03:19 -0800516 connectionNames = drive->second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700517
518 asyncResp->res.jsonValue["@odata.type"] =
519 "#Drive.v1_7_0.Drive";
520 asyncResp->res.jsonValue["@odata.id"] =
521 "/redfish/v1/Systems/system/Storage/1/Drives/" +
522 driveId;
523 asyncResp->res.jsonValue["Name"] = driveId;
524 asyncResp->res.jsonValue["Id"] = driveId;
525
526 if (connectionNames.size() != 1)
James Feiste284a7c2019-11-20 16:20:23 -0800527 {
528 BMCWEB_LOG_ERROR << "Connection size "
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700529 << connectionNames.size()
Willy Tu03913172021-11-08 02:03:19 -0800530 << ", not equal to 1";
James Feiste284a7c2019-11-20 16:20:23 -0800531 messages::internalError(asyncResp->res);
532 return;
533 }
534
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700535 getMainChassisId(
536 asyncResp,
537 [](const std::string& chassisId,
538 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
539 aRsp->res.jsonValue["Links"]["Chassis"] = {
540 {"@odata.id",
541 "/redfish/v1/Chassis/" + chassisId}};
542 });
543
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700544 // default it to Enabled
545 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
546
547 auto health = std::make_shared<HealthPopulate>(asyncResp);
James Feiste284a7c2019-11-20 16:20:23 -0800548 health->inventory.emplace_back(path);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700549 health->populate();
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700550
Willy Tu03913172021-11-08 02:03:19 -0800551 const std::string& connectionName =
552 connectionNames[0].first;
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700553
Willy Tu03913172021-11-08 02:03:19 -0800554 getDriveAsset(asyncResp, connectionName, path);
555 getDrivePresent(asyncResp, connectionName, path);
556 getDriveState(asyncResp, connectionName, path);
Willy Tu19b8e9a2021-11-08 02:55:03 -0800557 getDriveItemProperties(asyncResp, connectionName, path);
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700558 },
559 "xyz.openbmc_project.ObjectMapper",
560 "/xyz/openbmc_project/object_mapper",
561 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
562 "/xyz/openbmc_project/inventory", int32_t(0),
563 std::array<const char*, 1>{
564 "xyz.openbmc_project.Inventory.Item.Drive"});
565 });
566}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700567} // namespace redfish