storage: Refactor Drive and StorageController into separate method
Cleanup dbus path with with object_path.filename() to determine to get
the resource ID/Name.
There will be no changes to the redfish tree with this change. This
change help manage the Drive/Storage functions by diving it up into
smaller function with no functional changes.
TESTED:
Redfish Validation passed for Storage
Storage Get
```
wget -qO- http://localhost:80/redfish/v1/Systems/system/Storage/storage0
{
"@odata.id": "/redfish/v1/Systems/system/Storage/storage0",
"@odata.type": "#Storage.v1_7_1.Storage",
"Drives": [
{
"@odata.id": "/redfish/v1/Systems/system/Storage/storage0/Drives/drive0"
}
],
"Drives@odata.count": 1,
"Id": "1",
"Name": "Storage",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
},
"StorageControllers": [
{
"@odata.id": "/redfish/v1/Systems/system/Storage/storage0#/StorageControllers/0",
"@odata.type": "#Storage.v1_7_0.StorageController",
"MemberId": "cpld",
"Name": "cpld",
"Status": {
"Health": "OK",
"HealthRollup": "OK",
"State": "Enabled"
}
}
]
}
```
Change-Id: I334e2233f42efc8e390a410493d7594d5d81bd4e
Signed-off-by: Willy Tu <wltu@google.com>
diff --git a/redfish-core/lib/storage.hpp b/redfish-core/lib/storage.hpp
index a276be1..36916d5 100644
--- a/redfish-core/lib/storage.hpp
+++ b/redfish-core/lib/storage.hpp
@@ -51,6 +51,187 @@
});
}
+inline void getDrives(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::shared_ptr<HealthPopulate>& health)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, health](
+ const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreePathsResponse& driveList) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Drive mapper call error";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ nlohmann::json& driveArray = asyncResp->res.jsonValue["Drives"];
+ driveArray = nlohmann::json::array();
+ auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
+ count = 0;
+
+ health->inventory.insert(health->inventory.end(), driveList.begin(),
+ driveList.end());
+
+ for (const std::string& drive : driveList)
+ {
+ sdbusplus::message::object_path object(drive);
+ if (object.filename().empty())
+ {
+ BMCWEB_LOG_ERROR << "Failed to find filename in " << drive;
+ return;
+ }
+
+ nlohmann::json::object_t driveJson;
+ driveJson["@odata.id"] =
+ "/redfish/v1/Systems/system/Storage/1/Drives/" +
+ object.filename();
+ driveArray.push_back(std::move(driveJson));
+ }
+
+ count = driveArray.size();
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+ "/xyz/openbmc_project/inventory", int32_t(0),
+ std::array<const char*, 1>{"xyz.openbmc_project.Inventory.Item.Drive"});
+}
+
+inline void
+ getStorageControllers(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::shared_ptr<HealthPopulate>& health)
+{
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ health](const boost::system::error_code ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree) {
+ if (ec || subtree.empty())
+ {
+ // doesn't have to be there
+ return;
+ }
+
+ nlohmann::json& root = asyncResp->res.jsonValue["StorageControllers"];
+ root = nlohmann::json::array();
+ for (const auto& [path, interfaceDict] : subtree)
+ {
+ sdbusplus::message::object_path object(path);
+ std::string id = object.filename();
+ if (id.empty())
+ {
+ BMCWEB_LOG_ERROR << "Failed to find filename in " << path;
+ return;
+ }
+
+ if (interfaceDict.size() != 1)
+ {
+ BMCWEB_LOG_ERROR << "Connection size " << interfaceDict.size()
+ << ", greater than 1";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ const std::string& connectionName = interfaceDict.front().first;
+
+ size_t index = root.size();
+ nlohmann::json& storageController =
+ root.emplace_back(nlohmann::json::object());
+
+ storageController["@odata.type"] =
+ "#Storage.v1_7_0.StorageController";
+ storageController["@odata.id"] =
+ "/redfish/v1/Systems/system/Storage/1#/StorageControllers/" +
+ std::to_string(index);
+ storageController["Name"] = id;
+ storageController["MemberId"] = id;
+ storageController["Status"]["State"] = "Enabled";
+
+ sdbusplus::asio::getProperty<bool>(
+ *crow::connections::systemBus, connectionName, path,
+ "xyz.openbmc_project.Inventory.Item", "Present",
+ [asyncResp, index](const boost::system::error_code ec2,
+ bool enabled) {
+ // this interface isn't necessary, only check it
+ // if we get a good return
+ if (ec2)
+ {
+ return;
+ }
+ if (!enabled)
+ {
+ asyncResp->res.jsonValue["StorageControllers"][index]
+ ["Status"]["State"] = "Disabled";
+ }
+ });
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, index](
+ const boost::system::error_code ec2,
+ const std::vector<
+ std::pair<std::string, dbus::utility::DbusVariantType>>&
+ propertiesList) {
+ if (ec2)
+ {
+ // this interface isn't necessary
+ return;
+ }
+ for (const std::pair<std::string,
+ dbus::utility::DbusVariantType>& property :
+ propertiesList)
+ {
+ // Store DBus properties that are also
+ // Redfish properties with same name and a
+ // string value
+ const std::string& propertyName = property.first;
+ nlohmann::json& object =
+ asyncResp->res.jsonValue["StorageControllers"][index];
+ if ((propertyName == "PartNumber") ||
+ (propertyName == "SerialNumber") ||
+ (propertyName == "Manufacturer") ||
+ (propertyName == "Model"))
+ {
+ const std::string* value =
+ std::get_if<std::string>(&property.second);
+ if (value == nullptr)
+ {
+ // illegal property
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ object[propertyName] = *value;
+ }
+ }
+ },
+ connectionName, path, "org.freedesktop.DBus.Properties",
+ "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
+ }
+
+ // this is done after we know the json array will no longer
+ // be resized, as json::array uses vector underneath and we
+ // need references to its members that won't change
+ size_t count = 0;
+ // Pointer based on |asyncResp->res.jsonValue|
+ nlohmann::json::json_pointer rootPtr =
+ "/StorageControllers"_json_pointer;
+ for (const auto& [path, interfaceDict] : subtree)
+ {
+ auto subHealth = std::make_shared<HealthPopulate>(
+ asyncResp, rootPtr / count / "Status");
+ subHealth->inventory.emplace_back(path);
+ health->inventory.emplace_back(path);
+ health->children.emplace_back(subHealth);
+ count++;
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", int32_t(0),
+ std::array<const char*, 1>{
+ "xyz.openbmc_project.Inventory.Item.StorageController"});
+}
+
inline void requestRoutesStorage(App& app)
{
BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/Storage/1/")
@@ -72,185 +253,8 @@
auto health = std::make_shared<HealthPopulate>(asyncResp);
health->populate();
- crow::connections::systemBus->async_method_call(
- [asyncResp,
- health](const boost::system::error_code ec,
- const dbus::utility::MapperGetSubTreePathsResponse&
- storageList) {
- nlohmann::json& storageArray = asyncResp->res.jsonValue["Drives"];
- storageArray = nlohmann::json::array();
- auto& count = asyncResp->res.jsonValue["Drives@odata.count"];
- count = 0;
-
- if (ec)
- {
- BMCWEB_LOG_ERROR << "Drive mapper call error";
- messages::internalError(asyncResp->res);
- return;
- }
-
- health->inventory.insert(health->inventory.end(),
- storageList.begin(), storageList.end());
-
- for (const std::string& objpath : storageList)
- {
- std::size_t lastPos = objpath.rfind('/');
- if (lastPos == std::string::npos ||
- (objpath.size() <= lastPos + 1))
- {
- BMCWEB_LOG_ERROR << "Failed to find '/' in " << objpath;
- continue;
- }
- nlohmann::json::object_t storage;
- storage["@odata.id"] =
- "/redfish/v1/Systems/system/Storage/1/Drives/" +
- objpath.substr(lastPos + 1);
- storageArray.push_back(std::move(storage));
- }
-
- count = storageArray.size();
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
- "/xyz/openbmc_project/inventory", int32_t(0),
- std::array<const char*, 1>{
- "xyz.openbmc_project.Inventory.Item.Drive"});
-
- crow::connections::systemBus->async_method_call(
- [asyncResp,
- health](const boost::system::error_code ec,
- const dbus::utility::MapperGetSubTreeResponse& subtree) {
- if (ec || subtree.empty())
- {
- // doesn't have to be there
- return;
- }
-
- nlohmann::json& root =
- asyncResp->res.jsonValue["StorageControllers"];
- root = nlohmann::json::array();
- for (const auto& [path, interfaceDict] : subtree)
- {
- std::size_t lastPos = path.rfind('/');
- if (lastPos == std::string::npos ||
- (path.size() <= lastPos + 1))
- {
- BMCWEB_LOG_ERROR << "Failed to find '/' in " << path;
- return;
- }
-
- if (interfaceDict.size() != 1)
- {
- BMCWEB_LOG_ERROR << "Connection size "
- << interfaceDict.size()
- << ", greater than 1";
- messages::internalError(asyncResp->res);
- return;
- }
-
- const std::string& connectionName = interfaceDict.front().first;
-
- size_t index = root.size();
- nlohmann::json& storageController =
- root.emplace_back(nlohmann::json::object());
-
- std::string id = path.substr(lastPos + 1);
-
- storageController["@odata.type"] =
- "#Storage.v1_7_0.StorageController";
- storageController["@odata.id"] =
- "/redfish/v1/Systems/system/Storage/1#/StorageControllers/" +
- std::to_string(index);
- storageController["Name"] = id;
- storageController["MemberId"] = id;
- storageController["Status"]["State"] = "Enabled";
-
- sdbusplus::asio::getProperty<bool>(
- *crow::connections::systemBus, connectionName, path,
- "xyz.openbmc_project.Inventory.Item", "Present",
- [asyncResp, index](const boost::system::error_code ec2,
- bool enabled) {
- // this interface isn't necessary, only check it
- // if we get a good return
- if (ec2)
- {
- return;
- }
- if (!enabled)
- {
- asyncResp->res.jsonValue["StorageControllers"][index]
- ["Status"]["State"] =
- "Disabled";
- }
- });
-
- crow::connections::systemBus->async_method_call(
- [asyncResp,
- index](const boost::system::error_code ec2,
- const std::vector<std::pair<
- std::string, dbus::utility::DbusVariantType>>&
- propertiesList) {
- if (ec2)
- {
- // this interface isn't necessary
- return;
- }
- for (const std::pair<std::string,
- dbus::utility::DbusVariantType>&
- property : propertiesList)
- {
- // Store DBus properties that are also
- // Redfish properties with same name and a
- // string value
- const std::string& propertyName = property.first;
- nlohmann::json& object =
- asyncResp->res
- .jsonValue["StorageControllers"][index];
- if ((propertyName == "PartNumber") ||
- (propertyName == "SerialNumber") ||
- (propertyName == "Manufacturer") ||
- (propertyName == "Model"))
- {
- const std::string* value =
- std::get_if<std::string>(&property.second);
- if (value == nullptr)
- {
- // illegal property
- messages::internalError(asyncResp->res);
- return;
- }
- object[propertyName] = *value;
- }
- }
- },
- connectionName, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
- }
-
- // this is done after we know the json array will no longer
- // be resized, as json::array uses vector underneath and we
- // need references to its members that won't change
- size_t count = 0;
- // Pointer based on |asyncResp->res.jsonValue|
- nlohmann::json::json_pointer rootPtr =
- "/StorageControllers"_json_pointer;
- for (const auto& [path, interfaceDict] : subtree)
- {
- auto subHealth = std::make_shared<HealthPopulate>(
- asyncResp, rootPtr / count / "Status");
- subHealth->inventory.emplace_back(path);
- health->inventory.emplace_back(path);
- health->children.emplace_back(subHealth);
- count++;
- }
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree",
- "/xyz/openbmc_project/inventory", int32_t(0),
- std::array<const char*, 1>{
- "xyz.openbmc_project.Inventory.Item.StorageController"});
+ getDrives(asyncResp, health);
+ getStorageControllers(asyncResp, health);
});
}