mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +00:00
VDI images working now
*Helpful error messages included
This commit is contained in:
parent
6fb60a33f0
commit
efecc15382
6 changed files with 81 additions and 15 deletions
|
@ -6,6 +6,7 @@ class NoPartitions(object):
|
||||||
def __init__(self, data):
|
def __init__(self, data):
|
||||||
root = data['root']
|
root = data['root']
|
||||||
self.root = SinglePartition(root['size'], root['filesystem'])
|
self.root = SinglePartition(root['size'], root['filesystem'])
|
||||||
|
self.partitions = [self.root]
|
||||||
self.mount_points = [('/', self.root)]
|
self.mount_points = [('/', self.root)]
|
||||||
|
|
||||||
def get_total_size(self):
|
def get_total_size(self):
|
||||||
|
|
|
@ -1,11 +1,16 @@
|
||||||
|
|
||||||
|
|
||||||
def get_major_minor_dev_num(device_name):
|
def get_partitions():
|
||||||
import re
|
import re
|
||||||
regexp = re.compile('^ *(?P<major>\d+) *(?P<minor>\d+) *(?P<num_blks>\d+) {device_name}$'
|
regexp = re.compile('^ *(?P<major>\d+) *(?P<minor>\d+) *(?P<num_blks>\d+) (?P<dev_name>\S+)$')
|
||||||
.format(device_name=device_name))
|
matches = {}
|
||||||
with open('/proc/partitions') as partitions:
|
path = '/proc/partitions'
|
||||||
|
with open(path) as partitions:
|
||||||
|
next(partitions)
|
||||||
|
next(partitions)
|
||||||
for line in partitions:
|
for line in partitions:
|
||||||
match = regexp.match(line)
|
match = regexp.match(line)
|
||||||
if match is not None:
|
if match is None:
|
||||||
return match.group('major'), match.group('minor')
|
raise RuntimeError('Unable to parse {line} in {path}'.format(line=line, path=path))
|
||||||
|
matches[match.group('dev_name')] = match.groupdict()
|
||||||
|
return matches
|
||||||
|
|
|
@ -49,15 +49,17 @@ class LoopbackVolume(Volume):
|
||||||
|
|
||||||
def _link_dm_node(self, e):
|
def _link_dm_node(self, e):
|
||||||
import os.path
|
import os.path
|
||||||
|
from . import get_partitions
|
||||||
|
proc_partitions = get_partitions()
|
||||||
loop_device_name = os.path.basename(self.loop_device_path)
|
loop_device_name = os.path.basename(self.loop_device_path)
|
||||||
from . import get_major_minor_dev_num
|
loop_device_partition = proc_partitions[loop_device_name]
|
||||||
major, minor = get_major_minor_dev_num(loop_device_name)
|
|
||||||
sectors = self.size*1024*1024/512
|
sectors = self.size*1024*1024/512
|
||||||
table = ('{log_start_sec} {sectors} linear {major}:{minor} {start_sec}'
|
table = ('{log_start_sec} {sectors} linear {major}:{minor} {start_sec}'
|
||||||
.format(log_start_sec=0,
|
.format(log_start_sec=0,
|
||||||
sectors=sectors,
|
sectors=sectors,
|
||||||
major=major,
|
major=loop_device_partition['major'],
|
||||||
minor=minor,
|
minor=loop_device_partition['minor'],
|
||||||
start_sec=0))
|
start_sec=0))
|
||||||
import string
|
import string
|
||||||
import os.path
|
import os.path
|
||||||
|
|
|
@ -64,15 +64,15 @@ class MountBoot(Task):
|
||||||
|
|
||||||
|
|
||||||
class CreateBootMountDir(Task):
|
class CreateBootMountDir(Task):
|
||||||
description = 'Creating mountpoint boot partition'
|
description = 'Creating mountpoint for the boot partition'
|
||||||
phase = phases.volume_mounting
|
phase = phases.volume_mounting
|
||||||
after = [MountRoot]
|
after = [MountRoot]
|
||||||
before = [MountBoot]
|
before = [MountBoot]
|
||||||
|
|
||||||
def run(self, info):
|
def run(self, info):
|
||||||
import os
|
import os
|
||||||
info.boot = os.path.join(info.root, 'boot')
|
boot_dir = os.path.join(info.root, 'boot')
|
||||||
os.makedirs()
|
os.makedirs(boot_dir)
|
||||||
|
|
||||||
|
|
||||||
class MountSpecials(Task):
|
class MountSpecials(Task):
|
||||||
|
|
|
@ -91,7 +91,9 @@ def tasks(tasklist, manifest):
|
||||||
break
|
break
|
||||||
|
|
||||||
if 'boot' in manifest.volume['partitions']:
|
if 'boot' in manifest.volume['partitions']:
|
||||||
tasklist.add(filesystem.MountBoot(), filesystem.UnmountBoot())
|
tasklist.add(filesystem.CreateBootMountDir(),
|
||||||
|
filesystem.MountBoot(),
|
||||||
|
filesystem.UnmountBoot())
|
||||||
|
|
||||||
|
|
||||||
def rollback_tasks(tasklist, tasks_completed, manifest):
|
def rollback_tasks(tasklist, tasks_completed, manifest):
|
||||||
|
@ -105,7 +107,7 @@ def rollback_tasks(tasklist, tasks_completed, manifest):
|
||||||
counter_task(filesystem.CreateMountDir, filesystem.DeleteMountDir)
|
counter_task(filesystem.CreateMountDir, filesystem.DeleteMountDir)
|
||||||
counter_task(partitioning.MapPartitions, partitioning.UnmapPartitions)
|
counter_task(partitioning.MapPartitions, partitioning.UnmapPartitions)
|
||||||
counter_task(filesystem.MountRoot, filesystem.UnmountRoot)
|
counter_task(filesystem.MountRoot, filesystem.UnmountRoot)
|
||||||
counter_task(filesystem.MountSpecials, filesystem.UnmountSpecials)
|
|
||||||
counter_task(filesystem.MountBoot, filesystem.UnmountBoot)
|
counter_task(filesystem.MountBoot, filesystem.UnmountBoot)
|
||||||
|
counter_task(filesystem.MountSpecials, filesystem.UnmountSpecials)
|
||||||
counter_task(volume_tasks.Attach, volume_tasks.Detach)
|
counter_task(volume_tasks.Attach, volume_tasks.Detach)
|
||||||
counter_task(workspace.CreateWorkspace, workspace.DeleteWorkspace)
|
counter_task(workspace.CreateWorkspace, workspace.DeleteWorkspace)
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from common.fs.loopbackvolume import LoopbackVolume
|
from common.fs.loopbackvolume import LoopbackVolume
|
||||||
|
from base.fs.exceptions import VolumeError
|
||||||
from common.tools import log_check_call
|
from common.tools import log_check_call
|
||||||
|
from common.fs import get_partitions
|
||||||
|
|
||||||
|
|
||||||
class VirtualBoxVolume(LoopbackVolume):
|
class VirtualBoxVolume(LoopbackVolume):
|
||||||
|
@ -9,3 +11,57 @@ class VirtualBoxVolume(LoopbackVolume):
|
||||||
def _create(self, e):
|
def _create(self, e):
|
||||||
self.image_path = e.image_path
|
self.image_path = e.image_path
|
||||||
log_check_call(['/usr/bin/qemu-img', 'create', '-f', 'vdi', self.image_path, str(self.size) + 'M'])
|
log_check_call(['/usr/bin/qemu-img', 'create', '-f', 'vdi', self.image_path, str(self.size) + 'M'])
|
||||||
|
|
||||||
|
def _attach(self, e):
|
||||||
|
num_partitions = len(self.partition_map.partitions)
|
||||||
|
if not self._module_loaded('nbd'):
|
||||||
|
msg = ('The kernel module `nbd\' must be loaded '
|
||||||
|
'(`modprobe nbd max_part={num_partitions}\') to attach .vdi images'
|
||||||
|
.format(num_partitions=num_partitions))
|
||||||
|
raise VolumeError(msg)
|
||||||
|
nbd_max_part = int(self._module_param('nbd', 'max_part'))
|
||||||
|
if nbd_max_part < num_partitions:
|
||||||
|
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)
|
||||||
|
self.loop_device_path = self._find_free_nbd_device()
|
||||||
|
log_check_call(['/usr/bin/qemu-nbd', '--connect', self.loop_device_path, self.image_path])
|
||||||
|
self.device_path = self.loop_device_path
|
||||||
|
|
||||||
|
def _detach(self, e):
|
||||||
|
log_check_call(['/usr/bin/qemu-nbd', '--disconnect', self.loop_device_path])
|
||||||
|
del self.loop_device_path
|
||||||
|
del self.device_path
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
def _module_param(self, module, param):
|
||||||
|
import os.path
|
||||||
|
param_path = os.path.join('/sys/module', module, 'parameters', param)
|
||||||
|
with open(param_path) as param:
|
||||||
|
return param.read().strip()
|
||||||
|
|
||||||
|
# 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()
|
||||||
|
|
||||||
|
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.')
|
||||||
|
|
Loading…
Add table
Reference in a new issue