version manager: Check all software objects

For uploaded tarball, the version manager will check if there is
an existing version, and log "Software Object with the same version
already exists" error.
However it only checks the versions that it creates, but not for
existing versions on D-Bus.

This commit adds additional check, by getting all software objects and
check if the uploaded version exists or not.

Tested: On a BMC running a version, upload the same BMC tarball.
        Before this change, it creates a version object at the same
        D-Bus path;
        With this commit, it logs "Software Object with the same version
        already exists", and REST API returns 400 Bad Request, with
        "description": "Version already exists or failed to be
        extracted"

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I0532ea99eb330060f61c9bbfea4bf2bd746432a7
diff --git a/image_manager.cpp b/image_manager.cpp
index 422e1bf..e132465 100644
--- a/image_manager.cpp
+++ b/image_manager.cpp
@@ -52,6 +52,24 @@
     }
 };
 
+namespace // anonymous
+{
+
+std::vector<std::string> getSoftwareObjects(sdbusplus::bus::bus& bus)
+{
+    std::vector<std::string> paths;
+    auto method = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
+                                      MAPPER_INTERFACE, "GetSubTreePaths");
+    method.append(SOFTWARE_OBJPATH);
+    method.append(0); // Depth 0 to search all
+    method.append(std::vector<std::string>({VERSION_BUSNAME}));
+    auto reply = bus.call(method);
+    reply.read(paths);
+    return paths;
+}
+
+} // namespace
+
 int Manager::processImage(const std::string& tarFilePath)
 {
     if (!fs::is_regular_file(tarFilePath))
@@ -170,11 +188,17 @@
     // Clear the path, so it does not attemp to remove a non-existing path
     tmpDirToRemove.path.clear();
 
-    // Create Version object
     auto objPath = std::string{SOFTWARE_OBJPATH} + '/' + id;
 
-    if (versions.find(id) == versions.end())
+    // This service only manages the uploaded versions, and there could be
+    // active versions on D-Bus that is not managed by this service.
+    // So check D-Bus if there is an existing version.
+    auto allSoftwareObjs = getSoftwareObjects(bus);
+    auto it =
+        std::find(allSoftwareObjs.begin(), allSoftwareObjs.end(), objPath);
+    if (versions.find(id) == versions.end() && it == allSoftwareObjs.end())
     {
+        // Create Version object
         auto versionPtr = std::make_unique<Version>(
             bus, objPath, version, purpose, imageDirPath.string(),
             std::bind(&Manager::erase, this, std::placeholders::_1));