[node-patches] Change in ovirt-node[master]: [WIP] utils_fs: Add symlink support

asegurap at redhat.com asegurap at redhat.com
Fri Jun 20 23:04:23 UTC 2014


Antoni Segura Puimedon has uploaded a new change for review.

Change subject: [WIP] utils_fs: Add symlink support
......................................................................

[WIP] utils_fs: Add symlink support

Change-Id: Ibcc52e9e5cd99bb7f342bb024d1aae12831ddc60
Signed-off-by: Antoni S. Puimedon <asegurap at redhat.com>
---
M src/ovirt/node/utils/fs/__init__.py
1 file changed, 110 insertions(+), 6 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-node refs/changes/13/29013/1

diff --git a/src/ovirt/node/utils/fs/__init__.py b/src/ovirt/node/utils/fs/__init__.py
index a02ad08..b3e7539 100644
--- a/src/ovirt/node/utils/fs/__init__.py
+++ b/src/ovirt/node/utils/fs/__init__.py
@@ -22,12 +22,15 @@
 """
 Some convenience functions realted to the filesystem
 """
+from __future__ import print_function
 
 import shutil
+import errno
 import os
 import re
 import StringIO
 
+from . import mount
 from .. import process, parse_varfile
 from ... import base, log
 
@@ -382,17 +385,118 @@
 class Config(base.Base):
     """oVirt Node specififc way to persist files
     """
-    basedir = "/config"
+    basedir = '/config'
+    path_entries = '/config/files'
 
     def _config_path(self, fn=""):
         return os.path.join(self.basedir, fn.strip("/"))
 
-    def persist(self, filename):
-        """Persist a file and bind mount it
+    def persist(self, path):
+        """Persist path and bind mount it back to its current location
         """
-        if filename and self.is_enabled():
-            from ovirtnode import ovirtfunctions
-            return ovirtfunctions.ovirt_store_config(filename)
+        # TODO: Abort if it is stateless
+        if not self.is_enabled():
+            return
+        abspath = os.path.abspath(path)
+        if os.path.exists(abspath):
+            # Check first for symlinks as os.path file type detection follows
+            # links and will give the type of the target
+            if os.path.islink(abspath):
+                self._persist_symlink(abspath)
+            elif os.path.isdir(abspath):
+                self._persist_dir(abspath)
+            elif os.path.isfile(abspath):
+                self._persist_file(abspath)
+
+    def _persist_dir(self, abspath):
+        """Persist directory and bind mount it back to its current location
+        """
+        persisted_path = os.path.join(self.basedir, abspath)
+        if os.path.exists(persisted_path):
+            logger.warn('Directory "%s" had already been persisted' % abspath)
+            return
+
+        shutil.copytree(abspath, persisted_path, symlinks=True)
+        mount.mount(persisted_path, abspath, flags=mount.MS_BIND)
+        logger.info('Directory "%s" successfully persisted' % abspath)
+        self._add_path_entry(abspath)
+
+    def _persist_file(self, abspath):
+        """Persist file and bind mount it back to its current location
+        """
+        from ovirtnode import ovirtfunctions
+        persisted_path = os.path.join(self.basedir, abspath)
+        if os.path.exists(persisted_path):
+            current_checksum = ovirtfunctions.cksum(abspath)
+            stored_checksum = ovirtfunctions.cksum(persisted_path)
+            if stored_checksum == current_checksum:
+                logger.warn('File "%s" had already been persisted' % abspath)
+                return
+            else:  # Refresh
+                try:
+                    mount.umount(abspath)
+                    os.unlink(persisted_path)
+                except OSError as ose:
+                    logger.error('Failed to refresh persisted file "%s": %s' %
+                                 (abspath, ose.message))
+        self._prepare_dir(persisted_path)
+        shutil.copy2(abspath, persisted_path)
+        mount.mount(persisted_path, abspath, flags=mount.MS_BIND)
+        logger.info('File "%s" successfully persisted' % abspath)
+        self._add_path_entry(abspath)
+
+    def _persist_symlink(self, abspath):
+        """Persist symbolic link and bind mount it back to its current location
+        """
+        persisted_path = os.path.join(self.basedir, abspath)
+        current_target = os.readlink(abspath)
+        if os.path.exists(persisted_path):
+            stored_target = os.readlink(persisted_path)
+            if stored_target == current_target:
+                logger.warn('Symlink "%s" had already been persisted' %
+                            abspath)
+                return
+            else:
+                # Write the new symlink to an alternate location and atomically
+                # rename
+                self._prepare_dir(persisted_path)
+                tmp_path = persisted_path + '.ovirtnode.atom'
+                try:
+                    os.symlink(current_target, tmp_path)
+                except Exception:
+                    raise
+                else:
+                    os.rename(tmp_path, persisted_path)
+        else:
+            self._prepare_dir(persisted_path)
+            os.symlink(current_target, persisted_path)
+
+        logger.info('Symbolic link "%s" successfully persisted' % abspath)
+        self._add_path_entry(abspath)
+
+    def _prepare_dir(self, abspath, persisted_path):
+        dir_path = os.path.dirname(persisted_path)
+        try:
+            os.makedirs(dir_path)
+        except OSError as ose:
+            if OSError.errno != errno.EEXIST:
+                logger.error('Failed to create the directories necessary to '
+                             'persist %s: %s' % (abspath, ose))
+                raise
+
+    def _persisted_path_entries(self):
+        with open(self.path_entries) as path_entries:
+            for entry in path_entries:
+                yield entry
+
+    def _add_path_entry(self, abspath):
+        matches = (entry for entry in self._persisted_path_entries if
+                   entry == abspath)
+        if any(matches):
+            pass  # Entry already present
+        else:
+            with open(self.path_entries, 'a') as path_entries:
+                print(abspath, file=path_entries)
 
     def unpersist(self, filename):
         """Remove the persistent version of a file and remove the bind mount


-- 
To view, visit http://gerrit.ovirt.org/29013
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ibcc52e9e5cd99bb7f342bb024d1aae12831ddc60
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-node
Gerrit-Branch: master
Gerrit-Owner: Antoni Segura Puimedon <asegurap at redhat.com>



More information about the node-patches mailing list