diff --git a/base/fs/partitions/abstract.py b/base/fs/partitions/abstract.py index bb2354c..b99a48f 100644 --- a/base/fs/partitions/abstract.py +++ b/base/fs/partitions/abstract.py @@ -1,4 +1,5 @@ from abc import ABCMeta +import os.path from common.tools import log_check_call from common.fsm_proxy import FSMProxy @@ -13,10 +14,32 @@ class AbstractPartition(FSMProxy): {'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'}, ] + class Mount(object): + def __init__(self, source, destination, opts): + self.source = source + self.destination = destination + self.opts = opts + + def mount(self, prefix): + mount_dir = os.path.join(prefix, self.destination) + if isinstance(self.source, AbstractPartition): + self.source.mount(mount_dir) + else: + log_check_call(['/bin/mount'] + self.opts + [self.source, mount_dir]) + self.mount_dir = mount_dir + + def unmount(self): + if isinstance(self.source, AbstractPartition): + self.source.unmount() + else: + log_check_call(['/bin/umount', self.mount_dir]) + del self.mount_dir + def __init__(self, size, filesystem): self.size = size self.filesystem = filesystem self.device_path = None + self.mounts = {} cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}} super(AbstractPartition, self).__init__(cfg) @@ -36,6 +59,23 @@ class AbstractPartition(FSMProxy): log_check_call(['/bin/mount', '--types', self.filesystem, self.device_path, e.destination]) self.mount_dir = e.destination + def _after_mount(self, e): + for destination in sorted(self.mounts.iterkeys(), key=len): + self.mounts[destination].mount(self.mount_dir) + def _before_unmount(self, e): + for destination in sorted(self.mounts.iterkeys(), key=len, reverse=True): + self.mounts[destination].unmount() log_check_call(['/bin/umount', self.mount_dir]) del self.mount_dir + + def add_mount(self, source, destination, opts=[]): + mount = self.Mount(source, destination, opts) + if self.fsm.current == 'mounted': + mount.mount(self.mount_dir) + self.mounts[destination] = mount + + def remove_mount(self, destination): + if self.fsm.current == 'mounted': + self.mounts[destination].unmount() + del self.mounts[destination] diff --git a/base/fs/volume.py b/base/fs/volume.py index e83ad5b..aba03f9 100644 --- a/base/fs/volume.py +++ b/base/fs/volume.py @@ -17,7 +17,6 @@ class Volume(FSMProxy): def __init__(self, partition_map): self.device_path = None - self.specials_mounted = False self.partition_map = partition_map self.size = self.partition_map.get_total_size() @@ -34,31 +33,6 @@ class Volume(FSMProxy): if isinstance(self.partition_map, NoPartitions): self.partition_map.root.create() - def can_mount_specials(self): - return self.fsm.current == 'attached' - - def mount_specials(self): - if self.specials_mounted: - raise VolumeError('The special devices are already mounted') - root = self.partition_map.root.mount_dir - log_check_call(['/bin/mount', '--bind', '/dev', '{root}/dev'.format(root=root)]) - log_check_call(['/usr/sbin/chroot', root, '/bin/mount', '--types', 'proc', 'none', '/proc']) - log_check_call(['/usr/sbin/chroot', root, '/bin/mount', '--types', 'sysfs', 'none', '/sys']) - log_check_call(['/usr/sbin/chroot', root, '/bin/mount', '--types', 'devpts', 'none', '/dev/pts']) - self.specials_mounted = True - - def unmount_specials(self): - if not self.specials_mounted: - raise VolumeError('The special devices are not mounted') - root = self.partition_map.root.mount_dir - log_check_call(['/usr/sbin/chroot', root, '/bin/umount', '/dev/pts']) - log_check_call(['/usr/sbin/chroot', root, '/bin/umount', '/sys']) - log_check_call(['/usr/sbin/chroot', root, '/bin/umount', '/proc']) - log_check_call(['/bin/umount', '{root}/dev'.format(root=root)]) - self.specials_mounted = False - def _check_blocking(self, e): if self.partition_map.is_blocking(): raise VolumeError('The partitionmap prevents the detach procedure') - if self.specials_mounted: - raise VolumeError('The special devices are mounted and prevent the detaching procedure') diff --git a/common/fs/__init__.py b/common/fs/__init__.py index 3cde7cf..6d26291 100644 --- a/common/fs/__init__.py +++ b/common/fs/__init__.py @@ -20,10 +20,6 @@ def remount(volume, fn): from base.fs.partitionmaps.none import NoPartitions p_map = volume.partition_map - volume.unmount_specials() - if hasattr(p_map, 'boot'): - boot_dir = p_map.boot.mount_dir - p_map.boot.unmount() root_dir = p_map.root.mount_dir p_map.root.unmount() if not isinstance(p_map, NoPartitions): @@ -33,7 +29,4 @@ def remount(volume, fn): else: result = fn() p_map.root.mount(root_dir) - if hasattr(p_map, 'boot'): - p_map.boot.mount(boot_dir) - volume.mount_specials() return result diff --git a/common/fs/loopbackvolume.py b/common/fs/loopbackvolume.py index 81269b9..f20afdc 100644 --- a/common/fs/loopbackvolume.py +++ b/common/fs/loopbackvolume.py @@ -19,9 +19,6 @@ class LoopbackVolume(Volume): extension = 'raw' - def can_mount_specials(self): - return self.fsm.current in ['attached', 'linked'] - def create(self, image_path): self.fsm.create(image_path=image_path) diff --git a/common/task_sets.py b/common/task_sets.py index 07e7a31..7f5d4fb 100644 --- a/common/task_sets.py +++ b/common/task_sets.py @@ -31,13 +31,11 @@ partitioning_set = [partitioning.PartitionVolume, boot_partition_set = [filesystem.CreateBootMountDir, filesystem.MountBoot, - filesystem.UnmountBoot, ] mounting_set = [filesystem.CreateMountDir, filesystem.MountRoot, filesystem.MountSpecials, - filesystem.UnmountSpecials, filesystem.UnmountRoot, filesystem.DeleteMountDir, ] diff --git a/common/tasks/filesystem.py b/common/tasks/filesystem.py index 063fb82..457e656 100644 --- a/common/tasks/filesystem.py +++ b/common/tasks/filesystem.py @@ -55,25 +55,24 @@ class MountRoot(Task): info.volume.partition_map.root.mount(info.root) -class MountBoot(Task): - description = 'Mounting the boot partition' - phase = phases.volume_mounting - predecessors = [MountRoot] - - def run(self, info): - info.volume.partition_map.boot.mount(info.boot_dir) - - class CreateBootMountDir(Task): description = 'Creating mountpoint for the boot partition' phase = phases.volume_mounting - successors = [MountBoot] predecessors = [MountRoot] def run(self, info): - import os - info.boot_dir = os.path.join(info.root, 'boot') - os.makedirs(info.boot_dir) + import os.path + os.makedirs(os.path.join(info.root, 'boot')) + + +class MountBoot(Task): + description = 'Mounting the boot partition' + phase = phases.volume_mounting + predecessors = [CreateBootMountDir] + + def run(self, info): + p_map = info.volume.partition_map + p_map.root.add_mount(p_map.boot, 'boot') class MountSpecials(Task): @@ -82,7 +81,11 @@ class MountSpecials(Task): predecessors = [Bootstrap] def run(self, info): - info.volume.mount_specials() + root = info.volume.partition_map.root + root.add_mount('/dev', 'dev', ['--bind']) + root.add_mount('none', 'proc', ['--types', 'proc']) + root.add_mount('none', 'sys', ['--types', 'sysfs']) + root.add_mount('none', 'dev/pts', ['--types', 'devpts']) class UnmountRoot(Task): @@ -94,24 +97,6 @@ class UnmountRoot(Task): info.volume.partition_map.root.unmount() -class UnmountBoot(Task): - description = 'Unmounting the boot partition' - phase = phases.volume_unmounting - successors = [UnmountRoot] - - def run(self, info): - info.volume.partition_map.boot.unmount() - - -class UnmountSpecials(Task): - description = 'Unmunting special block devices' - phase = phases.volume_unmounting - successors = [UnmountRoot] - - def run(self, info): - info.volume.unmount_specials() - - class DeleteMountDir(Task): description = 'Deleting mountpoint for the bootstrap volume' phase = phases.volume_unmounting diff --git a/manifests/virtualbox.manifest.json b/manifests/virtualbox.manifest.json index 9541af9..cbd009b 100644 --- a/manifests/virtualbox.manifest.json +++ b/manifests/virtualbox.manifest.json @@ -1,18 +1,18 @@ { - "provider" : "virtualbox", + "provider": "virtualbox", "bootstrapper": { "workspace": "/target" }, "image": { - "name" : "debian-{release}-{architecture}-{%y}{%m}{%d}", + "name": "debian-{release}-{architecture}-{%y}{%m}{%d}", "description": "Debian {release} {architecture}" }, "system": { - "release" : "wheezy", + "release": "wheezy", "architecture": "amd64", - "timezone" : "UTC", - "locale" : "en_US", - "charmap" : "UTF-8" + "timezone": "UTC", + "locale": "en_US", + "charmap": "UTF-8" }, "volume": { "backing": "vdi", diff --git a/plugins/prebootstrapped/__init__.py b/plugins/prebootstrapped/__init__.py index 35e7518..7988778 100644 --- a/plugins/prebootstrapped/__init__.py +++ b/plugins/prebootstrapped/__init__.py @@ -2,7 +2,6 @@ from tasks import Snapshot from tasks import CopyImage from tasks import CreateFromSnapshot from tasks import CreateFromImage -from tasks import SetBootMountDir from providers.ec2.tasks import ebs from common.tasks import loopback from common.tasks import volume @@ -27,16 +26,12 @@ def tasks(tasklist, manifest): if 'snapshot' in settings and settings['snapshot'] is not None: tasklist.add(CreateFromSnapshot) tasklist.remove(*skip_tasks) - if 'boot' in manifest.volume['partitions']: - tasklist.add(SetBootMountDir) else: tasklist.add(Snapshot) else: if 'image' in settings and settings['image'] is not None: tasklist.add(CreateFromImage) tasklist.remove(*skip_tasks) - if 'boot' in manifest.volume['partitions']: - tasklist.add(SetBootMountDir) else: tasklist.add(CopyImage) diff --git a/plugins/prebootstrapped/tasks.py b/plugins/prebootstrapped/tasks.py index 7286293..374e516 100644 --- a/plugins/prebootstrapped/tasks.py +++ b/plugins/prebootstrapped/tasks.py @@ -14,7 +14,7 @@ log = logging.getLogger(__name__) class Snapshot(Task): description = 'Creating a snapshot of the bootstrapped volume' phase = phases.os_installation - predecessors = [bootstrap.Bootstrap, filesystem.MountSpecials] + predecessors = [bootstrap.Bootstrap] def run(self, info): def mk_snapshot(): @@ -45,7 +45,7 @@ class CreateFromSnapshot(Task): class CopyImage(Task): description = 'Creating a snapshot of the bootstrapped volume' phase = phases.os_installation - predecessors = [bootstrap.Bootstrap, filesystem.MountSpecials] + predecessors = [bootstrap.Bootstrap] def run(self, info): loopback_backup_name = 'volume-{id:x}.{ext}.backup'.format(id=info.run_id, ext=info.volume.extension) @@ -71,16 +71,6 @@ class CreateFromImage(Task): set_fs_states(info.volume) -class SetBootMountDir(Task): - description = 'Setting mountpoint for the boot partition' - phase = phases.volume_mounting - predecessors = [filesystem.MountRoot] - successors = [filesystem.MountBoot] - - def run(self, info): - info.boot_dir = os.path.join(info.root, 'boot') - - def set_fs_states(volume): volume.fsm.current = 'detached' diff --git a/providers/ec2/__init__.py b/providers/ec2/__init__.py index 7ad81d7..0c14415 100644 --- a/providers/ec2/__init__.py +++ b/providers/ec2/__init__.py @@ -107,10 +107,8 @@ def rollback_tasks(tasklist, tasks_completed, manifest): counter_task(partitioning.MapPartitions, partitioning.UnmapPartitions) counter_task(common_filesystem.CreateMountDir, common_filesystem.DeleteMountDir) - counter_task(common_filesystem.MountSpecials, common_filesystem.UnmountSpecials) counter_task(common_filesystem.MountRoot, common_filesystem.UnmountRoot) - counter_task(common_filesystem.MountBoot, common_filesystem.UnmountBoot) counter_task(volume_tasks.Attach, volume_tasks.Detach) counter_task(workspace.CreateWorkspace, workspace.DeleteWorkspace) counter_task(ami.BundleImage, ami.RemoveBundle) diff --git a/providers/virtualbox/__init__.py b/providers/virtualbox/__init__.py index 8e31b1b..dc0dc8f 100644 --- a/providers/virtualbox/__init__.py +++ b/providers/virtualbox/__init__.py @@ -74,7 +74,5 @@ def rollback_tasks(tasklist, tasks_completed, manifest): counter_task(filesystem.CreateMountDir, filesystem.DeleteMountDir) counter_task(partitioning.MapPartitions, partitioning.UnmapPartitions) counter_task(filesystem.MountRoot, filesystem.UnmountRoot) - counter_task(filesystem.MountBoot, filesystem.UnmountBoot) - counter_task(filesystem.MountSpecials, filesystem.UnmountSpecials) counter_task(volume_tasks.Attach, volume_tasks.Detach) counter_task(workspace.CreateWorkspace, workspace.DeleteWorkspace)