From 49b495138994991792c5fa23c856d7dc5c804447 Mon Sep 17 00:00:00 2001 From: Bahtiar `kalkin-` Gadimov Date: Fri, 15 Apr 2016 17:11:42 +0200 Subject: [PATCH] Storage move rename() logic to XenPool - Fix config renaming --- qubes/storage/__init__.py | 34 ++++++++++---------- qubes/storage/xen.py | 65 ++++++++++++++++++++++++++++++++++++++- qubes/vm/qubesvm.py | 12 ++++---- 3 files changed, 86 insertions(+), 25 deletions(-) diff --git a/qubes/storage/__init__.py b/qubes/storage/__init__.py index 308aaae8..a1dbb0f9 100644 --- a/qubes/storage/__init__.py +++ b/qubes/storage/__init__.py @@ -56,7 +56,11 @@ class Volume(object): script = None usage = 0 - def __init__(self, name=None, pool=None, volume_type=None, vid=None, + def __init__(self, + name=None, + pool=None, + volume_type=None, + vid=None, size=0): assert name and pool and volume_type self.name = str(name) @@ -167,23 +171,12 @@ class Storage(object): volume) self.vm.volumes[name] = volume - # TODO migrate this - @staticmethod - def rename(newpath, oldpath): - '''Move storage directory, most likely during domain's rename. - - .. note:: - The arguments are in different order than in :program:`cp` utility. - - .. versionchange:: 4.0 - This is now dummy method that just passes everything to - :py:func:`os.rename`. - - :param str newpath: New path - :param str oldpath: Old path - ''' - - os.rename(oldpath, newpath) + def rename(self, old_name, new_name): + ''' Notify the pools that the domain was renamed ''' + volumes = self.vm.volumes + for name, volume in volumes.items(): + pool = self.get_pool(volume) + volumes[name] = pool.rename(volume, old_name, new_name) def verify_files(self): '''Verify that the storage is sane. @@ -271,6 +264,11 @@ class Pool(object): raise NotImplementedError("Pool %s has remove() not implemented" % self.name) + def rename(self, volume, old_name, new_name): + ''' Called when the domain changes its name ''' + raise NotImplementedError("Pool %s has rename() not implemented" % + self.name) + def start(self, volume): ''' Do what ever is needed on start ''' raise NotImplementedError("Pool %s has start() not implemented" % diff --git a/qubes/storage/xen.py b/qubes/storage/xen.py index 7bb0dfb3..7af5ff63 100644 --- a/qubes/storage/xen.py +++ b/qubes/storage/xen.py @@ -114,6 +114,23 @@ class XenPool(Pool): _remove_if_exists(volume.vid) _remove_if_exists(volume.path_cow) + def rename(self, volume, old_name, new_name): + assert issubclass(volume.__class__, XenVolume) + old_dir = os.path.dirname(volume.path) + new_dir = os.path.join(os.path.dirname(old_dir), new_name) + + if not os.path.exists(new_dir): + os.makedirs(new_dir) + + if volume.volume_type == 'read-write': + volume.rename_target_dir(new_name, new_dir) + elif volume.volume_type == 'read-only': + volume.rename_target_dir(old_name, new_dir) + elif volume.volume_type in ['origin', 'volatile']: + volume.rename_target_dir(new_dir) + + return volume + def _resize_loop_device(self, path): # find loop device if any p = subprocess.Popen( @@ -275,6 +292,17 @@ class ReadWriteFile(SizeMixIn): self.path = os.path.join(self.target_dir, self.name + '.img') self.vid = self.path + def rename_target_dir(self, new_name, new_dir): + # :pylint: disable=unused-argument + old_path = self.path + file_name = os.path.basename(self.path) + new_path = os.path.join(new_dir, file_name) + + os.rename(old_path, new_path) + self.target_dir = new_dir + self.path = new_path + self.vid = self.path + class ReadOnlyFile(XenVolume): # :pylint: disable=missing-docstring @@ -285,6 +313,20 @@ class ReadOnlyFile(XenVolume): super(ReadOnlyFile, self).__init__(size=int(size), **kwargs) self.path = self.vid + def rename_target_dir(self, old_name, new_dir): + # only copy the read-only volume if it's "owned" by the current vm + # "owned" means that it's in a directory named the same as the vm + if os.path.basename(self.target_dir) == old_name: + file_name = os.path.basename(self.path) + new_path = os.path.join(new_dir, file_name) + old_path = self.path + + os.rename(old_path, new_path) + + self.target_dir = new_dir + self.path = new_path + self.vid = self.path + class OriginFile(SizeMixIn): # :pylint: disable=missing-docstring @@ -300,6 +342,19 @@ class OriginFile(SizeMixIn): def commit(self): raise NotImplementedError + def rename_target_dir(self, new_dir): + old_path_origin = self.path_origin + old_path_cow = self.path_cow + new_path_origin = os.path.join(new_dir, self.name + '.img') + new_path_cow = os.path.join(new_dir, self.name + '-cow.img') + os.rename(old_path_origin, new_path_origin) + os.rename(old_path_cow, new_path_cow) + self.target_dir = new_dir + self.path_origin = new_path_origin + self.path_cow = new_path_cow + self.path = '%s:%s' % (self.path_origin, self.path_cow) + self.vid = self.path_origin + @property def usage(self): result = 0 @@ -335,7 +390,15 @@ class VolatileFile(SizeMixIn): def __init__(self, **kwargs): super(VolatileFile, self).__init__(**kwargs) - self.path = os.path.join(self.target_dir, 'volatile.img') + self.path = os.path.join(self.target_dir, self.name + '.img') + self.vid = self.path + + def rename_target_dir(self, new_dir): + _remove_if_exists(self) + file_name = os.path.basename(self.path) + self.target_dir = new_dir + new_path = os.path.join(new_dir, file_name) + self.path = new_path self.vid = self.path diff --git a/qubes/vm/qubesvm.py b/qubes/vm/qubesvm.py index 7aad4ac8..4a77b181 100644 --- a/qubes/vm/qubesvm.py +++ b/qubes/vm/qubesvm.py @@ -566,18 +566,18 @@ class QubesVM(qubes.vm.mix.net.NetVMMixin, qubes.vm.BaseVM): self._qdb_connection.close() self._qdb_connection = None - self.storage.rename( - os.path.join(qubes.config.system_path['qubes_base_dir'], - self.dir_path_prefix, new_name), - os.path.join(qubes.config.system_path['qubes_base_dir'], - self.dir_path_prefix, old_name)) + self.storage.rename(old_name, new_name) + + prefix = os.path.join(qubes.config.system_path['qubes_base_dir'], self.dir_path_prefix) + old_config = os.path.join(prefix, old_name, old_name + '.conf') + new_config = os.path.join(prefix, new_name, new_name + '.conf') + os.rename(old_config, new_config) self._update_libvirt_domain() if self.autostart: self.autostart = self.autostart - @qubes.events.handler('property-pre-set:autostart') def on_property_pre_set_autostart(self, event, prop, name, value, oldvalue=None):