Merge remote-tracking branch 'woju/pull/21/head' into core3-devel
Conflicts: qubes/storage/__init__.py
This commit is contained in:
commit
1ff1ca37a1
@ -911,6 +911,7 @@ class Qubes(qubes.PropertyHolder):
|
||||
pool = self._get_pool(**kwargs)
|
||||
pool.setup()
|
||||
self.pools[name] = pool
|
||||
return pool
|
||||
|
||||
def remove_pool(self, name):
|
||||
""" Remove a storage pool from config file. """
|
||||
|
@ -42,6 +42,7 @@ STORAGE_ENTRY_POINT = 'qubes.storage'
|
||||
|
||||
|
||||
class StoragePoolException(qubes.exc.QubesException):
|
||||
''' A general storage exception '''
|
||||
pass
|
||||
|
||||
|
||||
@ -98,6 +99,9 @@ class Volume(object):
|
||||
def __hash__(self):
|
||||
return hash('%s:%s %s' % (self.pool, self.vid, self.volume_type))
|
||||
|
||||
def __str__(self):
|
||||
return "{!s}:{!s}".format(self.pool, self.vid)
|
||||
|
||||
|
||||
class Storage(object):
|
||||
''' Class for handling VM virtual disks.
|
||||
@ -198,7 +202,7 @@ class Storage(object):
|
||||
self.get_pool(volume).resize(volume, size)
|
||||
|
||||
def create(self, source_template=None):
|
||||
|
||||
''' Creates volumes on disk '''
|
||||
if source_template is None and hasattr(self.vm, 'template'):
|
||||
source_template = self.vm.template
|
||||
|
||||
@ -213,6 +217,7 @@ class Storage(object):
|
||||
os.umask(old_umask)
|
||||
|
||||
def clone(self, src_vm):
|
||||
''' Clone volumes from the specified vm '''
|
||||
self.vm.log.info('Creating directory: {0}'.format(self.vm.dir_path))
|
||||
if not os.path.exists(self.vm.dir_path):
|
||||
self.log.info('Creating directory: {0}'.format(self.vm.dir_path))
|
||||
@ -288,6 +293,7 @@ class Storage(object):
|
||||
return self.pools[volume.name]
|
||||
|
||||
def commit_template_changes(self):
|
||||
''' Makes changes to an 'origin' volume persistent '''
|
||||
for volume in self.vm.volumes.values():
|
||||
if volume.volume_type == 'origin':
|
||||
self.get_pool(volume).commit_template_changes(volume)
|
||||
@ -318,15 +324,25 @@ class Pool(object):
|
||||
private_img_size = qubes.config.defaults['private_img_size']
|
||||
root_img_size = qubes.config.defaults['root_img_size']
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.name == other.name
|
||||
|
||||
|
||||
def __neq__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
def __init__(self, name, **kwargs):
|
||||
super(Pool, self).__init__(**kwargs)
|
||||
self.name = name
|
||||
kwargs['name'] = self.name
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def __xml__(self):
|
||||
return lxml.etree.Element('pool', **self.config)
|
||||
|
||||
def create(self, volume, source_volume):
|
||||
def create(self, volume, source_volume=None):
|
||||
''' Create the given volume on disk or copy from provided
|
||||
`source_volume`.
|
||||
'''
|
||||
@ -351,6 +367,9 @@ class Pool(object):
|
||||
self.name)
|
||||
|
||||
def destroy(self):
|
||||
''' Called when removing the pool. Use this for implementation specific
|
||||
clean up.
|
||||
'''
|
||||
raise NotImplementedError("Pool %s has destroy() not implemented" %
|
||||
self.name)
|
||||
|
||||
@ -374,6 +393,9 @@ class Pool(object):
|
||||
self.name)
|
||||
|
||||
def setup(self):
|
||||
''' Called when adding a pool to the system. Use this for implementation
|
||||
specific set up.
|
||||
'''
|
||||
raise NotImplementedError("Pool %s has setup() not implemented" %
|
||||
self.name)
|
||||
|
||||
|
@ -91,7 +91,7 @@ class FilePool(Pool):
|
||||
''' Expands volume, throws
|
||||
:py:class:`qubst.storage.StoragePoolException` if given size is
|
||||
less than current_size
|
||||
'''
|
||||
''' # pylint: disable=no-self-use
|
||||
_type = volume.volume_type
|
||||
if _type not in ['origin', 'read-write', 'volatile']:
|
||||
raise StoragePoolException('Can not resize a %s volume %s' %
|
||||
@ -112,7 +112,18 @@ class FilePool(Pool):
|
||||
with open(path, 'a+b') as fd:
|
||||
fd.truncate(size)
|
||||
|
||||
self._resize_loop_device(path)
|
||||
p = subprocess.Popen(
|
||||
['sudo', 'losetup', '--associated', path],
|
||||
stdout=subprocess.PIPE)
|
||||
result = p.communicate()
|
||||
|
||||
m = re.match(r'^(/dev/loop\d+):\s', result[0])
|
||||
if m is not None:
|
||||
loop_dev = m.group(1)
|
||||
|
||||
# resize loop device
|
||||
subprocess.check_call(['sudo', 'losetup', '--set-capacity', loop_dev
|
||||
])
|
||||
|
||||
def remove(self, volume):
|
||||
if volume.volume_type in ['read-write', 'volatile']:
|
||||
@ -133,23 +144,6 @@ class FilePool(Pool):
|
||||
|
||||
return volume
|
||||
|
||||
@staticmethod
|
||||
def _resize_loop_device(path):
|
||||
''' Sets the loop device capacity '''
|
||||
# find loop device if any
|
||||
p = subprocess.Popen(
|
||||
['sudo', 'losetup', '--associated', path],
|
||||
stdout=subprocess.PIPE)
|
||||
result = p.communicate()
|
||||
|
||||
m = re.match(r'^(/dev/loop\d+):\s', result[0])
|
||||
if m is not None:
|
||||
loop_dev = m.group(1)
|
||||
|
||||
# resize loop device
|
||||
subprocess.check_call(['sudo', 'losetup', '--set-capacity',
|
||||
loop_dev])
|
||||
|
||||
def commit_template_changes(self, volume):
|
||||
if volume.volume_type != 'origin':
|
||||
return volume
|
||||
@ -175,7 +169,7 @@ class FilePool(Pool):
|
||||
|
||||
def start(self, volume):
|
||||
if volume.volume_type == 'volatile':
|
||||
self._reset_volume(volume)
|
||||
_reset_volume(volume)
|
||||
if volume.volume_type in ['origin', 'snapshot']:
|
||||
_check_path(volume.path_origin)
|
||||
_check_path(volume.path_cow)
|
||||
@ -187,18 +181,6 @@ class FilePool(Pool):
|
||||
def stop(self, volume):
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def _reset_volume(volume):
|
||||
''' Remove and recreate a volatile volume '''
|
||||
assert volume.volume_type == 'volatile', "Not a volatile volume"
|
||||
assert volume.size
|
||||
|
||||
_remove_if_exists(volume.path)
|
||||
|
||||
with open(volume.path, "w") as f_volatile:
|
||||
f_volatile.truncate(volume.size)
|
||||
return volume
|
||||
|
||||
def target_dir(self, vm):
|
||||
""" Returns the path to vmdir depending on the type of the VM.
|
||||
|
||||
@ -259,6 +241,7 @@ class FilePool(Pool):
|
||||
expected_origin_type
|
||||
|
||||
origin_pool = vm.app.get_pool(origin_vm.volume_config[name]['pool'])
|
||||
|
||||
assert isinstance(origin_pool,
|
||||
FilePool), 'Origin volume not a file volume'
|
||||
|
||||
@ -558,7 +541,7 @@ def copy_file(source, destination):
|
||||
|
||||
|
||||
def _remove_if_exists(path):
|
||||
''' Removes a path if it exist, silently succeeds if file does not exist '''
|
||||
''' Removes a file if it exist, silently succeeds if file does not exist '''
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
@ -567,3 +550,16 @@ def _check_path(path):
|
||||
''' Raise an StoragePoolException if ``path`` does not exist'''
|
||||
if not os.path.exists(path):
|
||||
raise StoragePoolException('Missing image file: %s' % path)
|
||||
|
||||
|
||||
def _reset_volume(volume):
|
||||
''' Remove and recreate a volatile volume '''
|
||||
assert volume.volume_type == 'volatile', "Not a volatile volume"
|
||||
|
||||
assert volume.size
|
||||
|
||||
_remove_if_exists(volume.path)
|
||||
|
||||
with open(volume.path, "w") as f_volatile:
|
||||
f_volatile.truncate(volume.size)
|
||||
return volume
|
||||
|
@ -63,7 +63,7 @@ class LinuxKernel(Pool):
|
||||
def clone(self, source, target):
|
||||
return target
|
||||
|
||||
def create(self, volume, source_volume):
|
||||
def create(self, volume, source_volume=None):
|
||||
return volume
|
||||
|
||||
def commit_template_changes(self, volume):
|
||||
|
Loading…
Reference in New Issue
Block a user