Implement partition mounts.

This solves quite a few challenges with mounting directories into root etc.
This commit is contained in:
Anders Ingemann 2013-11-27 18:06:45 +01:00 committed by Anders Ingemann
parent 970cbfccf2
commit 2af0968156
11 changed files with 65 additions and 97 deletions

View file

@ -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]

View file

@ -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')

View file

@ -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

View file

@ -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)

View file

@ -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,
]

View file

@ -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

View file

@ -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",

View file

@ -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)

View file

@ -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'

View file

@ -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)

View file

@ -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)