Clean up zones root path 95/44195/7
authorMateusz Malicki <m.malicki2@samsung.com>
Fri, 17 Jul 2015 14:49:43 +0000 (16:49 +0200)
committerMateusz Malicki <m.malicki2@samsung.com>
Fri, 24 Jul 2015 08:51:54 +0000 (10:51 +0200)
[Feature]       Clean up zones root path (according to cleanUpZonesPath flag)
[Cause]         N/A
[Solution]      Added cleanUpZonesPath to daemon.conf which tells whether
                to remove unknown files from the zonesPath;
                Added (vsm_)clean_up_zones_root to cli and client
[Verification]  Build, install, create files in zonesPath,
                run vasum-server with different flag value, check if
                zonesPath is as it should; execute command

Change-Id: I64a1656ef05ccd5fd7e83a48cd50234e2e6bd4b4

17 files changed:
cli/command-line-interface.cpp
cli/command-line-interface.hpp
cli/main.cpp
client/vasum-client-impl.cpp
client/vasum-client-impl.hpp
client/vasum-client.cpp
client/vasum-client.h
server/configs/daemon.conf.in
server/host-dbus-connection.cpp
server/host-dbus-definitions.hpp
server/host-ipc-connection.cpp
server/host-ipc-connection.hpp
server/host-ipc-definitions.hpp
server/zones-manager-config.hpp
server/zones-manager.cpp
server/zones-manager.hpp
tests/unit_tests/configs/test-daemon.conf.in

index cdd64b4..29dd4a3 100644 (file)
@@ -649,5 +649,12 @@ void netdev_down(const Args& argv)
                   argv[2].c_str()));
 }
 
+void clean_up_zones_root(const Args& /* argv */)
+{
+    using namespace std::placeholders;
+
+    CommandLineInterface::executeCallback(bind(vsm_clean_up_zones_root, _1));
+}
+
 } // namespace cli
 } // namespace vasum
index 54ea7b9..f13fab5 100644 (file)
@@ -340,6 +340,13 @@ void netdev_up(const Args& argv);
  */
 void netdev_down(const Args& argv);
 
+/**
+ * Parses command line arguments and call vsm_clean_up_zones_root
+ *
+ * @see vsm_clean_up_zones_root
+ */
+void clean_up_zones_root(const Args& argv);
+
 } // namespace cli
 } // namespace vasum
 
index c5fe0c1..efff7c6 100644 (file)
@@ -328,6 +328,15 @@ std::map<std::string, CommandLineInterface> commands = {
             {{"zone_id", "id zone name"},
              {"netdev_id", "network device id"}}
         }
+    },
+    {
+        "clean_up_zones_root", {
+            clean_up_zones_root,
+            "clean_up_zones_root",
+            "Clean up zones root directory",
+            MODE_COMMAND_LINE | MODE_INTERACTIVE,
+            {}
+        }
     }
 };
 
index d99b08b..78c2d8f 100644 (file)
@@ -882,3 +882,12 @@ VsmStatus Client::vsm_remove_declaration(const char* id, VsmString declaration)
     });
 }
 
+VsmStatus Client::vsm_clean_up_zones_root() noexcept
+{
+    return coverException([&] {
+        mClient->callSync<api::Void, api::Void>(
+            api::ipc::METHOD_CLEAN_UP_ZONES_ROOT,
+            std::make_shared<api::Void>());
+    });
+}
+
index 57797c2..1195b66 100644 (file)
@@ -340,6 +340,11 @@ public:
      */
     VsmStatus vsm_remove_declaration(const char* zone, VsmString declaration) noexcept;
 
