Activation: Delete version interface after activation

When activation is finished, the version interface and the related
images created by phosphor-version-software-manager shall be deleted.

This is done by invoking the Delete method of the related service, so we
need to get all the services from the object, and get the correct
service to invoke the Delete method.

Tested: Verify the Version interface created by
        xyz.openbmc_project.Software.Version service, and the related
        files in /tmp/image/<versionId> are removed after activation is
        completed.

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: Icb14731bbea35175c2519bd40b9f88a0b54a034a
diff --git a/src/activation.cpp b/src/activation.cpp
index df84879..2230d0f 100644
--- a/src/activation.cpp
+++ b/src/activation.cpp
@@ -6,6 +6,8 @@
 
 #include <cassert>
 #include <filesystem>
+#include <phosphor-logging/elog-errors.hpp>
+#include <phosphor-logging/log.hpp>
 
 namespace phosphor
 {
@@ -21,6 +23,8 @@
 namespace fs = std::filesystem;
 namespace softwareServer = sdbusplus::xyz::openbmc_project::Software::server;
 
+using namespace phosphor::logging;
+using sdbusplus::exception::SdBusError;
 using SoftwareActivation = softwareServer::Activation;
 
 namespace internal
@@ -118,12 +122,51 @@
 
 void Activation::finishActivation()
 {
-    // TODO: delete the interfaces created by phosphor-software-manager
     // TODO: delete the old software object
     // TODO: create related associations
+    deleteImageManagerObject();
     activation(Status::Active);
 }
 
+void Activation::deleteImageManagerObject()
+{
+    // Get the Delete object for <versionID> inside image_manager
+    constexpr auto versionServiceStr = "xyz.openbmc_project.Software.Version";
+    constexpr auto deleteInterface = "xyz.openbmc_project.Object.Delete";
+    std::string versionService;
+    auto services = utils::getServices(bus, path.c_str(), deleteInterface);
+
+    // We need to find the phosphor-version-software-manager's version service
+    // to invoke the delete interface
+    for (const auto& service : services)
+    {
+        if (service.find(versionServiceStr) != std::string::npos)
+        {
+            versionService = service;
+            break;
+        }
+    }
+    if (versionService.empty())
+    {
+        log<level::ERR>("Error finding version service");
+        return;
+    }
+
+    // Call the Delete object for <versionID> inside image_manager
+    auto method = bus.new_method_call(versionService.c_str(), path.c_str(),
+                                      deleteInterface, "Delete");
+    try
+    {
+        bus.call(method);
+    }
+    catch (const SdBusError& e)
+    {
+        log<level::ERR>("Error performing call to Delete object path",
+                        entry("ERROR=%s", e.what()),
+                        entry("PATH=%s", path.c_str()));
+    }
+}
+
 } // namespace updater
 } // namespace software
 } // namespace phosphor
diff --git a/src/activation.hpp b/src/activation.hpp
index cde55c5..6d5de67 100644
--- a/src/activation.hpp
+++ b/src/activation.hpp
@@ -99,6 +99,12 @@
      */
     void unitStateChange(sdbusplus::message::message& msg);
 
+    /**
+     * @brief Delete the version from Image Manager and the
+     *        untar image from image upload dir.
+     */
+    void deleteImageManagerObject();
+
     /** @brief Start PSU update */
     void startActivation();
 
diff --git a/src/utils.cpp b/src/utils.cpp
index 7a968b7..33e56be 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -77,6 +77,18 @@
 std::string Utils::getService(sdbusplus::bus::bus& bus, const char* path,
                               const char* interface) const
 {
+    auto services = getServices(bus, path, interface);
+    if (services.empty())
+    {
+        return {};
+    }
+    return services[0];
+}
+
+std::vector<std::string> Utils::getServices(sdbusplus::bus::bus& bus,
+                                            const char* path,
+                                            const char* interface) const
+{
     auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
                                       MAPPER_INTERFACE, "GetObject");
 
@@ -93,11 +105,12 @@
             log<level::ERR>("Error reading mapper response");
             throw std::runtime_error("Error reading mapper response");
         }
-        if (mapperResponse.size() < 1)
+        std::vector<std::string> ret;
+        for (const auto& i : mapperResponse)
         {
-            return "";
+            ret.emplace_back(i.first);
         }
-        return mapperResponse[0].first;
+        return ret;
     }
     catch (const sdbusplus::exception::SdBusError& ex)
     {
diff --git a/src/utils.hpp b/src/utils.hpp
index 86ee5dd..fe376a8 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -37,6 +37,17 @@
 std::string getService(sdbusplus::bus::bus& bus, const char* path,
                        const char* interface);
 
+/** @brief Get all the service names from object path and interface
+ *
+ * @param[in] bus          - The Dbus bus object
+ * @param[in] path         - The Dbus object path
+ * @param[in] interface    - The Dbus interface
+ *
+ * @return The name of the services
+ */
+std::vector<std::string> getServices(sdbusplus::bus::bus& bus, const char* path,
+                                     const char* interface);
+
 /** @brief The template function to get property from the requested dbus path
  *
  * @param[in] bus          - The Dbus bus object
@@ -88,6 +99,10 @@
     virtual std::string getService(sdbusplus::bus::bus& bus, const char* path,
                                    const char* interface) const = 0;
 
+    virtual std::vector<std::string>
+        getServices(sdbusplus::bus::bus& bus, const char* path,
+                    const char* interface) const = 0;
+
     virtual std::string getVersionId(const std::string& version) const = 0;
 
     virtual std::string getVersion(const std::string& inventoryPath) const = 0;
@@ -117,6 +132,10 @@
     std::string getService(sdbusplus::bus::bus& bus, const char* path,
                            const char* interface) const override;
 
+    std::vector<std::string> getServices(sdbusplus::bus::bus& bus,
+                                         const char* path,
+                                         const char* interface) const override;
+
     std::string getVersionId(const std::string& version) const override;
 
     std::string getVersion(const std::string& inventoryPath) const override;
@@ -132,6 +151,13 @@
     return getUtils().getService(bus, path, interface);
 }
 
+inline std::vector<std::string> getServices(sdbusplus::bus::bus& bus,
+                                            const char* path,
+                                            const char* interface)
+{
+    return getUtils().getServices(bus, path, interface);
+}
+
 inline std::vector<std::string> getPSUInventoryPath(sdbusplus::bus::bus& bus)
 {
     return getUtils().getPSUInventoryPath(bus);
diff --git a/test/mocked_utils.hpp b/test/mocked_utils.hpp
index 88fdcf2..7afe07c 100644
--- a/test/mocked_utils.hpp
+++ b/test/mocked_utils.hpp
@@ -17,6 +17,11 @@
                        std::string(sdbusplus::bus::bus& bus, const char* path,
                                    const char* interface));
 
+    MOCK_CONST_METHOD3(getServices,
+                       std::vector<std::string>(sdbusplus::bus::bus& bus,
+                                                const char* path,
+                                                const char* interface));
+
     MOCK_CONST_METHOD1(getVersionId, std::string(const std::string& version));
 
     MOCK_CONST_METHOD1(getVersion,