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);
         });
 }