Unallocate provisioned resources in destructor 61/33761/5
authorMateusz Malicki <m.malicki2@samsung.com>
Wed, 14 Jan 2015 09:18:14 +0000 (10:18 +0100)
committerJan Olszak <j.olszak@samsung.com>
Thu, 15 Jan 2015 14:50:28 +0000 (06:50 -0800)
[Bug/Feature]   Provisioned resources aren't released when "zone->start" throws exception.
[Cause]         There is no destructor in ZoneProvsion class
[Solution]      Destructor was implemented
[Verification]  Build, install, run ZoneProvsionSuite tests

Change-Id: I4d610cae7b1ffee4fd3b06f2906b9e4631a1dcf7

server/zone-provision.cpp
server/zone-provision.hpp
tests/unit_tests/server/ut-zone-provision.cpp

index 3bff4b5..b9192a4 100644 (file)
@@ -67,6 +67,11 @@ ZoneProvision::ZoneProvision(const std::string& zonePath,
     mValidLinkPrefixes = validLinkPrefixes;
 }
 
+ZoneProvision::~ZoneProvision()
+{
+    stop();
+}
+
 std::string ZoneProvision::getRootPath() const
 {
     return mRootPath;
@@ -118,7 +123,9 @@ void ZoneProvision::start() noexcept
                 } else if (unit.is<ZoneProvisioning::Link>()) {
                     link(unit.as<ZoneProvisioning::Link>());
                 }
-            } catch (std::exception& ex) {
+                // mProvisioned must be FILO
+                mProvisioned.push_front(unit);
+            } catch (const std::exception& ex) {
                 LOGE("Provsion error: " << ex.what());
             }
         }
