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 = self._get_pool(**kwargs)
|
||||||
pool.setup()
|
pool.setup()
|
||||||
self.pools[name] = pool
|
self.pools[name] = pool
|
||||||
|
return pool
|
||||||
|
|
||||||
def remove_pool(self, name):
|
def remove_pool(self, name):
|
||||||
""" Remove a storage pool from config file. """
|
""" Remove a storage pool from config file. """
|
||||||
|
@ -42,6 +42,7 @@ STORAGE_ENTRY_POINT = 'qubes.storage'
|
|||||||
|
|
||||||
|
|
||||||
class StoragePoolException(qubes.exc.QubesException):
|
class StoragePoolException(qubes.exc.QubesException):
|
||||||
|
''' A general storage exception '''
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@ -98,6 +99,9 @@ class Volume(object):
|
|||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
return hash('%s:%s %s' % (self.pool, self.vid, self.volume_type))
|
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 Storage(object):
|
||||||
''' Class for handling VM virtual disks.
|
''' Class for handling VM virtual disks.
|
||||||
@ -198,7 +202,7 @@ class Storage(object):
|
|||||||
self.get_pool(volume).resize(volume, size)
|
self.get_pool(volume).resize(volume, size)
|
||||||
|
|
||||||
def create(self, source_template=None):
|
def create(self, source_template=None):
|
||||||
|
''' Creates volumes on disk '''
|
||||||
if source_template is None and hasattr(self.vm, 'template'):
|
if source_template is None and hasattr(self.vm, 'template'):
|
||||||
source_template = self.vm.template
|
source_template = self.vm.template
|
||||||
|
|
||||||
@ -213,6 +217,7 @@ class Storage(object):
|
|||||||
os.umask(old_umask)
|
os.umask(old_umask)
|
||||||
|
|
||||||
def clone(self, src_vm):
|
def clone(self, src_vm):
|
||||||
|
''' Clone volumes from the specified vm '''
|
||||||
self.vm.log.info('Creating directory: {0}'.format(self.vm.dir_path))
|
self.vm.log.info('Creating directory: {0}'.format(self.vm.dir_path))
|
||||||
if not os.path.exists(self.vm.dir_path):
|
if not os.path.exists(self.vm.dir_path):
|
||||||
self.log.info('Creating directory: {0}'.format(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]
|
return self.pools[volume.name]
|
||||||
|
|
||||||
def commit_template_changes(self):
|
def commit_template_changes(self):
|
||||||
|
''' Makes changes to an 'origin' volume persistent '''
|
||||||
for volume in self.vm.volumes.values():
|
for volume in self.vm.volumes.values():
|
||||||
if volume.volume_type == 'origin':
|
if volume.volume_type == 'origin':
|
||||||
self.get_pool(volume).commit_template_changes(volume)
|
self.get_pool(volume).commit_template_changes(volume)
|
||||||
@ -318,15 +324,25 @@ class Pool(object):
|
|||||||
private_img_size = qubes.config.defaults['private_img_size']
|
private_img_size = qubes.config.defaults['private_img_size']
|
||||||
root_img_size = qubes.config.defaults['root_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):
|
def __init__(self, name, **kwargs):
|
||||||
super(Pool, self).__init__(**kwargs)
|
super(Pool, self).__init__(**kwargs)
|
||||||
self.name = name
|
self.name = name
|
||||||
kwargs['name'] = self.name
|
kwargs['name'] = self.name
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
def __xml__(self):
|
def __xml__(self):
|
||||||
return lxml.etree.Element('pool', **self.config)
|
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
|
''' Create the given volume on disk or copy from provided
|
||||||
`source_volume`.
|
`source_volume`.
|
||||||
'''
|
'''
|
||||||
@ -351,6 +367,9 @@ class Pool(object):
|
|||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
|
''' Called when removing the pool. Use this for implementation specific
|
||||||
|
clean up.
|
||||||
|
'''
|
||||||
raise NotImplementedError("Pool %s has destroy() not implemented" %
|
raise NotImplementedError("Pool %s has destroy() not implemented" %
|
||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
@ -374,6 +393,9 @@ class Pool(object):
|
|||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
def setup(self):
|
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" %
|
raise NotImplementedError("Pool %s has setup() not implemented" %
|
||||||
self.name)
|
self.name)
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ class FilePool(Pool):
|
|||||||
''' Expands volume, throws
|
''' Expands volume, throws
|
||||||
:py:class:`qubst.storage.StoragePoolException` if given size is
|
:py:class:`qubst.storage.StoragePoolException` if given size is
|
||||||
less than current_size
|
less than current_size
|
||||||
'''
|
''' # pylint: disable=no-self-use
|
||||||
_type = volume.volume_type
|
_type = volume.volume_type
|
||||||
if _type not in ['origin', 'read-write', 'volatile']:
|
if _type not in ['origin', 'read-write', 'volatile']:
|
||||||
raise StoragePoolException('Can not resize a %s volume %s' %
|
raise StoragePoolException('Can not resize a %s volume %s' %
|
||||||
@ -112,7 +112,18 @@ class FilePool(Pool):
|
|||||||
with open(path, 'a+b') as fd:
|
with open(path, 'a+b') as fd:
|
||||||
fd.truncate(size)
|
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):
|
def remove(self, volume):
|
||||||
if volume.volume_type in ['read-write', 'volatile']:
|
if volume.volume_type in ['read-write', 'volatile']:
|
||||||
@ -133,23 +144,6 @@ class FilePool(Pool):
|
|||||||
|
|
||||||
return volume
|
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):
|
def commit_template_changes(self, volume):
|
||||||
if volume.volume_type != 'origin':
|
if volume.volume_type != 'origin':
|
||||||
return volume
|
return volume
|
||||||
@ -175,7 +169,7 @@ class FilePool(Pool):
|
|||||||
|
|
||||||
def start(self, volume):
|
def start(self, volume):
|
||||||
if volume.volume_type == 'volatile':
|
if volume.volume_type == 'volatile':
|
||||||
self._reset_volume(volume)
|
_reset_volume(volume)
|
||||||
if volume.volume_type in ['origin', 'snapshot']:
|
if volume.volume_type in ['origin', 'snapshot']:
|
||||||
_check_path(volume.path_origin)
|
_check_path(volume.path_origin)
|
||||||
_check_path(volume.path_cow)
|
_check_path(volume.path_cow)
|
||||||
@ -187,18 +181,6 @@ class FilePool(Pool):
|
|||||||
def stop(self, volume):
|
def stop(self, volume):
|
||||||
pass
|
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):
|
def target_dir(self, vm):
|
||||||
""" Returns the path to vmdir depending on the type of the VM.
|
""" Returns the path to vmdir depending on the type of the VM.
|
||||||
|
|
||||||
@ -259,6 +241,7 @@ class FilePool(Pool):
|
|||||||
expected_origin_type
|
expected_origin_type
|
||||||
|
|
||||||
origin_pool = vm.app.get_pool(origin_vm.volume_config[name]['pool'])
|
origin_pool = vm.app.get_pool(origin_vm.volume_config[name]['pool'])
|
||||||
|
|
||||||
assert isinstance(origin_pool,
|
assert isinstance(origin_pool,
|
||||||
FilePool), 'Origin volume not a file volume'
|
FilePool), 'Origin volume not a file volume'
|
||||||
|
|
||||||
@ -558,7 +541,7 @@ def copy_file(source, destination):
|
|||||||
|
|
||||||
|
|
||||||
def _remove_if_exists(path):
|
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):
|
if os.path.exists(path):
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
|
|
||||||
@ -567,3 +550,16 @@ def _check_path(path):
|
|||||||
''' Raise an StoragePoolException if ``path`` does not exist'''
|
''' Raise an StoragePoolException if ``path`` does not exist'''
|
||||||
if not os.path.exists(path):
|
if not os.path.exists(path):
|
||||||
raise StoragePoolException('Missing image file: %s' % 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):
|
def clone(self, source, target):
|
||||||
return target
|
return target
|
||||||
|
|
||||||
def create(self, volume, source_volume):
|
def create(self, volume, source_volume=None):
|
||||||
return volume
|
return volume
|
||||||
|
|
||||||
def commit_template_changes(self, volume):
|
def commit_template_changes(self, volume):
|
||||||
|
Loading…
Reference in New Issue
Block a user