+    /**
+     * @see ::vsm_clean_up_zones_root
+     */
+    VsmStatus vsm_clean_up_zones_root() noexcept;
+
 private:
     struct Status {
         Status();
index ac77187..68496d5 100644 (file)
@@ -390,3 +390,8 @@ API VsmStatus vsm_remove_declaration(VsmClient client,
     return getClient(client).vsm_remove_declaration(zone, declaration);
 }
 
+API VsmStatus vsm_clean_up_zones_root(VsmClient client)
+{
+    return getClient(client).vsm_clean_up_zones_root();
+}
+
index cd38aee..06ad043 100644 (file)
@@ -894,6 +894,13 @@ VsmStatus vsm_remove_declaration(VsmClient client,
                                  const char* zone,
                                  VsmString declaration);
 
+/**
+ * Clean up zones root directory
+ *
+ * Removes all unknown zones root directory entry
+ * @return status of this function call
+ */
+VsmStatus vsm_clean_up_zones_root(VsmClient client);
 
 /** @} Host API */
 
index f3dd9fd..96d748f 100644 (file)
@@ -2,6 +2,7 @@
     "dbPath" : "/etc/vasum/vasum.db",
     "zoneIds" : [],
     "zonesPath" : "${DATA_DIR}/zones",
+    "cleanUpZonesPath" : false,
     "zoneImagePath" : "",
     "zoneTemplateDir" : "/etc/vasum/templates/",
     "runMountPointPrefix" : "/var/run/zones",
index 53fc271..90a248b 100644 (file)
@@ -405,6 +405,12 @@ void HostDbusConnection::onMessageCall(const std::string& objectPath,
         mZonesManagerPtr->handleSwitchToDefaultCall(EMPTY_CALLER, rb);
         return;
     }
+
+    if (methodName == api::dbus::METHOD_CLEAN_UP_ZONES_ROOT) {
+        auto rb = std::make_shared<api::DbusMethodResultBuilder<api::Void>>(result);
+        mZonesManagerPtr->handleCleanUpZonesRootCall(rb);
+        return;
+    }
 }
 
 void HostDbusConnection::onClientVanished(const std::string& name)
index 7aeaf31..d06d087 100644 (file)
@@ -66,6 +66,7 @@ const std::string METHOD_CREATE_FILE              = "CreateFile";
 const std::string METHOD_LOCK_QUEUE               = "LockQueue";
 const std::string METHOD_UNLOCK_QUEUE             = "UnlockQueue";
 const std::string METHOD_SWITCH_TO_DEFAULT        = "SwitchToDefault";
+const std::string METHOD_CLEAN_UP_ZONES_ROOT      = "CleanUpZonesRoot";
 
 const std::string DEFINITION =
     "<node>"
@@ -205,6 +206,8 @@ const std::string DEFINITION =
     "    </method>"
     "    <method name='" + METHOD_SWITCH_TO_DEFAULT + "'>"
     "    </method>"
+    "    <method name='" + METHOD_CLEAN_UP_ZONES_ROOT + "'>"
+    "    </method>"
     "  </interface>"
     "</node>";
 
index d3684b9..c2ba755 100644 (file)
@@ -135,6 +135,9 @@ HostIPCConnection::HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesMana
 
     setCreateFileCallback(std::bind(&ZonesManager::handleCreateFileCall,
                                     mZonesManagerPtr, _1, _2));
+
+    setCleanUpZonesRootCallback(std::bind(&ZonesManager::handleCleanUpZonesRootCall,
+                                          mZonesManagerPtr, _1));
 }
 
 HostIPCConnection::~HostIPCConnection()
@@ -392,4 +395,12 @@ void HostIPCConnection::setCreateFileCallback(const Method<const api::CreateFile
         Method::getWrapper(callback));
 }
 
+void HostIPCConnection::setCleanUpZonesRootCallback(const Method<api::Void>::type& callback)
+{
+    typedef IPCMethodWrapper<api::Void> Callback;
+    mService->setMethodHandler<Callback::out, Callback::in>(
+        api::ipc::METHOD_CLEAN_UP_ZONES_ROOT,
+        Callback::getWrapper(callback));
+}
+
 } // namespace vasum
index da3dbd4..47a7612 100644 (file)
@@ -87,6 +87,7 @@ private:
     void setRevokeDeviceCallback(const Method<const api::RevokeDeviceIn>::type& callback);
     void setSwitchToDefaultCallback(const Method<api::Void>::type& callback);
     void setCreateFileCallback(const Method<const api::CreateFileIn, api::CreateFileOut>::type& callback);
