redfish: Add Chassis associated Drive query
This change supports named drives being queried by their associated
chassis, by using the follow form:
/redfish/v1/Chassis/<chassis>/Drives/<drive>
This change is in accordance with redfish
Tested:
With the redfish validator: No new errors
$ wget -qO- http://localhost:80/redfish/v1/Chassis/DC_SCM/Drives/mmcblk0
{
"@odata.context": "/redfish/v1/$metadata#Drive.Drive",
"@odata.id": "/redfish/v1/Chassis/DC_SCM/Drives/mmcblk0",
"@odata.type": "#Drive.v1_7_0.Drive",
"CapacityBytes": 15634268160,
"Id": "mmcblk0",
"Name": "mmcblk0",
"Status": {
"State": "Enabled"
}
}
Signed-off-by: John Edward Broadbent <jebr@google.com>
Change-Id: I3501ea4789bae57a905052d0e820d441665b72d7
diff --git a/Redfish.md b/Redfish.md
index d301f54..b7d7f4c 100644
--- a/Redfish.md
+++ b/Redfish.md
@@ -150,6 +150,13 @@
(This is dependent on a entity manager association from
Chassis to Drives, The name of the association is "chassis<->drive")
+#### /redfish/v1/Chassis/{ChassisId}/Drive/{DriveId}/
+#### Drive
+- Drives
+- Drives@odata.count
+- Status
+(this is dependant on a entity manager association from Chassis to Drives)
+
#### /redfish/v1/Chassis/{ChassisId}/Power/
##### Power
- PowerControl
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index 0f976d6..eae83e8 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -85,6 +85,7 @@
requestRoutesChassisResetAction(app);
requestRoutesChassisResetActionInfo(app);
requestRoutesChassisDrive(app);
+ requestRoutesChassisDriveName(app);
requestRoutesUpdateService(app);
requestRoutesStorageCollection(app);
requestRoutesStorage(app);
diff --git a/redfish-core/lib/storage.hpp b/redfish-core/lib/storage.hpp
index 282665a..e17130c 100644
--- a/redfish-core/lib/storage.hpp
+++ b/redfish-core/lib/storage.hpp
@@ -471,6 +471,31 @@
});
}
+void addAllDriveInfo(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& connectionName, const std::string& path,
+ const std::vector<std::string>& interfaces)
+{
+ for (const std::string& interface : interfaces)
+ {
+ if (interface == "xyz.openbmc_project.Inventory.Decorator.Asset")
+ {
+ getDriveAsset(asyncResp, connectionName, path);
+ }
+ else if (interface == "xyz.openbmc_project.Inventory.Item")
+ {
+ getDrivePresent(asyncResp, connectionName, path);
+ }
+ else if (interface == "xyz.openbmc_project.State.Drive")
+ {
+ getDriveState(asyncResp, connectionName, path);
+ }
+ else if (interface == "xyz.openbmc_project.Inventory.Item.Drive")
+ {
+ getDriveItemProperties(asyncResp, connectionName, path);
+ }
+ }
+}
+
inline void requestRoutesDrive(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/Drives/<str>/")
@@ -543,29 +568,8 @@
health->inventory.emplace_back(path);
health->populate();
- const std::string& connectionName = connectionNames[0].first;
-
- for (const std::string& interface : connectionNames[0].second)
- {
- if (interface ==
- "xyz.openbmc_project.Inventory.Decorator.Asset")
- {
- getDriveAsset(asyncResp, connectionName, path);
- }
- else if (interface == "xyz.openbmc_project.Inventory.Item")
- {
- getDrivePresent(asyncResp, connectionName, path);
- }
- else if (interface == "xyz.openbmc_project.State.Drive")
- {
- getDriveState(asyncResp, connectionName, path);
- }
- else if (interface ==
- "xyz.openbmc_project.Inventory.Item.Drive")
- {
- getDriveItemProperties(asyncResp, connectionName, path);
- }
- }
+ addAllDriveInfo(asyncResp, connectionNames[0].first, path,
+ connectionNames[0].second);
},
"xyz.openbmc_project.ObjectMapper",
"/xyz/openbmc_project/object_mapper",
@@ -692,4 +696,168 @@
std::bind_front(chassisDriveCollectionGet, std::ref(app)));
}
+void buildDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId, const std::string& driveName,
+ const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree)
+{
+
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ object : subtree)
+ {
+ const std::string& path = object.first;
+ const std::vector<std::pair<std::string, std::vector<std::string>>>&
+ connectionNames = object.second;
+
+ sdbusplus::message::object_path objPath(path);
+ if (objPath.filename() != driveName)
+ {
+ continue;
+ }
+
+ if (connectionNames.empty())
+ {
+ BMCWEB_LOG_ERROR << "Got 0 Connection names";
+ continue;
+ }
+
+ asyncResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
+ "redfish", "v1", "Chassis", "Drives", driveName);
+
+ asyncResp->res.jsonValue["@odata.type"] = "#Drive.v1_7_0.Drive";
+ asyncResp->res.jsonValue["Name"] = "Name";
+ asyncResp->res.jsonValue["Id"] = driveName;
+ // default it to Enabled
+ asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
+
+ nlohmann::json::object_t linkChassisNav;
+ linkChassisNav["@odata.id"] =
+ crow::utility::urlFromPieces("redfish", "v1", "Chassis", chassisId);
+ asyncResp->res.jsonValue["Links"]["Chassis"] = linkChassisNav;
+
+ addAllDriveInfo(asyncResp, connectionNames[0].first, path,
+ connectionNames[0].second);
+ }
+}
+
+void matchAndFillDrive(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId,
+ const std::string& driveName,
+ const std::vector<std::string>& resp)
+{
+
+ for (const std::string& drivePath : resp)
+ {
+ sdbusplus::message::object_path path(drivePath);
+ std::string leaf = path.filename();
+ if (leaf != driveName)
+ {
+ continue;
+ }
+ // mapper call drive
+ const std::array<const char*, 1> driveInterface = {
+ "xyz.openbmc_project.Inventory.Item.Drive"};
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, chassisId, driveName](
+ const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree) {
+ buildDrive(asyncResp, chassisId, driveName, ec, subtree);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", 0, driveInterface);
+ }
+}
+
+void handleChassisDriveGet(crow::App& app, const crow::Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& chassisId,
+ const std::string& driveName)
+{
+ if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
+ {
+ return;
+ }
+ const std::array<const char*, 2> interfaces = {
+ "xyz.openbmc_project.Inventory.Item.Board",
+ "xyz.openbmc_project.Inventory.Item.Chassis"};
+
+ // mapper call chassis
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, chassisId,
+ driveName](const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ object : subtree)
+ {
+ const std::string& path = object.first;
+ const std::vector<std::pair<std::string, std::vector<std::string>>>&
+ connectionNames = object.second;
+
+ sdbusplus::message::object_path objPath(path);
+ if (objPath.filename() != chassisId)
+ {
+ continue;
+ }
+
+ if (connectionNames.empty())
+ {
+ BMCWEB_LOG_ERROR << "Got 0 Connection names";
+ continue;
+ }
+
+ sdbusplus::asio::getProperty<std::vector<std::string>>(
+ *crow::connections::systemBus,
+ "xyz.openbmc_project.ObjectMapper", path + "/drive",
+ "xyz.openbmc_project.Association", "endpoints",
+ [asyncResp, chassisId,
+ driveName](const boost::system::error_code ec3,
+ const std::vector<std::string>& resp) {
+ if (ec3)
+ {
+ return; // no drives = no failures
+ }
+ matchAndFillDrive(asyncResp, chassisId, driveName, resp);
+ });
+ break;
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", 0, interfaces);
+}
+
+/**
+ * This URL will show the drive interface for the specific drive in the chassis
+ */
+inline void requestRoutesChassisDriveName(App& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/Drives/<str>/")
+ .privileges(redfish::privileges::getChassis)
+ .methods(boost::beast::http::verb::get)(
+ std::bind_front(handleChassisDriveGet, std::ref(app)));
+}
+
} // namespace redfish