2018-02-12 04:17:53 +00:00
|
|
|
from .loopbackvolume import LoopbackVolume
|
2014-03-23 23:12:07 +01:00
|
|
|
from bootstrapvz.base.fs.exceptions import VolumeError
|
|
|
|
from ..tools import log_check_call
|
|
|
|
from . import get_partitions
|
2013-09-15 13:19:45 +02:00
|
|
|
|
|
|
|
|
2013-12-28 14:01:34 +01:00
|
|
|
class QEMUVolume(LoopbackVolume):
|
2013-12-15 00:51:51 +01:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _before_create(self, e):
|
|
|
|
self.image_path = e.image_path
|
|
|
|
vol_size = str(self.size.bytes.get_qty_in('MiB')) + 'M'
|
|
|
|
log_check_call(['qemu-img', 'create', '-f', self.qemu_format, self.image_path, vol_size])
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _check_nbd_module(self):
|
|
|
|
from bootstrapvz.base.fs.partitionmaps.none import NoPartitions
|
|
|
|
if isinstance(self.partition_map, NoPartitions):
|
|
|
|
if not self._module_loaded('nbd'):
|
|
|
|
msg = ('The kernel module `nbd\' must be loaded '
|
|
|
|
'(`modprobe nbd\') to attach .{extension} images'
|
|
|
|
.format(extension=self.extension))
|
|
|
|
raise VolumeError(msg)
|
|
|
|
else:
|
|
|
|
num_partitions = len(self.partition_map.partitions)
|
|
|
|
if not self._module_loaded('nbd'):
|
|
|
|
msg = ('The kernel module `nbd\' must be loaded '
|
|
|
|
'(run `modprobe nbd max_part={num_partitions}\') '
|
|
|
|
'to attach .{extension} images'
|
|
|
|
.format(num_partitions=num_partitions, extension=self.extension))
|
|
|
|
raise VolumeError(msg)
|
|
|
|
nbd_max_part = int(self._module_param('nbd', 'max_part'))
|
|
|
|
if nbd_max_part < num_partitions:
|
|
|
|
# Found here: http://bethesignal.org/blog/2011/01/05/how-to-mount-virtualbox-vdi-image/
|
|
|
|
msg = ('The kernel module `nbd\' was loaded with the max_part '
|
|
|
|
'parameter set to {max_part}, which is below '
|
|
|
|
'the amount of partitions for this volume ({num_partitions}). '
|
|
|
|
'Reload the nbd kernel module with max_part set to at least {num_partitions} '
|
|
|
|
'(`rmmod nbd; modprobe nbd max_part={num_partitions}\').'
|
|
|
|
.format(max_part=nbd_max_part, num_partitions=num_partitions))
|
|
|
|
raise VolumeError(msg)
|
2013-10-04 20:31:51 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _before_attach(self, e):
|
|
|
|
self._check_nbd_module()
|
|
|
|
self.loop_device_path = self._find_free_nbd_device()
|
|
|
|
log_check_call(['qemu-nbd', '--connect', self.loop_device_path, self.image_path])
|
|
|
|
self.device_path = self.loop_device_path
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _before_detach(self, e):
|
|
|
|
log_check_call(['qemu-nbd', '--disconnect', self.loop_device_path])
|
|
|
|
del self.loop_device_path
|
|
|
|
self.device_path = None
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _module_loaded(self, module):
|
|
|
|
import re
|
|
|
|
regexp = re.compile('^{module} +'.format(module=module))
|
|
|
|
with open('/proc/modules') as loaded_modules:
|
|
|
|
for line in loaded_modules:
|
|
|
|
match = regexp.match(line)
|
|
|
|
if match is not None:
|
|
|
|
return True
|
|
|
|
return False
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _module_param(self, module, param):
|
|
|
|
import os.path
|
|
|
|
param_path = os.path.join('/sys/module', module, 'parameters', param)
|
2018-02-25 08:20:13 +00:00
|
|
|
with open(param_path) as param_file:
|
|
|
|
return param_file.read().strip()
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
# From http://lists.gnu.org/archive/html/qemu-devel/2011-11/msg02201.html
|
|
|
|
# Apparently it's not in the current qemu-nbd shipped with wheezy
|
|
|
|
def _is_nbd_used(self, device_name):
|
|
|
|
return device_name in get_partitions()
|
2013-09-15 18:26:22 +02:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def _find_free_nbd_device(self):
|
|
|
|
import os.path
|
|
|
|
for i in xrange(0, 15):
|
|
|
|
device_name = 'nbd' + str(i)
|
|
|
|
if not self._is_nbd_used(device_name):
|
|
|
|
return os.path.join('/dev', device_name)
|
|
|
|
raise VolumeError('Unable to find free nbd device.')
|
2014-12-19 01:25:38 +01:00
|
|
|
|
2016-06-04 11:35:59 +02:00
|
|
|
def __setstate__(self, state):
|
|
|
|
for key in state:
|
|
|
|
self.__dict__[key] = state[key]
|