@@ -127,13 +134,18 @@ void ZoneProvision::start() noexcept
 
 void ZoneProvision::stop() noexcept
 {
-    for (auto it = mProvisioningConfig.units.rbegin();
-         it != mProvisioningConfig.units.rend();
-         ++it) {
-        if (it->is<ZoneProvisioning::Mount>()) {
-            umount(it->as<ZoneProvisioning::Mount>());
+    mProvisioned.remove_if([this](const ZoneProvisioning::Unit& unit) -> bool {
+        try {
+            if (unit.is<ZoneProvisioning::Mount>()) {
+                umount(unit.as<ZoneProvisioning::Mount>());
+            }
+            // leaves files, links, fifo, untouched
+            return true;
+        } catch (const std::exception& ex) {
+            LOGE("Provsion error: " << ex.what());
+            return false;
         }
-    }
+    });
 }
 
 void ZoneProvision::file(const ZoneProvisioning::File& config)
@@ -187,7 +199,10 @@ void ZoneProvision::mount(const ZoneProvisioning::Mount& config)
 void ZoneProvision::umount(const ZoneProvisioning::Mount& config)
 {
     const fs::path hostPath = fs::path(mRootPath) / fs::path(config.target);
-    utils::umount(hostPath.string());
+    bool ret = utils::umount(hostPath.string());
+    if (!ret) {
+        throw UtilsException("Umount operation failure - path : " + config.target);
+    }
 }
 
 void ZoneProvision::link(const ZoneProvisioning::Link& config)
index c87fbe9..5585c1f 100644 (file)
@@ -30,6 +30,7 @@
 
 #include <string>
 #include <vector>
+#include <list>
 
 namespace vasum {
 
@@ -47,6 +48,7 @@ public:
      */
     ZoneProvision(const std::string& zonePath,
                   const std::vector<std::string>& validLinkPrefixes);
+    ~ZoneProvision();
 
     /**
      * Declare file, directory or pipe that will be created while zone startup
@@ -82,6 +84,7 @@ private:
     std::string mRootPath;
     std::string mProvisionFile;
     std::vector<std::string> mValidLinkPrefixes;
+    std::list<ZoneProvisioning::Unit> mProvisioned;
 
     void mount(const ZoneProvisioning::Mount& config);
     void umount(const ZoneProvisioning::Mount& config);
index 6a6e4ef..239d53e 100644 (file)
 /**
  * @file
  * @author  Mateusz Malicki (m.malicki2@samsung.com)
- * @brief   Unit tests of the ZoneProvsion class
+ * @brief   Unit tests of the ZoneProvision class
  */
 
 #include "config.hpp"
 #include "ut.hpp"
 
-#include "zone.hpp"
-
-#include "utils/glib-loop.hpp"
 #include "utils/scoped-dir.hpp"
+#include "utils/exception.hpp"
 #include "config/manager.hpp"
+#include "zone-provision.hpp"
 #include "zone-provision-config.hpp"
 #include "vasum-client.h"
 
-#include <memory>
 #include <string>
+#include <fstream>
 
 #include <boost/filesystem.hpp>
 #include <sys/mount.h>
@@ -49,8 +48,7 @@ namespace fs = boost::filesystem;
 namespace {
 
 const std::string PROVISON_CONFIG_FILE = "provision.conf";
-const std::string ZONE = "ut-zone-test";
-const fs::path TEST_CONFIG_PATH = VSM_TEST_CONFIG_INSTALL_DIR "/server/ut-zone/zones/test.conf";
+const std::string ZONE = "ut-zone-provision-test";
 const fs::path ZONES_PATH = "/tmp/ut-zones";
 const fs::path LXC_TEMPLATES_PATH = VSM_TEST_LXC_TEMPLATES_INSTALL_DIR;
 const fs::path ZONE_PATH = ZONES_PATH / fs::path(ZONE);
@@ -58,26 +56,14 @@ const fs::path PROVISION_FILE_PATH = ZONE_PATH / fs::path(PROVISON_CONFIG_FILE);
 const fs::path ROOTFS_PATH = ZONE_PATH / fs::path("rootfs");
 
 struct Fixture {
-    utils::ScopedGlibLoop mLoop;
     utils::ScopedDir mZonesPathGuard;
-    utils::ScopedDir mRunGuard;
     utils::ScopedDir mRootfsPath;
 
     Fixture()
         : mZonesPathGuard(ZONES_PATH.string())
-        , mRunGuard("/tmp/ut-run")
         , mRootfsPath(ROOTFS_PATH.string())
     {
     }
-
-    std::unique_ptr<Zone> create(const std::string& configPath)
-    {
-        return std::unique_ptr<Zone>(new Zone(utils::Worker::create(),
-                                              ZONES_PATH.string(),
-                                              configPath,
-                                              LXC_TEMPLATES_PATH.string(),
-                                              ""));
-    }
 };
 
 } // namespace
@@ -85,6 +71,34 @@ struct Fixture {
 
 BOOST_FIXTURE_TEST_SUITE(ZoneProvisionSuite, Fixture)
 
+BOOST_AUTO_TEST_CASE(DestructorTest)
+{
+    const fs::path mountTarget = fs::path("/opt/usr/data/ut-from-host-provision");
+    const fs::path mountSource = fs::path("/tmp/ut-provision");
+    {
+        utils::ScopedDir provisionfs(mountSource.string());
+
+        ZoneProvisioning config;
+        ZoneProvisioning::Unit unit;
+        unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY,
+                                        mountTarget.string(),
+                                        0,
+                                        0777}));
+        config.units.push_back(unit);
+        unit.set(ZoneProvisioning::Mount({mountSource.string(),
+                                          mountTarget.string(),
+                                          "",
+                                          MS_BIND,
+                                          ""}));
+        config.units.push_back(unit);
+
+        config::saveToFile(PROVISION_FILE_PATH.string(), config);
+        ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+        zoneProvision.start();
+    }
+    BOOST_CHECK(!fs::exists(mountSource));
+}
+
 BOOST_AUTO_TEST_CASE(FileTest)
 {
     //TODO: Test Fifo
@@ -116,15 +130,16 @@ BOOST_AUTO_TEST_CASE(FileTest)
                                     0777}));
     config.units.push_back(unit);
     config::saveToFile(PROVISION_FILE_PATH.string(), config);
-    auto c = create(TEST_CONFIG_PATH.string());
-    c->start();
+
+    ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+    zoneProvision.start();
 
     BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile.parent_path()));
     BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile));
     BOOST_CHECK(fs::exists(ROOTFS_PATH / copyFile.parent_path()));
     BOOST_CHECK(fs::exists(ROOTFS_PATH / copyFile));
 
-    c->stop();
+    zoneProvision.stop();
 }
 
 BOOST_AUTO_TEST_CASE(MountTest)
@@ -155,16 +170,16 @@ BOOST_AUTO_TEST_CASE(MountTest)
                                     O_CREAT,
                                     0777}));
     config.units.push_back(unit);
-
     config::saveToFile(PROVISION_FILE_PATH.string(), config);
-    auto c = create(TEST_CONFIG_PATH.string());
-    c->start();
+
+    ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+    zoneProvision.start();
 
     BOOST_CHECK(fs::exists(ROOTFS_PATH / mountTarget));
     BOOST_CHECK(fs::exists(ROOTFS_PATH / mountTarget / sharedFile));
     BOOST_CHECK(fs::exists(mountSource / sharedFile));
 
