blob: 44b7746c7fe84776476fe353c5b0c505bc4eedb4 [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
Willy Tu13451e32023-05-24 16:08:18 -070018#include "bmcweb_config.h"
19
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080020#include "app.hpp"
George Liu7a1dbc42022-12-07 16:03:22 +080021#include "dbus_utility.hpp"
John Edward Broadbente5029d82022-06-08 14:35:21 -070022#include "generated/enums/drive.hpp"
George Liudde9bc12023-02-22 09:35:51 +080023#include "generated/enums/protocol.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070024#include "health.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080025#include "human_sort.hpp"
James Feiste284a7c2019-11-20 16:20:23 -080026#include "openbmc_dbus_rest.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080027#include "query.hpp"
Ed Tanousa8e884f2023-01-13 17:40:03 -080028#include "redfish_util.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080029#include "registries/privilege_registry.hpp"
30#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070031
George Liue99073f2022-12-09 11:06:16 +080032#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070033#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070034#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020035#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070036
George Liu7a1dbc42022-12-07 16:03:22 +080037#include <array>
38#include <string_view>
39
Nikhil Potadea25aecc2019-08-23 16:35:26 -070040namespace redfish
41{
John Edward Broadbent7e860f12021-04-08 15:57:16 -070042inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070043{
Ed Tanous22d268c2022-05-19 09:39:07 -070044 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070045 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070046 .methods(boost::beast::http::verb::get)(
Ed Tanous45ca1b82022-03-25 13:07:27 -070047 [&app](const crow::Request& req,
Ed Tanous22d268c2022-05-19 09:39:07 -070048 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
49 const std::string& systemName) {
Carson Labrado3ba00072022-06-06 19:40:56 +000050 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -070051 {
52 return;
53 }
Ed Tanous22d268c2022-05-19 09:39:07 -070054 if (systemName != "system")
55 {
56 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
57 systemName);
58 return;
59 }
60
Ed Tanous002d39b2022-05-31 08:59:27 -070061 asyncResp->res.jsonValue["@odata.type"] =
62 "#StorageCollection.StorageCollection";
63 asyncResp->res.jsonValue["@odata.id"] =
64 "/redfish/v1/Systems/system/Storage";
65 asyncResp->res.jsonValue["Name"] = "Storage Collection";
66 nlohmann::json::array_t members;
67 nlohmann::json::object_t member;
68 member["@odata.id"] = "/redfish/v1/Systems/system/Storage/1";
69 members.emplace_back(member);
70 asyncResp->res.jsonValue["Members"] = std::move(members);
71 asyncResp->res.jsonValue["Members@odata.count"] = 1;
72 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -070073}
Nikhil Potadea25aecc2019-08-23 16:35:26 -070074
Willy Tua85afbe2021-12-28 14:43:47 -080075inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
76 const std::shared_ptr<HealthPopulate>& health)
77{
George Liu7a1dbc42022-12-07 16:03:22 +080078 const std::array<std::string_view, 1> interfaces = {
79 "xyz.openbmc_project.Inventory.Item.Drive"};
80 dbus::utility::getSubTreePaths(
81 "/xyz/openbmc_project/inventory", 0, interfaces,
Willy Tua85afbe2021-12-28 14:43:47 -080082 [asyncResp, health](
George Liu7a1dbc42022-12-07 16:03:22 +080083 const boost::system::error_code& ec,
Willy Tua85afbe2021-12-28 14:43:47 -080084 const dbus::utility::MapperGetSubTreePathsResponse& driveList) {
85 if (ec)
86 {
87 BMCWEB_LOG_ERROR << "Drive mapper call error";
88 messages::internalError(asyncResp->res);
89 return;
90 }
91
92 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
93 driveArray = nlohmann::json::array();
94 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
95 count = 0;
96
Willy Tu13451e32023-05-24 16:08:18 -070097 if constexpr (bmcwebEnableHealthPopulate)
98 {
99 health->inventory.insert(health->inventory.end(), driveList.begin(),
100 driveList.end());
101 }
Willy Tua85afbe2021-12-28 14:43:47 -0800102
103 for (const std::string& drive : driveList)
104 {
105 sdbusplus::message::object_path object(drive);
106 if (object.filename().empty())
107 {
108 BMCWEB_LOG_ERROR << "Failed to find filename in " << drive;
109 return;
110 }
111
112 nlohmann::json::object_t driveJson;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700113 driveJson["@odata.id"] = boost::urls::format(
114 "/redfish/v1/Systems/system/Storage/1/Drives/{}",
Willy Tueddfc432022-09-26 16:46:38 +0000115 object.filename());
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500116 driveArray.emplace_back(std::move(driveJson));
Willy Tua85afbe2021-12-28 14:43:47 -0800117 }
118
119 count = driveArray.size();
George Liu7a1dbc42022-12-07 16:03:22 +0800120 });
Willy Tua85afbe2021-12-28 14:43:47 -0800121}
122
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700123inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700124{
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700125 BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
Ed Tanoused398212021-06-09 17:05:54 -0700126 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700127 .methods(boost::beast::http::verb::get)(
128 [&app](const crow::Request& req,
129 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000130 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700131 {
132 return;
133 }
Willy Tu61b1eb22023-03-14 11:29:50 -0700134 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
Ed Tanous002d39b2022-05-31 08:59:27 -0700135 asyncResp->res.jsonValue["@odata.id"] =
136 "/redfish/v1/Systems/system/Storage/1";
137 asyncResp->res.jsonValue["Name"] = "Storage";
138 asyncResp->res.jsonValue["Id"] = "1";
139 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
140
141 auto health = std::make_shared<HealthPopulate>(asyncResp);
Willy Tu13451e32023-05-24 16:08:18 -0700142 if constexpr (bmcwebEnableHealthPopulate)
143 {
144 health->populate();
145 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700146
Willy Tua85afbe2021-12-28 14:43:47 -0800147 getDrives(asyncResp, health);
Willy Tu61b1eb22023-03-14 11:29:50 -0700148 asyncResp->res.jsonValue["Controllers"]["@odata.id"] =
149 "/redfish/v1/Systems/system/Storage/1/Controllers";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700150 });
151}
152
Willy Tu03913172021-11-08 02:03:19 -0800153inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
154 const std::string& connectionName,
155 const std::string& path)
156{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200157 sdbusplus::asio::getAllProperties(
158 *crow::connections::systemBus, connectionName, path,
159 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800160 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800161 const std::vector<
162 std::pair<std::string, dbus::utility::DbusVariantType>>&
163 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700164 if (ec)
165 {
166 // this interface isn't necessary
167 return;
168 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200169
170 const std::string* partNumber = nullptr;
171 const std::string* serialNumber = nullptr;
172 const std::string* manufacturer = nullptr;
173 const std::string* model = nullptr;
174
175 const bool success = sdbusplus::unpackPropertiesNoThrow(
176 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
177 partNumber, "SerialNumber", serialNumber, "Manufacturer",
178 manufacturer, "Model", model);
179
180 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700181 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200182 messages::internalError(asyncResp->res);
183 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700184 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200185
186 if (partNumber != nullptr)
187 {
188 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
189 }
190
191 if (serialNumber != nullptr)
192 {
193 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
194 }
195
196 if (manufacturer != nullptr)
197 {
198 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
199 }
200
201 if (model != nullptr)
202 {
203 asyncResp->res.jsonValue["Model"] = *model;
204 }
205 });
Willy Tu03913172021-11-08 02:03:19 -0800206}
207
208inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
209 const std::string& connectionName,
210 const std::string& path)
211{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700212 sdbusplus::asio::getProperty<bool>(
213 *crow::connections::systemBus, connectionName, path,
214 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800215 [asyncResp, path](const boost::system::error_code& ec,
Willy Tucef57e82022-12-15 16:42:02 -0800216 const bool isPresent) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700217 // this interface isn't necessary, only check it if
218 // we get a good return
219 if (ec)
220 {
221 return;
222 }
Willy Tu03913172021-11-08 02:03:19 -0800223
Willy Tucef57e82022-12-15 16:42:02 -0800224 if (!isPresent)
Ed Tanous002d39b2022-05-31 08:59:27 -0700225 {
Willy Tucef57e82022-12-15 16:42:02 -0800226 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Ed Tanous002d39b2022-05-31 08:59:27 -0700227 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700228 });
Willy Tu03913172021-11-08 02:03:19 -0800229}
230
231inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
232 const std::string& connectionName,
233 const std::string& path)
234{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700235 sdbusplus::asio::getProperty<bool>(
236 *crow::connections::systemBus, connectionName, path,
237 "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800238 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700239 // this interface isn't necessary, only check it
240 // if we get a good return
241 if (ec)
242 {
243 return;
244 }
Willy Tu03913172021-11-08 02:03:19 -0800245
Ed Tanous002d39b2022-05-31 08:59:27 -0700246 // updating and disabled in the backend shouldn't be
247 // able to be set at the same time, so we don't need
248 // to check for the race condition of these two
249 // calls
250 if (updating)
251 {
252 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
253 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700254 });
Willy Tu03913172021-11-08 02:03:19 -0800255}
256
George Liudde9bc12023-02-22 09:35:51 +0800257inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800258{
259 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
260 {
George Liudde9bc12023-02-22 09:35:51 +0800261 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800262 }
263 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
264 {
George Liudde9bc12023-02-22 09:35:51 +0800265 return drive::MediaType::SSD;
266 }
267 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
268 {
269 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800270 }
271
George Liudde9bc12023-02-22 09:35:51 +0800272 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800273}
274
George Liudde9bc12023-02-22 09:35:51 +0800275inline std::optional<protocol::Protocol>
276 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800277{
278 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
279 {
George Liudde9bc12023-02-22 09:35:51 +0800280 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800281 }
282 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
283 {
George Liudde9bc12023-02-22 09:35:51 +0800284 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800285 }
286 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
287 {
George Liudde9bc12023-02-22 09:35:51 +0800288 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800289 }
290 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
291 {
George Liudde9bc12023-02-22 09:35:51 +0800292 return protocol::Protocol::FC;
293 }
294 if (proto ==
295 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
296 {
297 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800298 }
299
George Liudde9bc12023-02-22 09:35:51 +0800300 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800301}
302
303inline void
304 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
305 const std::string& connectionName,
306 const std::string& path)
307{
308 sdbusplus::asio::getAllProperties(
309 *crow::connections::systemBus, connectionName, path,
310 "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800311 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800312 const std::vector<
313 std::pair<std::string, dbus::utility::DbusVariantType>>&
314 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700315 if (ec)
316 {
317 // this interface isn't required
318 return;
319 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700320 const std::string* encryptionStatus = nullptr;
321 const bool* isLocked = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700322 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
323 property : propertiesList)
324 {
325 const std::string& propertyName = property.first;
326 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800327 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700328 const std::string* value =
329 std::get_if<std::string>(&property.second);
330 if (value == nullptr)
331 {
332 // illegal property
333 BMCWEB_LOG_ERROR << "Illegal property: Type";
334 messages::internalError(asyncResp->res);
335 return;
336 }
337
George Liudde9bc12023-02-22 09:35:51 +0800338 std::optional<drive::MediaType> mediaType =
339 convertDriveType(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700340 if (!mediaType)
341 {
George Liudde9bc12023-02-22 09:35:51 +0800342 BMCWEB_LOG_WARNING << "UnknownDriveType Interface: "
343 << *value;
344 continue;
345 }
346 if (*mediaType == drive::MediaType::Invalid)
347 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700348 messages::internalError(asyncResp->res);
349 return;
350 }
351
352 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800353 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700354 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800355 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700356 const uint64_t* capacity =
357 std::get_if<uint64_t>(&property.second);
358 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800359 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700360 BMCWEB_LOG_ERROR << "Illegal property: Capacity";
361 messages::internalError(asyncResp->res);
362 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800363 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700364 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800365 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700366 // drive capacity not known
367 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800368 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800369
Ed Tanous002d39b2022-05-31 08:59:27 -0700370 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800371 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700372 else if (propertyName == "Protocol")
373 {
374 const std::string* value =
375 std::get_if<std::string>(&property.second);
376 if (value == nullptr)
377 {
378 BMCWEB_LOG_ERROR << "Illegal property: Protocol";
379 messages::internalError(asyncResp->res);
380 return;
381 }
382
George Liudde9bc12023-02-22 09:35:51 +0800383 std::optional<protocol::Protocol> proto =
384 convertDriveProtocol(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700385 if (!proto)
386 {
George Liudde9bc12023-02-22 09:35:51 +0800387 BMCWEB_LOG_WARNING << "Unknown DrivePrototype Interface: "
388 << *value;
389 continue;
390 }
391 if (*proto == protocol::Protocol::Invalid)
392 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700393 messages::internalError(asyncResp->res);
394 return;
395 }
396 asyncResp->res.jsonValue["Protocol"] = *proto;
397 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700398 else if (propertyName == "PredictedMediaLifeLeftPercent")
399 {
400 const uint8_t* lifeLeft =
401 std::get_if<uint8_t>(&property.second);
402 if (lifeLeft == nullptr)
403 {
404 BMCWEB_LOG_ERROR
405 << "Illegal property: PredictedMediaLifeLeftPercent";
406 messages::internalError(asyncResp->res);
407 return;
408 }
409 // 255 means reading the value is not supported
410 if (*lifeLeft != 255)
411 {
412 asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
413 *lifeLeft;
414 }
415 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700416 else if (propertyName == "EncryptionStatus")
417 {
418 encryptionStatus = std::get_if<std::string>(&property.second);
419 if (encryptionStatus == nullptr)
420 {
421 BMCWEB_LOG_ERROR << "Illegal property: EncryptionStatus";
422 messages::internalError(asyncResp->res);
423 return;
424 }
425 }
426 else if (propertyName == "Locked")
427 {
428 isLocked = std::get_if<bool>(&property.second);
429 if (isLocked == nullptr)
430 {
431 BMCWEB_LOG_ERROR << "Illegal property: Locked";
432 messages::internalError(asyncResp->res);
433 return;
434 }
435 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700436 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700437
438 if (encryptionStatus == nullptr || isLocked == nullptr ||
439 *encryptionStatus ==
440 "xyz.openbmc_project.Drive.DriveEncryptionState.Unknown")
441 {
442 return;
443 }
444 if (*encryptionStatus !=
445 "xyz.openbmc_project.Drive.DriveEncryptionState.Encrypted")
446 {
447 //"The drive is not currently encrypted."
448 asyncResp->res.jsonValue["EncryptionStatus"] =
449 drive::EncryptionStatus::Unencrypted;
450 return;
451 }
452 if (*isLocked)
453 {
454 //"The drive is currently encrypted and the data is not
455 // accessible to the user."
456 asyncResp->res.jsonValue["EncryptionStatus"] =
457 drive::EncryptionStatus::Locked;
458 return;
459 }
460 // if not locked
461 // "The drive is currently encrypted but the data is accessible
462 // to the user in unencrypted form."
463 asyncResp->res.jsonValue["EncryptionStatus"] =
464 drive::EncryptionStatus::Unlocked;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800465 });
466}
467
Nan Zhoub53dcd92022-06-21 17:47:50 +0000468static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
469 const std::string& connectionName,
470 const std::string& path,
471 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700472{
473 for (const std::string& interface : interfaces)
474 {
475 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
476 {
477 getDriveAsset(asyncResp, connectionName, path);
478 }
479 else if (interface == "xyz.openbmc_project.Inventory.Item")
480 {
481 getDrivePresent(asyncResp, connectionName, path);
482 }
483 else if (interface == "xyz.openbmc_project.State.Drive")
484 {
485 getDriveState(asyncResp, connectionName, path);
486 }
487 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
488 {
489 getDriveItemProperties(asyncResp, connectionName, path);
490 }
491 }
492}
493
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700494inline void requestRoutesDrive(App& app)
495{
Ed Tanous22d268c2022-05-19 09:39:07 -0700496 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700497 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700498 .methods(boost::beast::http::verb::get)(
499 [&app](const crow::Request& req,
500 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous22d268c2022-05-19 09:39:07 -0700501 const std::string& systemName, const std::string& driveId) {
Carson Labrado3ba00072022-06-06 19:40:56 +0000502 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
Ed Tanous002d39b2022-05-31 08:59:27 -0700503 {
504 return;
505 }
Ed Tanous22d268c2022-05-19 09:39:07 -0700506 if (systemName != "system")
507 {
508 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
509 systemName);
510 return;
511 }
512
George Liue99073f2022-12-09 11:06:16 +0800513 constexpr std::array<std::string_view, 1> interfaces = {
514 "xyz.openbmc_project.Inventory.Item.Drive"};
515 dbus::utility::getSubTree(
516 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous002d39b2022-05-31 08:59:27 -0700517 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800518 driveId](const boost::system::error_code& ec,
Ed Tanous002d39b2022-05-31 08:59:27 -0700519 const dbus::utility::MapperGetSubTreeResponse& subtree) {
520 if (ec)
Ed Tanous45ca1b82022-03-25 13:07:27 -0700521 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 BMCWEB_LOG_ERROR << "Drive mapper call error";
523 messages::internalError(asyncResp->res);
Ed Tanous45ca1b82022-03-25 13:07:27 -0700524 return;
525 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700526
Ed Tanous002d39b2022-05-31 08:59:27 -0700527 auto drive = std::find_if(
528 subtree.begin(), subtree.end(),
529 [&driveId](
Nan Zhou8cb65f82022-06-15 05:12:24 +0000530 const std::pair<std::string,
531 dbus::utility::MapperServiceMap>& object) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700532 return sdbusplus::message::object_path(object.first)
533 .filename() == driveId;
534 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700535
Ed Tanous002d39b2022-05-31 08:59:27 -0700536 if (drive == subtree.end())
537 {
538 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
539 return;
540 }
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700541
Ed Tanous002d39b2022-05-31 08:59:27 -0700542 const std::string& path = drive->first;
Nan Zhou8cb65f82022-06-15 05:12:24 +0000543 const dbus::utility::MapperServiceMap& connectionNames =
544 drive->second;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700545
Ed Tanous002d39b2022-05-31 08:59:27 -0700546 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
Ed Tanousef4c65b2023-04-24 15:28:50 -0700547 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
548 "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700549 asyncResp->res.jsonValue["Name"] = driveId;
550 asyncResp->res.jsonValue["Id"] = driveId;
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700551
Ed Tanous002d39b2022-05-31 08:59:27 -0700552 if (connectionNames.size() != 1)
553 {
554 BMCWEB_LOG_ERROR << "Connection size " << connectionNames.size()
555 << ", not equal to 1";
556 messages::internalError(asyncResp->res);
557 return;
558 }
James Feiste284a7c2019-11-20 16:20:23 -0800559
Ed Tanous002d39b2022-05-31 08:59:27 -0700560 getMainChassisId(
Ed Tanousef4c65b2023-04-24 15:28:50 -0700561 asyncResp,
562 [](const std::string& chassisId,
563 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
564 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
565 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
Ed Tanous002d39b2022-05-31 08:59:27 -0700566 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700567
Ed Tanous002d39b2022-05-31 08:59:27 -0700568 // default it to Enabled
569 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700570
Willy Tu13451e32023-05-24 16:08:18 -0700571 if constexpr (bmcwebEnableHealthPopulate)
572 {
573 auto health = std::make_shared<HealthPopulate>(asyncResp);
574 health->inventory.emplace_back(path);
575 health->populate();
576 }
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700577
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700578 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
579 connectionNames[0].second);
George Liue99073f2022-12-09 11:06:16 +0800580 });
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700581 });
582}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700583
584/**
585 * Chassis drives, this URL will show all the DriveCollection
586 * information
587 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000588inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700589 crow::App& app, const crow::Request& req,
590 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
591 const std::string& chassisId)
592{
Carson Labrado3ba00072022-06-06 19:40:56 +0000593 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700594 {
595 return;
596 }
597
598 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800599 constexpr std::array<std::string_view, 2> interfaces = {
600 "xyz.openbmc_project.Inventory.Item.Board",
601 "xyz.openbmc_project.Inventory.Item.Chassis"};
602 dbus::utility::getSubTree(
603 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700604 [asyncResp,
George Liue99073f2022-12-09 11:06:16 +0800605 chassisId](const boost::system::error_code& ec,
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700606 const dbus::utility::MapperGetSubTreeResponse& subtree) {
607 if (ec)
608 {
609 if (ec == boost::system::errc::host_unreachable)
610 {
611 messages::resourceNotFound(asyncResp->res, "Chassis",
612 chassisId);
613 return;
614 }
615 messages::internalError(asyncResp->res);
616 return;
617 }
618
619 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000620 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700621 {
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700622 sdbusplus::message::object_path objPath(path);
623 if (objPath.filename() != chassisId)
624 {
625 continue;
626 }
627
628 if (connectionNames.empty())
629 {
630 BMCWEB_LOG_ERROR << "Got 0 Connection names";
631 continue;
632 }
633
634 asyncResp->res.jsonValue["@odata.type"] =
635 "#DriveCollection.DriveCollection";
636 asyncResp->res.jsonValue["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700637 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700638 asyncResp->res.jsonValue["Name"] = "Drive Collection";
639
640 // Association lambda
George Liu6c3e9452023-03-03 13:55:29 +0800641 dbus::utility::getAssociationEndPoints(
642 path + "/drive",
643 [asyncResp,
644 chassisId](const boost::system::error_code& ec3,
645 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700646 if (ec3)
647 {
648 BMCWEB_LOG_ERROR << "Error in chassis Drive association ";
649 }
650 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
651 // important if array is empty
652 members = nlohmann::json::array();
653
654 std::vector<std::string> leafNames;
655 for (const auto& drive : resp)
656 {
Ed Tanous8a592812022-06-04 09:06:59 -0700657 sdbusplus::message::object_path drivePath(drive);
658 leafNames.push_back(drivePath.filename());
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700659 }
660
661 std::sort(leafNames.begin(), leafNames.end(),
662 AlphanumLess<std::string>());
663
664 for (const auto& leafName : leafNames)
665 {
666 nlohmann::json::object_t member;
Ed Tanousef4c65b2023-04-24 15:28:50 -0700667 member["@odata.id"] =
668 boost::urls::format("/redfish/v1/Chassis/{}/Drives/{}",
669 chassisId, leafName);
Patrick Williamsb2ba3072023-05-12 10:27:39 -0500670 members.emplace_back(std::move(member));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700671 // navigation links will be registered in next patch set
672 }
673 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
674 }); // end association lambda
675
Patrick Williams89492a12023-05-10 07:51:34 -0500676 } // end Iterate over all retrieved ObjectPaths
George Liue99073f2022-12-09 11:06:16 +0800677 });
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700678}
679
680inline void requestRoutesChassisDrive(App& app)
681{
682 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
683 .privileges(redfish::privileges::getDriveCollection)
684 .methods(boost::beast::http::verb::get)(
685 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
686}
687
Nan Zhoub53dcd92022-06-21 17:47:50 +0000688inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
689 const std::string& chassisId,
690 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800691 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000692 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700693{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700694 if (ec)
695 {
696 BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
697 messages::internalError(asyncResp->res);
698 return;
699 }
700
701 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000702 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700703 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700704 sdbusplus::message::object_path objPath(path);
705 if (objPath.filename() != driveName)
706 {
707 continue;
708 }
709
710 if (connectionNames.empty())
711 {
712 BMCWEB_LOG_ERROR << "Got 0 Connection names";
713 continue;
714 }
715
Ed Tanousef4c65b2023-04-24 15:28:50 -0700716 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
717 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700718
719 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700720 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700721 asyncResp->res.jsonValue["Id"] = driveName;
722 // default it to Enabled
723 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
724
725 nlohmann::json::object_t linkChassisNav;
726 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700727 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700728 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
729
730 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
731 connectionNames[0].second);
732 }
733}
734
Nan Zhoub53dcd92022-06-21 17:47:50 +0000735inline void
736 matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
737 const std::string& chassisId,
738 const std::string& driveName,
739 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700740{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700741 for (const std::string& drivePath : resp)
742 {
743 sdbusplus::message::object_path path(drivePath);
744 std::string leaf = path.filename();
745 if (leaf != driveName)
746 {
747 continue;
748 }
749 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800750 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700751 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800752 dbus::utility::getSubTree(
753 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700754 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800755 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700756 const dbus::utility::MapperGetSubTreeResponse& subtree) {
757 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
George Liue99073f2022-12-09 11:06:16 +0800758 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700759 }
760}
761
Nan Zhoub53dcd92022-06-21 17:47:50 +0000762inline void
763 handleChassisDriveGet(crow::App& app, const crow::Request& req,
764 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
765 const std::string& chassisId,
766 const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700767{
Michal Orzel03810a12022-06-15 14:04:28 +0200768 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700769 {
770 return;
771 }
George Liue99073f2022-12-09 11:06:16 +0800772 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700773 "xyz.openbmc_project.Inventory.Item.Board",
774 "xyz.openbmc_project.Inventory.Item.Chassis"};
775
776 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800777 dbus::utility::getSubTree(
778 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700779 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800780 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700781 const dbus::utility::MapperGetSubTreeResponse& subtree) {
782 if (ec)
783 {
784 messages::internalError(asyncResp->res);
785 return;
786 }
787
788 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000789 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700790 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700791 sdbusplus::message::object_path objPath(path);
792 if (objPath.filename() != chassisId)
793 {
794 continue;
795 }
796
797 if (connectionNames.empty())
798 {
799 BMCWEB_LOG_ERROR << "Got 0 Connection names";
800 continue;
801 }
802
George Liu6c3e9452023-03-03 13:55:29 +0800803 dbus::utility::getAssociationEndPoints(
804 path + "/drive",
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700805 [asyncResp, chassisId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800806 driveName](const boost::system::error_code& ec3,
George Liu6c3e9452023-03-03 13:55:29 +0800807 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700808 if (ec3)
809 {
810 return; // no drives = no failures
811 }
812 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
813 });
814 break;
815 }
George Liue99073f2022-12-09 11:06:16 +0800816 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700817}
818
819/**
820 * This URL will show the drive interface for the specific drive in the chassis
821 */
822inline void requestRoutesChassisDriveName(App& app)
823{
824 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
825 .privileges(redfish::privileges::getChassis)
826 .methods(boost::beast::http::verb::get)(
827 std::bind_front(handleChassisDriveGet, std::ref(app)));
828}
829
Willy Tu61b1eb22023-03-14 11:29:50 -0700830inline void getStorageControllerAsset(
831 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
832 const boost::system::error_code& ec,
833 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
834 propertiesList)
835{
836 if (ec)
837 {
838 // this interface isn't necessary
839 BMCWEB_LOG_DEBUG << "Failed to get StorageControllerAsset";
840 return;
841 }
842
843 const std::string* partNumber = nullptr;
844 const std::string* serialNumber = nullptr;
845 const std::string* manufacturer = nullptr;
846 const std::string* model = nullptr;
847 if (!sdbusplus::unpackPropertiesNoThrow(
848 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
849 partNumber, "SerialNumber", serialNumber, "Manufacturer",
850 manufacturer, "Model", model))
851 {
852 messages::internalError(asyncResp->res);
853 return;
854 }
855
856 if (partNumber != nullptr)
857 {
858 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
859 }
860
861 if (serialNumber != nullptr)
862 {
863 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
864 }
865
866 if (manufacturer != nullptr)
867 {
868 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
869 }
870
871 if (model != nullptr)
872 {
873 asyncResp->res.jsonValue["Model"] = *model;
874 }
875}
876
877inline void populateStorageController(
878 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
879 const std::string& controllerId, const std::string& connectionName,
880 const std::string& path)
881{
882 asyncResp->res.jsonValue["@odata.type"] =
883 "#StorageController.v1_6_0.StorageController";
884 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
885 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", controllerId);
886 asyncResp->res.jsonValue["Name"] = controllerId;
887 asyncResp->res.jsonValue["Id"] = controllerId;
888 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
889
890 sdbusplus::asio::getProperty<bool>(
891 *crow::connections::systemBus, connectionName, path,
892 "xyz.openbmc_project.Inventory.Item", "Present",
893 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
894 // this interface isn't necessary, only check it
895 // if we get a good return
896 if (ec)
897 {
898 BMCWEB_LOG_DEBUG << "Failed to get Present property";
899 return;
900 }
901 if (!isPresent)
902 {
903 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
904 }
905 });
906
907 sdbusplus::asio::getAllProperties(
908 *crow::connections::systemBus, connectionName, path,
909 "xyz.openbmc_project.Inventory.Decorator.Asset",
910 [asyncResp](const boost::system::error_code& ec,
911 const std::vector<
912 std::pair<std::string, dbus::utility::DbusVariantType>>&
913 propertiesList) {
914 getStorageControllerAsset(asyncResp, ec, propertiesList);
915 });
916}
917
918inline void getStorageControllerHandler(
919 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
920 const std::string& controllerId, const boost::system::error_code& ec,
921 const dbus::utility::MapperGetSubTreeResponse& subtree)
922{
923 if (ec || subtree.empty())
924 {
925 // doesn't have to be there
926 BMCWEB_LOG_DEBUG << "Failed to handle StorageController";
927 return;
928 }
929
930 for (const auto& [path, interfaceDict] : subtree)
931 {
932 sdbusplus::message::object_path object(path);
933 std::string id = object.filename();
934 if (id.empty())
935 {
936 BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
937 return;
938 }
939 if (id != controllerId)
940 {
941 continue;
942 }
943
944 if (interfaceDict.size() != 1)
945 {
946 BMCWEB_LOG_ERROR << "Connection size " << interfaceDict.size()
947 << ", greater than 1";
948 messages::internalError(asyncResp->res);
949 return;
950 }
951
952 const std::string& connectionName = interfaceDict.front().first;
953 populateStorageController(asyncResp, controllerId, connectionName,
954 path);
955 }
956}
957
958inline void populateStorageControllerCollection(
959 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
960 const boost::system::error_code& ec,
961 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
962{
963 nlohmann::json::array_t members;
964 if (ec || controllerList.empty())
965 {
966 asyncResp->res.jsonValue["Members"] = std::move(members);
967 asyncResp->res.jsonValue["Members@odata.count"] = 0;
968 BMCWEB_LOG_DEBUG << "Failed to find any StorageController";
969 return;
970 }
971
972 for (const std::string& path : controllerList)
973 {
974 std::string id = sdbusplus::message::object_path(path).filename();
975 if (id.empty())
976 {
977 BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
978 return;
979 }
980 nlohmann::json::object_t member;
981 member["@odata.id"] = boost::urls::format(
982 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", id);
983 members.emplace_back(member);
984 }
985 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
986 asyncResp->res.jsonValue["Members"] = std::move(members);
987}
988
989inline void storageControllerCollectionHandler(
990 App& app, const crow::Request& req,
991 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
992 const std::string& systemName)
993{
994 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
995 {
996 BMCWEB_LOG_DEBUG
997 << "Failed to setup Redfish Route for StorageController Collection";
998 return;
999 }
1000 if (systemName != "system")
1001 {
1002 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1003 systemName);
1004 BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName;
1005 return;
1006 }
1007
1008 asyncResp->res.jsonValue["@odata.type"] =
1009 "#StorageControllerCollection.StorageControllerCollection";
1010 asyncResp->res.jsonValue["@odata.id"] =
1011 "/redfish/v1/Systems/system/Storage/1/Controllers";
1012 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1013
1014 constexpr std::array<std::string_view, 1> interfaces = {
1015 "xyz.openbmc_project.Inventory.Item.StorageController"};
1016 dbus::utility::getSubTreePaths(
1017 "/xyz/openbmc_project/inventory", 0, interfaces,
1018 [asyncResp](const boost::system::error_code& ec,
1019 const dbus::utility::MapperGetSubTreePathsResponse&
1020 controllerList) {
1021 populateStorageControllerCollection(asyncResp, ec, controllerList);
1022 });
1023}
1024
1025inline void storageControllerHandler(
1026 App& app, const crow::Request& req,
1027 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1028 const std::string& systemName, const std::string& controllerId)
1029{
1030 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1031 {
1032 BMCWEB_LOG_DEBUG
1033 << "Failed to setup Redfish Route for StorageController";
1034 return;
1035 }
1036 if (systemName != "system")
1037 {
1038 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1039 systemName);
1040 BMCWEB_LOG_DEBUG << "Failed to find ComputerSystem of " << systemName;
1041 return;
1042 }
1043 constexpr std::array<std::string_view, 1> interfaces = {
1044 "xyz.openbmc_project.Inventory.Item.StorageController"};
1045 dbus::utility::getSubTree(
1046 "/xyz/openbmc_project/inventory", 0, interfaces,
1047 [asyncResp,
1048 controllerId](const boost::system::error_code& ec,
1049 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1050 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
1051 });
1052}
1053
1054inline void requestRoutesStorageControllerCollection(App& app)
1055{
1056 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1057 .privileges(redfish::privileges::getStorageControllerCollection)
1058 .methods(boost::beast::http::verb::get)(
1059 std::bind_front(storageControllerCollectionHandler, std::ref(app)));
1060}
1061
1062inline void requestRoutesStorageController(App& app)
1063{
1064 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1065 .privileges(redfish::privileges::getStorageController)
1066 .methods(boost::beast::http::verb::get)(
1067 std::bind_front(storageControllerHandler, std::ref(app)));
1068}
1069
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001070} // namespace redfish