blob: 74c88f7bce9de4a2e1c8087e8bd38a681496b223 [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"
Willy Tu5e577bc2022-07-26 00:41:55 +000030#include "utils/collection.hpp"
Ed Tanous3ccb3ad2023-01-13 17:40:03 -080031#include "utils/dbus_utils.hpp"
James Feist2ad9c2f2019-10-29 16:26:48 -070032
George Liue99073f2022-12-09 11:06:16 +080033#include <boost/system/error_code.hpp>
Ed Tanousef4c65b2023-04-24 15:28:50 -070034#include <boost/url/format.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070035#include <sdbusplus/asio/property.hpp>
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +020036#include <sdbusplus/unpack_properties.hpp>
Nikhil Potadea25aecc2019-08-23 16:35:26 -070037
George Liu7a1dbc42022-12-07 16:03:22 +080038#include <array>
Ed Tanous3544d2a2023-08-06 18:12:20 -070039#include <ranges>
George Liu7a1dbc42022-12-07 16:03:22 +080040#include <string_view>
41
Nikhil Potadea25aecc2019-08-23 16:35:26 -070042namespace redfish
43{
Ed Tanous36d52332023-06-09 13:18:40 -070044
45inline void handleSystemsStorageCollectionGet(
46 App& app, const crow::Request& req,
47 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
48 const std::string& systemName)
49{
50 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
51 {
52 return;
53 }
54 if (systemName != "system")
55 {
56 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
57 systemName);
58 return;
59 }
60
61 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";
Willy Tu5e577bc2022-07-26 00:41:55 +000066
67 constexpr std::array<std::string_view, 1> interface {
68 "xyz.openbmc_project.Inventory.Item.Storage"
69 };
70 collection_util::getCollectionMembers(
71 asyncResp, boost::urls::format("/redfish/v1/Systems/system/Storage"),
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050072 interface, "/xyz/openbmc_project/inventory");
Willy Tu5e577bc2022-07-26 00:41:55 +000073}
74
75inline void handleStorageCollectionGet(
76 App& app, const crow::Request& req,
77 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
78{
79 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
80 {
81 return;
82 }
83 asyncResp->res.jsonValue["@odata.type"] =
84 "#StorageCollection.StorageCollection";
85 asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/Storage";
86 asyncResp->res.jsonValue["Name"] = "Storage Collection";
87 constexpr std::array<std::string_view, 1> interface {
88 "xyz.openbmc_project.Inventory.Item.Storage"
89 };
90 collection_util::getCollectionMembers(
Lakshmi Yadlapati36b5f1e2023-09-26 23:53:28 -050091 asyncResp, boost::urls::format("/redfish/v1/Storage"), interface,
92 "/xyz/openbmc_project/inventory");
Ed Tanous36d52332023-06-09 13:18:40 -070093}
94
John Edward Broadbent7e860f12021-04-08 15:57:16 -070095inline void requestRoutesStorageCollection(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -070096{
Ed Tanous22d268c2022-05-19 09:39:07 -070097 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/")
Ed Tanoused398212021-06-09 17:05:54 -070098 .privileges(redfish::privileges::getStorageCollection)
John Edward Broadbent7e860f12021-04-08 15:57:16 -070099 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700100 std::bind_front(handleSystemsStorageCollectionGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000101 BMCWEB_ROUTE(app, "/redfish/v1/Storage/")
102 .privileges(redfish::privileges::getStorageCollection)
103 .methods(boost::beast::http::verb::get)(
104 std::bind_front(handleStorageCollectionGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700105}
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700106
Ed Tanous36d52332023-06-09 13:18:40 -0700107inline void afterChassisDriveCollectionSubtree(
108 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
109 const std::shared_ptr<HealthPopulate>& health,
110 const boost::system::error_code& ec,
111 const dbus::utility::MapperGetSubTreePathsResponse& driveList)
112{
113 if (ec)
114 {
Ed Tanous62598e32023-07-17 17:06:25 -0700115 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700116 messages::internalError(asyncResp->res);
117 return;
118 }
119
120 nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
121 driveArray = nlohmann::json::array();
122 auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
123 count = 0;
124
125 if constexpr (bmcwebEnableHealthPopulate)
126 {
127 health->inventory.insert(health->inventory.end(), driveList.begin(),
128 driveList.end());
129 }
130
131 for (const std::string& drive : driveList)
132 {
133 sdbusplus::message::object_path object(drive);
134 if (object.filename().empty())
135 {
Ed Tanous62598e32023-07-17 17:06:25 -0700136 BMCWEB_LOG_ERROR("Failed to find filename in {}", drive);
Ed Tanous36d52332023-06-09 13:18:40 -0700137 return;
138 }
139
140 nlohmann::json::object_t driveJson;
141 driveJson["@odata.id"] = boost::urls::format(
142 "/redfish/v1/Systems/system/Storage/1/Drives/{}",
143 object.filename());
144 driveArray.emplace_back(std::move(driveJson));
145 }
146
147 count = driveArray.size();
148}
Willy Tua85afbe2021-12-28 14:43:47 -0800149inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
150 const std::shared_ptr<HealthPopulate>& health)
151{
George Liu7a1dbc42022-12-07 16:03:22 +0800152 const std::array<std::string_view, 1> interfaces = {
153 "xyz.openbmc_project.Inventory.Item.Drive"};
154 dbus::utility::getSubTreePaths(
155 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700156 std::bind_front(afterChassisDriveCollectionSubtree, asyncResp, health));
157}
Willy Tua85afbe2021-12-28 14:43:47 -0800158
Willy Tu5e577bc2022-07-26 00:41:55 +0000159inline void afterSystemsStorageGetSubtree(
160 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
161 const std::string& storageId, const boost::system::error_code& ec,
162 const dbus::utility::MapperGetSubTreeResponse& subtree)
Ed Tanous36d52332023-06-09 13:18:40 -0700163{
Willy Tu5e577bc2022-07-26 00:41:55 +0000164 if (ec)
Ed Tanous36d52332023-06-09 13:18:40 -0700165 {
Ed Tanous62598e32023-07-17 17:06:25 -0700166 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000167 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
168 storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700169 return;
170 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700171 auto storage = std::ranges::find_if(
172 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000173 [&storageId](const std::pair<std::string,
174 dbus::utility::MapperServiceMap>& object) {
175 return sdbusplus::message::object_path(object.first).filename() ==
176 storageId;
177 });
178 if (storage == subtree.end())
179 {
180 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
181 storageId);
182 return;
183 }
184
Ed Tanous36d52332023-06-09 13:18:40 -0700185 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
186 asyncResp->res.jsonValue["@odata.id"] =
Willy Tu5e577bc2022-07-26 00:41:55 +0000187 boost::urls::format("/redfish/v1/Systems/system/Storage/{}", storageId);
Ed Tanous36d52332023-06-09 13:18:40 -0700188 asyncResp->res.jsonValue["Name"] = "Storage";
Willy Tu5e577bc2022-07-26 00:41:55 +0000189 asyncResp->res.jsonValue["Id"] = storageId;
Ed Tanous36d52332023-06-09 13:18:40 -0700190 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
Willy Tua85afbe2021-12-28 14:43:47 -0800191
Ed Tanous36d52332023-06-09 13:18:40 -0700192 auto health = std::make_shared<HealthPopulate>(asyncResp);
193 if constexpr (bmcwebEnableHealthPopulate)
194 {
195 health->populate();
196 }
Willy Tua85afbe2021-12-28 14:43:47 -0800197
Ed Tanous36d52332023-06-09 13:18:40 -0700198 getDrives(asyncResp, health);
Willy Tu5e577bc2022-07-26 00:41:55 +0000199 asyncResp->res.jsonValue["Controllers"]["@odata.id"] = boost::urls::format(
200 "/redfish/v1/Systems/system/Storage/{}/Controllers", storageId);
201}
202
203inline void
204 handleSystemsStorageGet(App& app, const crow::Request& req,
205 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800206 const std::string& systemName,
Willy Tu5e577bc2022-07-26 00:41:55 +0000207 const std::string& storageId)
208{
209 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
210 {
211 return;
212 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800213 if constexpr (bmcwebEnableMultiHost)
214 {
215 // Option currently returns no systems. TBD
216 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
217 systemName);
218 return;
219 }
Willy Tu5e577bc2022-07-26 00:41:55 +0000220
221 constexpr std::array<std::string_view, 1> interfaces = {
222 "xyz.openbmc_project.Inventory.Item.Storage"};
223 dbus::utility::getSubTree(
224 "/xyz/openbmc_project/inventory", 0, interfaces,
225 std::bind_front(afterSystemsStorageGetSubtree, asyncResp, storageId));
226}
227
228inline void afterSubtree(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
229 const std::string& storageId,
230 const boost::system::error_code& ec,
231 const dbus::utility::MapperGetSubTreeResponse& subtree)
232{
233 if (ec)
234 {
Ed Tanous62598e32023-07-17 17:06:25 -0700235 BMCWEB_LOG_DEBUG("requestRoutesStorage DBUS response error");
Willy Tu5e577bc2022-07-26 00:41:55 +0000236 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
237 storageId);
238 return;
239 }
Ed Tanous3544d2a2023-08-06 18:12:20 -0700240 auto storage = std::ranges::find_if(
241 subtree,
Willy Tu5e577bc2022-07-26 00:41:55 +0000242 [&storageId](const std::pair<std::string,
243 dbus::utility::MapperServiceMap>& object) {
244 return sdbusplus::message::object_path(object.first).filename() ==
245 storageId;
246 });
247 if (storage == subtree.end())
248 {
249 messages::resourceNotFound(asyncResp->res, "#Storage.v1_13_0.Storage",
250 storageId);
251 return;
252 }
253
254 asyncResp->res.jsonValue["@odata.type"] = "#Storage.v1_13_0.Storage";
255 asyncResp->res.jsonValue["@odata.id"] =
256 boost::urls::format("/redfish/v1/Storage/{}", storageId);
257 asyncResp->res.jsonValue["Name"] = "Storage";
258 asyncResp->res.jsonValue["Id"] = storageId;
259 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
260
261 // Storage subsystem to Storage link.
262 nlohmann::json::array_t storageServices;
263 nlohmann::json::object_t storageService;
264 storageService["@odata.id"] =
265 boost::urls::format("/redfish/v1/Systems/system/Storage/{}", storageId);
266 storageServices.emplace_back(storageService);
267 asyncResp->res.jsonValue["Links"]["StorageServices"] =
268 std::move(storageServices);
269 asyncResp->res.jsonValue["Links"]["StorageServices@odata.count"] = 1;
270}
271
272inline void
273 handleStorageGet(App& app, const crow::Request& req,
274 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
275 const std::string& storageId)
276{
277 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
278 {
Ed Tanous62598e32023-07-17 17:06:25 -0700279 BMCWEB_LOG_DEBUG("requestRoutesStorage setUpRedfishRoute failed");
Willy Tu5e577bc2022-07-26 00:41:55 +0000280 return;
281 }
282
283 constexpr std::array<std::string_view, 1> interfaces = {
284 "xyz.openbmc_project.Inventory.Item.Storage"};
285 dbus::utility::getSubTree(
286 "/xyz/openbmc_project/inventory", 0, interfaces,
287 std::bind_front(afterSubtree, asyncResp, storageId));
Willy Tua85afbe2021-12-28 14:43:47 -0800288}
289
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700290inline void requestRoutesStorage(App& app)
Nikhil Potadea25aecc2019-08-23 16:35:26 -0700291{
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800292 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700293 .privileges(redfish::privileges::getStorage)
Ed Tanous002d39b2022-05-31 08:59:27 -0700294 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700295 std::bind_front(handleSystemsStorageGet, std::ref(app)));
Willy Tu5e577bc2022-07-26 00:41:55 +0000296
297 BMCWEB_ROUTE(app, "/redfish/v1/Storage/<str>/")
298 .privileges(redfish::privileges::getStorage)
299 .methods(boost::beast::http::verb::get)(
300 std::bind_front(handleStorageGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700301}
302
Willy Tu03913172021-11-08 02:03:19 -0800303inline void getDriveAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
304 const std::string& connectionName,
305 const std::string& path)
306{
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200307 sdbusplus::asio::getAllProperties(
308 *crow::connections::systemBus, connectionName, path,
309 "xyz.openbmc_project.Inventory.Decorator.Asset",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800310 [asyncResp](const boost::system::error_code& ec,
Ed Tanous168e20c2021-12-13 14:39:53 -0800311 const std::vector<
312 std::pair<std::string, dbus::utility::DbusVariantType>>&
313 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700314 if (ec)
315 {
316 // this interface isn't necessary
317 return;
318 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200319
320 const std::string* partNumber = nullptr;
321 const std::string* serialNumber = nullptr;
322 const std::string* manufacturer = nullptr;
323 const std::string* model = nullptr;
324
325 const bool success = sdbusplus::unpackPropertiesNoThrow(
326 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
327 partNumber, "SerialNumber", serialNumber, "Manufacturer",
328 manufacturer, "Model", model);
329
330 if (!success)
Ed Tanous002d39b2022-05-31 08:59:27 -0700331 {
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200332 messages::internalError(asyncResp->res);
333 return;
Ed Tanous002d39b2022-05-31 08:59:27 -0700334 }
Krzysztof Grobelnyd1bde9e2022-09-07 10:40:51 +0200335
336 if (partNumber != nullptr)
337 {
338 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
339 }
340
341 if (serialNumber != nullptr)
342 {
343 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
344 }
345
346 if (manufacturer != nullptr)
347 {
348 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
349 }
350
351 if (model != nullptr)
352 {
353 asyncResp->res.jsonValue["Model"] = *model;
354 }
355 });
Willy Tu03913172021-11-08 02:03:19 -0800356}
357
358inline void getDrivePresent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
359 const std::string& connectionName,
360 const std::string& path)
361{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700362 sdbusplus::asio::getProperty<bool>(
363 *crow::connections::systemBus, connectionName, path,
364 "xyz.openbmc_project.Inventory.Item", "Present",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800365 [asyncResp, path](const boost::system::error_code& ec,
Willy Tucef57e82022-12-15 16:42:02 -0800366 const bool isPresent) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700367 // this interface isn't necessary, only check it if
368 // we get a good return
369 if (ec)
370 {
371 return;
372 }
Willy Tu03913172021-11-08 02:03:19 -0800373
Willy Tucef57e82022-12-15 16:42:02 -0800374 if (!isPresent)
Ed Tanous002d39b2022-05-31 08:59:27 -0700375 {
Willy Tucef57e82022-12-15 16:42:02 -0800376 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
Ed Tanous002d39b2022-05-31 08:59:27 -0700377 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700378 });
Willy Tu03913172021-11-08 02:03:19 -0800379}
380
381inline void getDriveState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
382 const std::string& connectionName,
383 const std::string& path)
384{
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700385 sdbusplus::asio::getProperty<bool>(
386 *crow::connections::systemBus, connectionName, path,
387 "xyz.openbmc_project.State.Drive", "Rebuilding",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800388 [asyncResp](const boost::system::error_code& ec, const bool updating) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700389 // this interface isn't necessary, only check it
390 // if we get a good return
391 if (ec)
392 {
393 return;
394 }
Willy Tu03913172021-11-08 02:03:19 -0800395
Ed Tanous002d39b2022-05-31 08:59:27 -0700396 // updating and disabled in the backend shouldn't be
397 // able to be set at the same time, so we don't need
398 // to check for the race condition of these two
399 // calls
400 if (updating)
401 {
402 asyncResp->res.jsonValue["Status"]["State"] = "Updating";
403 }
Jonathan Doman1e1e5982021-06-11 09:36:17 -0700404 });
Willy Tu03913172021-11-08 02:03:19 -0800405}
406
George Liudde9bc12023-02-22 09:35:51 +0800407inline std::optional<drive::MediaType> convertDriveType(std::string_view type)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800408{
409 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.HDD")
410 {
George Liudde9bc12023-02-22 09:35:51 +0800411 return drive::MediaType::HDD;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800412 }
413 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.SSD")
414 {
George Liudde9bc12023-02-22 09:35:51 +0800415 return drive::MediaType::SSD;
416 }
417 if (type == "xyz.openbmc_project.Inventory.Item.Drive.DriveType.Unknown")
418 {
419 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800420 }
421
George Liudde9bc12023-02-22 09:35:51 +0800422 return drive::MediaType::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800423}
424
George Liudde9bc12023-02-22 09:35:51 +0800425inline std::optional<protocol::Protocol>
426 convertDriveProtocol(std::string_view proto)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800427{
428 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SAS")
429 {
George Liudde9bc12023-02-22 09:35:51 +0800430 return protocol::Protocol::SAS;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800431 }
432 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.SATA")
433 {
George Liudde9bc12023-02-22 09:35:51 +0800434 return protocol::Protocol::SATA;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800435 }
436 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.NVMe")
437 {
George Liudde9bc12023-02-22 09:35:51 +0800438 return protocol::Protocol::NVMe;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800439 }
440 if (proto == "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.FC")
441 {
George Liudde9bc12023-02-22 09:35:51 +0800442 return protocol::Protocol::FC;
443 }
444 if (proto ==
445 "xyz.openbmc_project.Inventory.Item.Drive.DriveProtocol.Unknown")
446 {
447 return std::nullopt;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800448 }
449
George Liudde9bc12023-02-22 09:35:51 +0800450 return protocol::Protocol::Invalid;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800451}
452
453inline void
454 getDriveItemProperties(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
455 const std::string& connectionName,
456 const std::string& path)
457{
458 sdbusplus::asio::getAllProperties(
459 *crow::connections::systemBus, connectionName, path,
460 "xyz.openbmc_project.Inventory.Item.Drive",
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800461 [asyncResp](const boost::system::error_code& ec,
Willy Tu19b8e9a2021-11-08 02:55:03 -0800462 const std::vector<
463 std::pair<std::string, dbus::utility::DbusVariantType>>&
464 propertiesList) {
Ed Tanous002d39b2022-05-31 08:59:27 -0700465 if (ec)
466 {
467 // this interface isn't required
468 return;
469 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700470 const std::string* encryptionStatus = nullptr;
471 const bool* isLocked = nullptr;
Ed Tanous002d39b2022-05-31 08:59:27 -0700472 for (const std::pair<std::string, dbus::utility::DbusVariantType>&
473 property : propertiesList)
474 {
475 const std::string& propertyName = property.first;
476 if (propertyName == "Type")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800477 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700478 const std::string* value =
479 std::get_if<std::string>(&property.second);
480 if (value == nullptr)
481 {
482 // illegal property
Ed Tanous62598e32023-07-17 17:06:25 -0700483 BMCWEB_LOG_ERROR("Illegal property: Type");
Ed Tanous002d39b2022-05-31 08:59:27 -0700484 messages::internalError(asyncResp->res);
485 return;
486 }
487
George Liudde9bc12023-02-22 09:35:51 +0800488 std::optional<drive::MediaType> mediaType =
489 convertDriveType(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700490 if (!mediaType)
491 {
Ed Tanous62598e32023-07-17 17:06:25 -0700492 BMCWEB_LOG_WARNING("UnknownDriveType Interface: {}",
493 *value);
George Liudde9bc12023-02-22 09:35:51 +0800494 continue;
495 }
496 if (*mediaType == drive::MediaType::Invalid)
497 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700498 messages::internalError(asyncResp->res);
499 return;
500 }
501
502 asyncResp->res.jsonValue["MediaType"] = *mediaType;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800503 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700504 else if (propertyName == "Capacity")
Willy Tu19b8e9a2021-11-08 02:55:03 -0800505 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700506 const uint64_t* capacity =
507 std::get_if<uint64_t>(&property.second);
508 if (capacity == nullptr)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800509 {
Ed Tanous62598e32023-07-17 17:06:25 -0700510 BMCWEB_LOG_ERROR("Illegal property: Capacity");
Ed Tanous002d39b2022-05-31 08:59:27 -0700511 messages::internalError(asyncResp->res);
512 return;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800513 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700514 if (*capacity == 0)
Willy Tu19b8e9a2021-11-08 02:55:03 -0800515 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700516 // drive capacity not known
517 continue;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800518 }
Willy Tu19b8e9a2021-11-08 02:55:03 -0800519
Ed Tanous002d39b2022-05-31 08:59:27 -0700520 asyncResp->res.jsonValue["CapacityBytes"] = *capacity;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800521 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700522 else if (propertyName == "Protocol")
523 {
524 const std::string* value =
525 std::get_if<std::string>(&property.second);
526 if (value == nullptr)
527 {
Ed Tanous62598e32023-07-17 17:06:25 -0700528 BMCWEB_LOG_ERROR("Illegal property: Protocol");
Ed Tanous002d39b2022-05-31 08:59:27 -0700529 messages::internalError(asyncResp->res);
530 return;
531 }
532
George Liudde9bc12023-02-22 09:35:51 +0800533 std::optional<protocol::Protocol> proto =
534 convertDriveProtocol(*value);
Ed Tanous002d39b2022-05-31 08:59:27 -0700535 if (!proto)
536 {
Ed Tanous62598e32023-07-17 17:06:25 -0700537 BMCWEB_LOG_WARNING("Unknown DrivePrototype Interface: {}",
538 *value);
George Liudde9bc12023-02-22 09:35:51 +0800539 continue;
540 }
541 if (*proto == protocol::Protocol::Invalid)
542 {
Ed Tanous002d39b2022-05-31 08:59:27 -0700543 messages::internalError(asyncResp->res);
544 return;
545 }
546 asyncResp->res.jsonValue["Protocol"] = *proto;
547 }
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700548 else if (propertyName == "PredictedMediaLifeLeftPercent")
549 {
550 const uint8_t* lifeLeft =
551 std::get_if<uint8_t>(&property.second);
552 if (lifeLeft == nullptr)
553 {
Ed Tanous62598e32023-07-17 17:06:25 -0700554 BMCWEB_LOG_ERROR(
555 "Illegal property: PredictedMediaLifeLeftPercent");
John Edward Broadbent3fe4d5c2022-05-06 14:42:35 -0700556 messages::internalError(asyncResp->res);
557 return;
558 }
559 // 255 means reading the value is not supported
560 if (*lifeLeft != 255)
561 {
562 asyncResp->res.jsonValue["PredictedMediaLifeLeftPercent"] =
563 *lifeLeft;
564 }
565 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700566 else if (propertyName == "EncryptionStatus")
567 {
568 encryptionStatus = std::get_if<std::string>(&property.second);
569 if (encryptionStatus == nullptr)
570 {
Ed Tanous62598e32023-07-17 17:06:25 -0700571 BMCWEB_LOG_ERROR("Illegal property: EncryptionStatus");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700572 messages::internalError(asyncResp->res);
573 return;
574 }
575 }
576 else if (propertyName == "Locked")
577 {
578 isLocked = std::get_if<bool>(&property.second);
579 if (isLocked == nullptr)
580 {
Ed Tanous62598e32023-07-17 17:06:25 -0700581 BMCWEB_LOG_ERROR("Illegal property: Locked");
John Edward Broadbente5029d82022-06-08 14:35:21 -0700582 messages::internalError(asyncResp->res);
583 return;
584 }
585 }
Ed Tanous002d39b2022-05-31 08:59:27 -0700586 }
John Edward Broadbente5029d82022-06-08 14:35:21 -0700587
588 if (encryptionStatus == nullptr || isLocked == nullptr ||
589 *encryptionStatus ==
590 "xyz.openbmc_project.Drive.DriveEncryptionState.Unknown")
591 {
592 return;
593 }
594 if (*encryptionStatus !=
595 "xyz.openbmc_project.Drive.DriveEncryptionState.Encrypted")
596 {
597 //"The drive is not currently encrypted."
598 asyncResp->res.jsonValue["EncryptionStatus"] =
599 drive::EncryptionStatus::Unencrypted;
600 return;
601 }
602 if (*isLocked)
603 {
604 //"The drive is currently encrypted and the data is not
605 // accessible to the user."
606 asyncResp->res.jsonValue["EncryptionStatus"] =
607 drive::EncryptionStatus::Locked;
608 return;
609 }
610 // if not locked
611 // "The drive is currently encrypted but the data is accessible
612 // to the user in unencrypted form."
613 asyncResp->res.jsonValue["EncryptionStatus"] =
614 drive::EncryptionStatus::Unlocked;
Willy Tu19b8e9a2021-11-08 02:55:03 -0800615 });
616}
617
Nan Zhoub53dcd92022-06-21 17:47:50 +0000618static void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
619 const std::string& connectionName,
620 const std::string& path,
621 const std::vector<std::string>& interfaces)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700622{
623 for (const std::string& interface : interfaces)
624 {
625 if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
626 {
627 getDriveAsset(asyncResp, connectionName, path);
628 }
629 else if (interface == "xyz.openbmc_project.Inventory.Item")
630 {
631 getDrivePresent(asyncResp, connectionName, path);
632 }
633 else if (interface == "xyz.openbmc_project.State.Drive")
634 {
635 getDriveState(asyncResp, connectionName, path);
636 }
637 else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
638 {
639 getDriveItemProperties(asyncResp, connectionName, path);
640 }
641 }
642}
643
Ed Tanous36d52332023-06-09 13:18:40 -0700644inline void afterGetSubtreeSystemsStorageDrive(
645 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
646 const std::string& driveId, const boost::system::error_code& ec,
647 const dbus::utility::MapperGetSubTreeResponse& subtree)
648{
649 if (ec)
650 {
Ed Tanous62598e32023-07-17 17:06:25 -0700651 BMCWEB_LOG_ERROR("Drive mapper call error");
Ed Tanous36d52332023-06-09 13:18:40 -0700652 messages::internalError(asyncResp->res);
653 return;
654 }
655
Ed Tanous3544d2a2023-08-06 18:12:20 -0700656 auto drive = std::ranges::find_if(
657 subtree,
Ed Tanous36d52332023-06-09 13:18:40 -0700658 [&driveId](const std::pair<std::string,
659 dbus::utility::MapperServiceMap>& object) {
660 return sdbusplus::message::object_path(object.first).filename() ==
661 driveId;
662 });
663
664 if (drive == subtree.end())
665 {
666 messages::resourceNotFound(asyncResp->res, "Drive", driveId);
667 return;
668 }
669
670 const std::string& path = drive->first;
671 const dbus::utility::MapperServiceMap& connectionNames = drive->second;
672
673 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
674 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
675 "/redfish/v1/Systems/system/Storage/1/Drives/{}", driveId);
676 asyncResp->res.jsonValue["Name"] = driveId;
677 asyncResp->res.jsonValue["Id"] = driveId;
678
679 if (connectionNames.size() != 1)
680 {
Ed Tanous62598e32023-07-17 17:06:25 -0700681 BMCWEB_LOG_ERROR("Connection size {}, not equal to 1",
682 connectionNames.size());
Ed Tanous36d52332023-06-09 13:18:40 -0700683 messages::internalError(asyncResp->res);
684 return;
685 }
686
687 getMainChassisId(asyncResp,
688 [](const std::string& chassisId,
689 const std::shared_ptr<bmcweb::AsyncResp>& aRsp) {
690 aRsp->res.jsonValue["Links"]["Chassis"]["@odata.id"] =
691 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
692 });
693
694 // default it to Enabled
695 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
696
697 if constexpr (bmcwebEnableHealthPopulate)
698 {
699 auto health = std::make_shared<HealthPopulate>(asyncResp);
700 health->inventory.emplace_back(path);
701 health->populate();
702 }
703
704 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
705 connectionNames[0].second);
706}
707
708inline void handleSystemsStorageDriveGet(
709 App& app, const crow::Request& req,
710 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
711 const std::string& systemName, const std::string& driveId)
712{
713 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
714 {
715 return;
716 }
Ed Tanous7f3e84a2022-12-28 16:22:54 -0800717 if constexpr (bmcwebEnableMultiHost)
718 {
719 // Option currently returns no systems. TBD
720 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
721 systemName);
722 return;
723 }
724
Ed Tanous36d52332023-06-09 13:18:40 -0700725 if (systemName != "system")
726 {
727 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
728 systemName);
729 return;
730 }
731
732 constexpr std::array<std::string_view, 1> interfaces = {
733 "xyz.openbmc_project.Inventory.Item.Drive"};
734 dbus::utility::getSubTree(
735 "/xyz/openbmc_project/inventory", 0, interfaces,
736 std::bind_front(afterGetSubtreeSystemsStorageDrive, asyncResp,
737 driveId));
738}
739
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700740inline void requestRoutesDrive(App& app)
741{
Ed Tanous22d268c2022-05-19 09:39:07 -0700742 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Drives/<str>/")
Ed Tanoused398212021-06-09 17:05:54 -0700743 .privileges(redfish::privileges::getDrive)
Ed Tanous002d39b2022-05-31 08:59:27 -0700744 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -0700745 std::bind_front(handleSystemsStorageDriveGet, std::ref(app)));
John Edward Broadbent7e860f12021-04-08 15:57:16 -0700746}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700747
Ed Tanous36d52332023-06-09 13:18:40 -0700748inline void afterChassisDriveCollectionSubtreeGet(
749 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
750 const std::string& chassisId, const boost::system::error_code& ec,
751 const dbus::utility::MapperGetSubTreeResponse& subtree)
752{
753 if (ec)
754 {
755 if (ec == boost::system::errc::host_unreachable)
756 {
757 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId);
758 return;
759 }
760 messages::internalError(asyncResp->res);
761 return;
762 }
763
764 // Iterate over all retrieved ObjectPaths.
765 for (const auto& [path, connectionNames] : subtree)
766 {
767 sdbusplus::message::object_path objPath(path);
768 if (objPath.filename() != chassisId)
769 {
770 continue;
771 }
772
773 if (connectionNames.empty())
774 {
Ed Tanous62598e32023-07-17 17:06:25 -0700775 BMCWEB_LOG_ERROR("Got 0 Connection names");
Ed Tanous36d52332023-06-09 13:18:40 -0700776 continue;
777 }
778
779 asyncResp->res.jsonValue["@odata.type"] =
780 "#DriveCollection.DriveCollection";
781 asyncResp->res.jsonValue["@odata.id"] =
782 boost::urls::format("/redfish/v1/Chassis/{}/Drives", chassisId);
783 asyncResp->res.jsonValue["Name"] = "Drive Collection";
784
785 // Association lambda
786 dbus::utility::getAssociationEndPoints(
787 path + "/drive",
788 [asyncResp, chassisId](const boost::system::error_code& ec3,
789 const dbus::utility::MapperEndPoints& resp) {
790 if (ec3)
791 {
Ed Tanous62598e32023-07-17 17:06:25 -0700792 BMCWEB_LOG_ERROR("Error in chassis Drive association ");
Ed Tanous36d52332023-06-09 13:18:40 -0700793 }
794 nlohmann::json& members = asyncResp->res.jsonValue["Members"];
795 // important if array is empty
796 members = nlohmann::json::array();
797
798 std::vector<std::string> leafNames;
799 for (const auto& drive : resp)
800 {
801 sdbusplus::message::object_path drivePath(drive);
802 leafNames.push_back(drivePath.filename());
803 }
804
Ed Tanous3544d2a2023-08-06 18:12:20 -0700805 std::ranges::sort(leafNames, AlphanumLess<std::string>());
Ed Tanous36d52332023-06-09 13:18:40 -0700806
807 for (const auto& leafName : leafNames)
808 {
809 nlohmann::json::object_t member;
810 member["@odata.id"] = boost::urls::format(
811 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, leafName);
812 members.emplace_back(std::move(member));
813 // navigation links will be registered in next patch set
814 }
815 asyncResp->res.jsonValue["Members@odata.count"] = resp.size();
816 }); // end association lambda
817
818 } // end Iterate over all retrieved ObjectPaths
819}
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700820/**
821 * Chassis drives, this URL will show all the DriveCollection
822 * information
823 */
Nan Zhoub53dcd92022-06-21 17:47:50 +0000824inline void chassisDriveCollectionGet(
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700825 crow::App& app, const crow::Request& req,
826 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
827 const std::string& chassisId)
828{
Carson Labrado3ba00072022-06-06 19:40:56 +0000829 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700830 {
831 return;
832 }
833
834 // mapper call lambda
George Liue99073f2022-12-09 11:06:16 +0800835 constexpr std::array<std::string_view, 2> interfaces = {
836 "xyz.openbmc_project.Inventory.Item.Board",
837 "xyz.openbmc_project.Inventory.Item.Chassis"};
838 dbus::utility::getSubTree(
839 "/xyz/openbmc_project/inventory", 0, interfaces,
Ed Tanous36d52332023-06-09 13:18:40 -0700840 std::bind_front(afterChassisDriveCollectionSubtreeGet, asyncResp,
841 chassisId));
John Edward Broadbent92903bd2022-04-26 13:40:59 -0700842}
843
844inline void requestRoutesChassisDrive(App& app)
845{
846 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/")
847 .privileges(redfish::privileges::getDriveCollection)
848 .methods(boost::beast::http::verb::get)(
849 std::bind_front(chassisDriveCollectionGet, std::ref(app)));
850}
851
Nan Zhoub53dcd92022-06-21 17:47:50 +0000852inline void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
853 const std::string& chassisId,
854 const std::string& driveName,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800855 const boost::system::error_code& ec,
Nan Zhoub53dcd92022-06-21 17:47:50 +0000856 const dbus::utility::MapperGetSubTreeResponse& subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700857{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700858 if (ec)
859 {
Ed Tanous62598e32023-07-17 17:06:25 -0700860 BMCWEB_LOG_DEBUG("DBUS response error {}", ec);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700861 messages::internalError(asyncResp->res);
862 return;
863 }
864
865 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000866 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700867 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700868 sdbusplus::message::object_path objPath(path);
869 if (objPath.filename() != driveName)
870 {
871 continue;
872 }
873
874 if (connectionNames.empty())
875 {
Ed Tanous62598e32023-07-17 17:06:25 -0700876 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700877 continue;
878 }
879
Ed Tanousef4c65b2023-04-24 15:28:50 -0700880 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
881 "/redfish/v1/Chassis/{}/Drives/{}", chassisId, driveName);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700882
883 asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
John Edward Broadbenta0cb40c2022-06-29 17:27:38 -0700884 asyncResp->res.jsonValue["Name"] = driveName;
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700885 asyncResp->res.jsonValue["Id"] = driveName;
886 // default it to Enabled
887 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
888
889 nlohmann::json::object_t linkChassisNav;
890 linkChassisNav["@odata.id"] =
Ed Tanousef4c65b2023-04-24 15:28:50 -0700891 boost::urls::format("/redfish/v1/Chassis/{}", chassisId);
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700892 asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
893
894 addAllDriveInfo(asyncResp, connectionNames[0].first, path,
895 connectionNames[0].second);
896 }
897}
898
Nan Zhoub53dcd92022-06-21 17:47:50 +0000899inline void
900 matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
901 const std::string& chassisId,
902 const std::string& driveName,
903 const std::vector<std::string>& resp)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700904{
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700905 for (const std::string& drivePath : resp)
906 {
907 sdbusplus::message::object_path path(drivePath);
908 std::string leaf = path.filename();
909 if (leaf != driveName)
910 {
911 continue;
912 }
913 // mapper call drive
George Liue99073f2022-12-09 11:06:16 +0800914 constexpr std::array<std::string_view, 1> driveInterface = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700915 "xyz.openbmc_project.Inventory.Item.Drive"};
George Liue99073f2022-12-09 11:06:16 +0800916 dbus::utility::getSubTree(
917 "/xyz/openbmc_project/inventory", 0, driveInterface,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700918 [asyncResp, chassisId, driveName](
George Liue99073f2022-12-09 11:06:16 +0800919 const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700920 const dbus::utility::MapperGetSubTreeResponse& subtree) {
921 buildDrive(asyncResp, chassisId, driveName, ec, subtree);
George Liue99073f2022-12-09 11:06:16 +0800922 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700923 }
924}
925
Nan Zhoub53dcd92022-06-21 17:47:50 +0000926inline void
927 handleChassisDriveGet(crow::App& app, const crow::Request& req,
928 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
929 const std::string& chassisId,
930 const std::string& driveName)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700931{
Michal Orzel03810a12022-06-15 14:04:28 +0200932 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700933 {
934 return;
935 }
George Liue99073f2022-12-09 11:06:16 +0800936 constexpr std::array<std::string_view, 2> interfaces = {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700937 "xyz.openbmc_project.Inventory.Item.Board",
938 "xyz.openbmc_project.Inventory.Item.Chassis"};
939
940 // mapper call chassis
George Liue99073f2022-12-09 11:06:16 +0800941 dbus::utility::getSubTree(
942 "/xyz/openbmc_project/inventory", 0, interfaces,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700943 [asyncResp, chassisId,
George Liue99073f2022-12-09 11:06:16 +0800944 driveName](const boost::system::error_code& ec,
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700945 const dbus::utility::MapperGetSubTreeResponse& subtree) {
946 if (ec)
947 {
948 messages::internalError(asyncResp->res);
949 return;
950 }
951
952 // Iterate over all retrieved ObjectPaths.
Nan Zhou8cb65f82022-06-15 05:12:24 +0000953 for (const auto& [path, connectionNames] : subtree)
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700954 {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700955 sdbusplus::message::object_path objPath(path);
956 if (objPath.filename() != chassisId)
957 {
958 continue;
959 }
960
961 if (connectionNames.empty())
962 {
Ed Tanous62598e32023-07-17 17:06:25 -0700963 BMCWEB_LOG_ERROR("Got 0 Connection names");
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700964 continue;
965 }
966
George Liu6c3e9452023-03-03 13:55:29 +0800967 dbus::utility::getAssociationEndPoints(
968 path + "/drive",
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700969 [asyncResp, chassisId,
Ed Tanous5e7e2dc2023-02-16 10:37:01 -0800970 driveName](const boost::system::error_code& ec3,
George Liu6c3e9452023-03-03 13:55:29 +0800971 const dbus::utility::MapperEndPoints& resp) {
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700972 if (ec3)
973 {
974 return; // no drives = no failures
975 }
976 matchAndFillDrive(asyncResp, chassisId, driveName, resp);
977 });
978 break;
979 }
George Liue99073f2022-12-09 11:06:16 +0800980 });
John Edward Broadbente56ed6b2022-04-26 13:40:59 -0700981}
982
983/**
984 * This URL will show the drive interface for the specific drive in the chassis
985 */
986inline void requestRoutesChassisDriveName(App& app)
987{
988 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
989 .privileges(redfish::privileges::getChassis)
990 .methods(boost::beast::http::verb::get)(
991 std::bind_front(handleChassisDriveGet, std::ref(app)));
992}
993
Willy Tu61b1eb22023-03-14 11:29:50 -0700994inline void getStorageControllerAsset(
995 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
996 const boost::system::error_code& ec,
997 const std::vector<std::pair<std::string, dbus::utility::DbusVariantType>>&
998 propertiesList)
999{
1000 if (ec)
1001 {
1002 // this interface isn't necessary
Ed Tanous62598e32023-07-17 17:06:25 -07001003 BMCWEB_LOG_DEBUG("Failed to get StorageControllerAsset");
Willy Tu61b1eb22023-03-14 11:29:50 -07001004 return;
1005 }
1006
1007 const std::string* partNumber = nullptr;
1008 const std::string* serialNumber = nullptr;
1009 const std::string* manufacturer = nullptr;
1010 const std::string* model = nullptr;
1011 if (!sdbusplus::unpackPropertiesNoThrow(
1012 dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber",
1013 partNumber, "SerialNumber", serialNumber, "Manufacturer",
1014 manufacturer, "Model", model))
1015 {
1016 messages::internalError(asyncResp->res);
1017 return;
1018 }
1019
1020 if (partNumber != nullptr)
1021 {
1022 asyncResp->res.jsonValue["PartNumber"] = *partNumber;
1023 }
1024
1025 if (serialNumber != nullptr)
1026 {
1027 asyncResp->res.jsonValue["SerialNumber"] = *serialNumber;
1028 }
1029
1030 if (manufacturer != nullptr)
1031 {
1032 asyncResp->res.jsonValue["Manufacturer"] = *manufacturer;
1033 }
1034
1035 if (model != nullptr)
1036 {
1037 asyncResp->res.jsonValue["Model"] = *model;
1038 }
1039}
1040
1041inline void populateStorageController(
1042 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1043 const std::string& controllerId, const std::string& connectionName,
1044 const std::string& path)
1045{
1046 asyncResp->res.jsonValue["@odata.type"] =
1047 "#StorageController.v1_6_0.StorageController";
1048 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
1049 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", controllerId);
1050 asyncResp->res.jsonValue["Name"] = controllerId;
1051 asyncResp->res.jsonValue["Id"] = controllerId;
1052 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
1053
1054 sdbusplus::asio::getProperty<bool>(
1055 *crow::connections::systemBus, connectionName, path,
1056 "xyz.openbmc_project.Inventory.Item", "Present",
1057 [asyncResp](const boost::system::error_code& ec, bool isPresent) {
1058 // this interface isn't necessary, only check it
1059 // if we get a good return
1060 if (ec)
1061 {
Ed Tanous62598e32023-07-17 17:06:25 -07001062 BMCWEB_LOG_DEBUG("Failed to get Present property");
Willy Tu61b1eb22023-03-14 11:29:50 -07001063 return;
1064 }
1065 if (!isPresent)
1066 {
1067 asyncResp->res.jsonValue["Status"]["State"] = "Absent";
1068 }
1069 });
1070
1071 sdbusplus::asio::getAllProperties(
1072 *crow::connections::systemBus, connectionName, path,
1073 "xyz.openbmc_project.Inventory.Decorator.Asset",
1074 [asyncResp](const boost::system::error_code& ec,
1075 const std::vector<
1076 std::pair<std::string, dbus::utility::DbusVariantType>>&
1077 propertiesList) {
1078 getStorageControllerAsset(asyncResp, ec, propertiesList);
1079 });
1080}
1081
1082inline void getStorageControllerHandler(
1083 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1084 const std::string& controllerId, const boost::system::error_code& ec,
1085 const dbus::utility::MapperGetSubTreeResponse& subtree)
1086{
1087 if (ec || subtree.empty())
1088 {
1089 // doesn't have to be there
Ed Tanous62598e32023-07-17 17:06:25 -07001090 BMCWEB_LOG_DEBUG("Failed to handle StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001091 return;
1092 }
1093
1094 for (const auto& [path, interfaceDict] : subtree)
1095 {
1096 sdbusplus::message::object_path object(path);
1097 std::string id = object.filename();
1098 if (id.empty())
1099 {
Ed Tanous62598e32023-07-17 17:06:25 -07001100 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001101 return;
1102 }
1103 if (id != controllerId)
1104 {
1105 continue;
1106 }
1107
1108 if (interfaceDict.size() != 1)
1109 {
Ed Tanous62598e32023-07-17 17:06:25 -07001110 BMCWEB_LOG_ERROR("Connection size {}, greater than 1",
1111 interfaceDict.size());
Willy Tu61b1eb22023-03-14 11:29:50 -07001112 messages::internalError(asyncResp->res);
1113 return;
1114 }
1115
1116 const std::string& connectionName = interfaceDict.front().first;
1117 populateStorageController(asyncResp, controllerId, connectionName,
1118 path);
1119 }
1120}
1121
1122inline void populateStorageControllerCollection(
1123 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1124 const boost::system::error_code& ec,
1125 const dbus::utility::MapperGetSubTreePathsResponse& controllerList)
1126{
1127 nlohmann::json::array_t members;
1128 if (ec || controllerList.empty())
1129 {
1130 asyncResp->res.jsonValue["Members"] = std::move(members);
1131 asyncResp->res.jsonValue["Members@odata.count"] = 0;
Ed Tanous62598e32023-07-17 17:06:25 -07001132 BMCWEB_LOG_DEBUG("Failed to find any StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001133 return;
1134 }
1135
1136 for (const std::string& path : controllerList)
1137 {
1138 std::string id = sdbusplus::message::object_path(path).filename();
1139 if (id.empty())
1140 {
Ed Tanous62598e32023-07-17 17:06:25 -07001141 BMCWEB_LOG_ERROR("Failed to find filename in {}", path);
Willy Tu61b1eb22023-03-14 11:29:50 -07001142 return;
1143 }
1144 nlohmann::json::object_t member;
1145 member["@odata.id"] = boost::urls::format(
1146 "/redfish/v1/Systems/system/Storage/1/Controllers/{}", id);
1147 members.emplace_back(member);
1148 }
1149 asyncResp->res.jsonValue["Members@odata.count"] = members.size();
1150 asyncResp->res.jsonValue["Members"] = std::move(members);
1151}
1152
Ed Tanous36d52332023-06-09 13:18:40 -07001153inline void handleSystemsStorageControllerCollectionGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001154 App& app, const crow::Request& req,
1155 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1156 const std::string& systemName)
1157{
1158 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1159 {
Ed Tanous62598e32023-07-17 17:06:25 -07001160 BMCWEB_LOG_DEBUG(
1161 "Failed to setup Redfish Route for StorageController Collection");
Willy Tu61b1eb22023-03-14 11:29:50 -07001162 return;
1163 }
1164 if (systemName != "system")
1165 {
1166 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1167 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001168 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001169 return;
1170 }
1171
1172 asyncResp->res.jsonValue["@odata.type"] =
1173 "#StorageControllerCollection.StorageControllerCollection";
1174 asyncResp->res.jsonValue["@odata.id"] =
1175 "/redfish/v1/Systems/system/Storage/1/Controllers";
1176 asyncResp->res.jsonValue["Name"] = "Storage Controller Collection";
1177
1178 constexpr std::array<std::string_view, 1> interfaces = {
1179 "xyz.openbmc_project.Inventory.Item.StorageController"};
1180 dbus::utility::getSubTreePaths(
1181 "/xyz/openbmc_project/inventory", 0, interfaces,
1182 [asyncResp](const boost::system::error_code& ec,
1183 const dbus::utility::MapperGetSubTreePathsResponse&
1184 controllerList) {
1185 populateStorageControllerCollection(asyncResp, ec, controllerList);
1186 });
1187}
1188
Ed Tanous36d52332023-06-09 13:18:40 -07001189inline void handleSystemsStorageControllerGet(
Willy Tu61b1eb22023-03-14 11:29:50 -07001190 App& app, const crow::Request& req,
1191 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1192 const std::string& systemName, const std::string& controllerId)
1193{
1194 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1195 {
Ed Tanous62598e32023-07-17 17:06:25 -07001196 BMCWEB_LOG_DEBUG("Failed to setup Redfish Route for StorageController");
Willy Tu61b1eb22023-03-14 11:29:50 -07001197 return;
1198 }
1199 if (systemName != "system")
1200 {
1201 messages::resourceNotFound(asyncResp->res, "ComputerSystem",
1202 systemName);
Ed Tanous62598e32023-07-17 17:06:25 -07001203 BMCWEB_LOG_DEBUG("Failed to find ComputerSystem of {}", systemName);
Willy Tu61b1eb22023-03-14 11:29:50 -07001204 return;
1205 }
1206 constexpr std::array<std::string_view, 1> interfaces = {
1207 "xyz.openbmc_project.Inventory.Item.StorageController"};
1208 dbus::utility::getSubTree(
1209 "/xyz/openbmc_project/inventory", 0, interfaces,
1210 [asyncResp,
1211 controllerId](const boost::system::error_code& ec,
1212 const dbus::utility::MapperGetSubTreeResponse& subtree) {
1213 getStorageControllerHandler(asyncResp, controllerId, ec, subtree);
1214 });
1215}
1216
1217inline void requestRoutesStorageControllerCollection(App& app)
1218{
1219 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/")
1220 .privileges(redfish::privileges::getStorageControllerCollection)
Ed Tanous36d52332023-06-09 13:18:40 -07001221 .methods(boost::beast::http::verb::get)(std::bind_front(
1222 handleSystemsStorageControllerCollectionGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001223}
1224
1225inline void requestRoutesStorageController(App& app)
1226{
1227 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/Storage/1/Controllers/<str>")
1228 .privileges(redfish::privileges::getStorageController)
1229 .methods(boost::beast::http::verb::get)(
Ed Tanous36d52332023-06-09 13:18:40 -07001230 std::bind_front(handleSystemsStorageControllerGet, std::ref(app)));
Willy Tu61b1eb22023-03-14 11:29:50 -07001231}
1232
Nikhil Potadea25aecc2019-08-23 16:35:26 -07001233} // namespace redfish