-    c->stop();
+    zoneProvision.stop();
 }
 
 BOOST_AUTO_TEST_CASE(LinkTest)
@@ -178,15 +193,25 @@ BOOST_AUTO_TEST_CASE(LinkTest)
                                      linkFile.string()}));
     config.units.push_back(unit);
     config::saveToFile(PROVISION_FILE_PATH.string(), config);
-    auto c = create(TEST_CONFIG_PATH.string());
-    c->start();
+    {
+        ZoneProvision zoneProvision(ZONE_PATH.string(), {});
+        zoneProvision.start();
 
-    BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile));
+        BOOST_CHECK(!fs::exists(ROOTFS_PATH / linkFile));
+
+        zoneProvision.stop();
+    }
+    {
+        ZoneProvision zoneProvision(ZONE_PATH.string(), {"/tmp/"});
+        zoneProvision.start();
+
+        BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile));
 
-    c->stop();
+        zoneProvision.stop();
+    }
 }
 
-BOOST_AUTO_TEST_CASE(DeclareFile)
+BOOST_AUTO_TEST_CASE(DeclareFileTest)
 {
     ZoneProvision zoneProvision(ZONE_PATH.string(), {});
     zoneProvision.declareFile(1, "path", 0747, 0777);
@@ -204,7 +229,7 @@ BOOST_AUTO_TEST_CASE(DeclareFile)
     BOOST_CHECK_EQUAL(unit.mode, 0777);
 }
 
-BOOST_AUTO_TEST_CASE(DeclareMount)
+BOOST_AUTO_TEST_CASE(DeclareMountTest)
 {
     ZoneProvision zoneProvision(ZONE_PATH.string(), {});
     zoneProvision.declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake");
@@ -223,7 +248,7 @@ BOOST_AUTO_TEST_CASE(DeclareMount)
     BOOST_CHECK_EQUAL(unit.data, "fake");
 }
 
-BOOST_AUTO_TEST_CASE(DeclareLink)
+BOOST_AUTO_TEST_CASE(DeclareLinkTest)
 {
     ZoneProvision zoneProvision(ZONE_PATH.string(), {});
     zoneProvision.declareLink("/fake/path1", "/fake/path2");
@@ -239,4 +264,56 @@ BOOST_AUTO_TEST_CASE(DeclareLink)
     BOOST_CHECK_EQUAL(unit.target, "/fake/path2");
 }
 
+BOOST_AUTO_TEST_CASE(ProvisionedAlreadyTest)
+{
+    const fs::path dir = fs::path("/opt/usr/data/ut-from-host-provision");
+    const fs::path linkFile = fs::path("/ut-from-host-provision.conf");
+    const fs::path regularFile = fs::path("/opt/usr/data/ut-regular-file");
+
+    ZoneProvisioning config;
+    ZoneProvisioning::Unit unit;
+    unit.set(ZoneProvisioning::File({VSMFILE_DIRECTORY,
+                                    dir.string(),
+                                    0,
+                                    0777}));
+    config.units.push_back(unit);
+    unit.set(ZoneProvisioning::Link({PROVISION_FILE_PATH.string(),
+                                     linkFile.string()}));
+    config.units.push_back(unit);
+    unit.set(ZoneProvisioning::File({VSMFILE_REGULAR,
+                                    regularFile.string(),
+                                    O_CREAT,
+                                    0777}));
+    config.units.push_back(unit);
+
+    config::saveToFile(PROVISION_FILE_PATH.string(), config);
+
+    ZoneProvision zoneProvision(ZONE_PATH.string(), {"/tmp/"});
+    zoneProvision.start();
+
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / dir));
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile));
+    BOOST_CHECK(fs::is_empty(ROOTFS_PATH / regularFile));
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile));
+
+    std::fstream file((ROOTFS_PATH / regularFile).string(), std::fstream::out);
+    BOOST_REQUIRE(file.is_open());
+    file << "touch" << std::endl;
+    file.close();
+    BOOST_REQUIRE(!fs::is_empty(ROOTFS_PATH / regularFile));
+
+    zoneProvision.stop();
+
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / dir));
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / regularFile));
+    BOOST_CHECK(!fs::is_empty(ROOTFS_PATH / regularFile));
+    BOOST_CHECK(fs::exists(ROOTFS_PATH / linkFile));
+
+    zoneProvision.start();
+
+    BOOST_CHECK(!fs::is_empty(ROOTFS_PATH / regularFile));
+
+    zoneProvision.stop();
+}
+
 BOOST_AUTO_TEST_SUITE_END()