+    void setCleanUpZonesRootCallback(const Method<api::Void>::type& callback);
 
     std::unique_ptr<ipc::Service> mService;
     ZonesManager* mZonesManagerPtr;
index 5fb6114..143f89d 100644 (file)
@@ -60,6 +60,7 @@ const ::ipc::MethodID METHOD_CREATE_FILE              = 27;
 const ::ipc::MethodID METHOD_LOCK_QUEUE               = 28;
 const ::ipc::MethodID METHOD_UNLOCK_QUEUE             = 29;
 const ::ipc::MethodID METHOD_SWITCH_TO_DEFAULT        = 30;
+const ::ipc::MethodID METHOD_CLEAN_UP_ZONES_ROOT      = 31;
 
 } // namespace ipc
 } // namespace api
index 6e4625f..e300e75 100644 (file)
@@ -49,6 +49,11 @@ struct ZonesManagerConfig {
     std::string zonesPath;
 
     /**
+     * If set then all files not related with existing containers will be removed
+     */
+    bool cleanUpZonesPath;
+
+    /**
      * A path where the zones image reside. Empty path means that zones image won't be
      * copied to zonesPath when creating new zone.
      */
@@ -83,6 +88,7 @@ struct ZonesManagerConfig {
     (
         dbPath,
         zonesPath,
+        cleanUpZonesPath,
         zoneImagePath,
         zoneTemplateDir,
         availableVTs,
index 0787be0..484b3e9 100644 (file)
@@ -45,6 +45,8 @@
 #include <cassert>
 #include <string>
 #include <climits>
+#include <cctype>
+#include <set>
 
 
 namespace vasum {
@@ -61,6 +63,11 @@ const boost::regex ZONE_IP_THIRD_OCTET_REGEX("~IP~");
 
 const unsigned int ZONE_IP_BASE_THIRD_OCTET = 100;
 
+const std::vector<std::string> prohibitedZonesNames{
+    ENABLED_FILE_NAME,
+    "lxc-monitord.log"
+};
+
 template<typename T>
 void remove(std::vector<T>& v, const T& item)
 {
@@ -97,6 +104,55 @@ bool zoneIsRunning(const std::unique_ptr<Zone>& zone) {
     return zone->isRunning();
 }
 
+bool isalnum(const std::string& str)
+{
+    for (const auto& c : str) {
+        if (!std::isalnum(c)) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void cleanUpUnknownsFromRoot(const boost::filesystem::path& zonesPath,
+                             const std::vector<std::string>& zoneIds,
+                             bool dryRun)
+{
+    namespace fs =  boost::filesystem;
+    const auto end = fs::directory_iterator();
+
+    std::set<std::string> knowns(zoneIds.begin(), zoneIds.end());
+    knowns.insert(prohibitedZonesNames.begin(), prohibitedZonesNames.end());
+
+    // Remove all directories that start with '.'
+    for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
+        if (zoneDir->path().filename().string()[0] ==  '.') {
+            if (!dryRun) {
+                fs::remove_all(zoneDir->path());
+                LOGI("Remove directory entry: " << *zoneDir);
+            } else {
+                LOGI("Remove directory entry (dry run): " << *zoneDir);
+            }
+        }
+    }
+
+    for (auto zoneDir = fs::directory_iterator(zonesPath); zoneDir != end; ++zoneDir) {
+        const auto zoneIt = knowns.find(zoneDir->path().filename().string());
+        if (zoneIt == knowns.end()) {
+            if (!dryRun) {
+                const std::string filename = '.' + zoneDir->path().filename().string();
+                fs::path newName = zoneDir->path().parent_path() / filename;
+
+                fs::rename(zoneDir->path(), newName);
+                fs::remove_all(newName);
+                LOGI("Remove directory entry: " << *zoneDir);
+            } else {
+                LOGI("Remove directory entry (dry run): " << *zoneDir);
+            }
+        }
+    }
+}
+
 } // namespace
 
 
@@ -133,6 +189,8 @@ void ZonesManager::start()
 
     mIsRunning = true;
 
+    cleanUpUnknownsFromRoot(mConfig.zonesPath, mDynamicConfig.zoneIds, !mConfig.cleanUpZonesPath);
+
 #ifdef DBUS_CONNECTION
     using namespace std::placeholders;
     mProxyCallPolicy.reset(new ProxyCallPolicy(mConfig.proxyCallRules));
@@ -1132,11 +1190,16 @@ int ZonesManager::getVTForNewZone()
 void ZonesManager::createZone(const std::string& id,
                               const std::string& templateName)
 {
-    if (id.empty()) { // TODO validate id (no spaces, slashes etc)
+    if (id.empty() || !isalnum(id)) {
         LOGE("Failed to add zone - invalid name.");
         throw InvalidZoneIdException("Invalid name");
     }
 
+    if (find(prohibitedZonesNames.begin(), prohibitedZonesNames.end(), id) != prohibitedZonesNames.end()) {
+        LOGE("Cannot create " << id << " zone - name is not allowed!");
+        throw InvalidZoneIdException("Zone name is not allowed");
+    }
+
     LOGI("Creating zone " << id);
 
     Lock lock(mMutex);
@@ -1151,6 +1214,12 @@ void ZonesManager::createZone(const std::string& id,
         throw InvalidZoneIdException("Already exists");
     }
 
+    if (fs::exists(fs::path(mConfig.zonesPath) / id)) {
+        LOGE("Cannot create " << id << " zone - file system already exists!");
+        throw InvalidZoneIdException("Zone file system already exists but there is no configuration for it. "
+                                     "Check cleanUpZonesPath in daemon.conf");
+    }
+
     const std::string zonePathStr = utils::createFilePath(mConfig.zonesPath, id, "/");
 
     // copy zone image if config contains path to image
@@ -1210,9 +1279,9 @@ void ZonesManager::handleCreateZoneCall(const api::CreateZoneIn& data,
             createZone(data.first, data.second);
             result->setVoid();
         } catch (const InvalidZoneIdException& e) {
-            result->setError(api::ERROR_INVALID_ID, "Existing or invalid zone id");
-        } catch (const std::runtime_error& e) {
-            result->setError(api::ERROR_INTERNAL, "Failed to create zone");
+            result->setError(api::ERROR_INVALID_ID, e.what());
+        } catch (const std::exception& e) {
+            result->setError(api::ERROR_INTERNAL, e.what());
         }
     };
 
@@ -1456,4 +1525,24 @@ void ZonesManager::handleRevokeDeviceCall(const api::RevokeDeviceIn& data,
     tryAddTask(handler, result, true);
 }
 
+void ZonesManager::handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result)
+{
+    auto handler = [&, this] {
+        LOGI("CleanUpZonesRoot call");
+        try {
+            std::vector<std::string> zonesIds;
+            Lock lock(mMutex);
+            for (const auto& zone : mZones) {
+                zonesIds.push_back(zone->getId());
+            }
+            cleanUpUnknownsFromRoot(mConfig.zonesPath, zonesIds, false);
+        } catch (const std::exception& e) {
+            result->setError(api::ERROR_INTERNAL, e.what());
+        }
+        result->setVoid();
+    };
+
+    tryAddTask(handler, result, true);
+}
+
 } // namespace vasum
index 6a7a2c4..de6663d 100644 (file)
@@ -196,6 +196,7 @@ public:
                               api::MethodResultBuilder::Pointer result);
     void handleSwitchToDefaultCall(const std::string& caller,
                                    api::MethodResultBuilder::Pointer result);
+    void handleCleanUpZonesRootCall(api::MethodResultBuilder::Pointer result);
 
 private:
     typedef std::recursive_mutex Mutex;
index 5151fbe..66ca69f 100644 (file)
@@ -2,6 +2,7 @@
     "dbPath" : "/tmp/ut-zones/vasum.db",
     "zoneIds" : [],
     "zonesPath" : "/tmp/ut-zones",
+    "cleanUpZonesPath" : false,
     "zoneImagePath" : "",
     "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/templates/",
     "runMountPointPrefix" : "",