diff --git a/base/fs/partitionmaps/abstract.py b/base/fs/partitionmaps/abstract.py index 167ddea..5871027 100644 --- a/base/fs/partitionmaps/abstract.py +++ b/base/fs/partitionmaps/abstract.py @@ -1,25 +1,41 @@ from abc import ABCMeta from abc import abstractmethod from common.tools import log_check_call +from common.fsm_proxy import FSMProxy from ..exceptions import PartitionError -class AbstractPartitionMap(object): +class AbstractPartitionMap(FSMProxy): __metaclass__ = ABCMeta - @abstractmethod - def __init__(self, data): - pass + events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'unmapped'}, + {'name': 'map', 'src': 'unmapped', 'dst': 'mapped'}, + {'name': 'unmap', 'src': 'mapped', 'dst': 'unmapped'}, + ] + + def __init__(self): + cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}} + super(AbstractPartitionMap, self).__init__(cfg) + + def is_blocking(self): + return self.is_state('mapped') def get_total_size(self): return sum(p.size for p in self.partitions) + 1 - @abstractmethod def create(self, volume): + self.fsm.create(volume=volume) + + @abstractmethod + def _before_create(self, event): pass def map(self, volume): + self.fsm.map(volume=volume) + + def _before_map(self, event): + volume = event.volume try: mappings = log_check_call(['/sbin/kpartx', '-l', volume.device_path]) import re @@ -38,35 +54,23 @@ class AbstractPartitionMap(object): self.partitions[p_idx].map(partition_path) for idx, partition in enumerate(self.partitions): - if not partition.state() in ['mapped', 'formatted']: + if not partition.is_state('mapped'): raise PartitionError('kpartx did not map partition #{idx}'.format(idx=idx+1)) except PartitionError as e: for partition in self.partitions: - if partition.state() in ['mapped', 'formatted']: + if not partition.is_state('mapped'): partition.unmap() log_check_call(['/sbin/kpartx', '-d', volume.device_path]) raise e def unmap(self, volume): + self.fsm.unmap(volume=volume) + + def _before_unmap(self, event): + volume = event.volume for partition in self.partitions: - partition.unmap() + if partition.is_blocking(): + msg = 'The partition {partition} prevents the unmap procedure'.format(partition=partition) + raise PartitionError(msg) log_check_call(['/sbin/kpartx', '-d', volume.device_path]) - - def format(self): - for partition in self.partitions: - partition.format() - - def mount_root(self, destination): - self.root.mount(destination) - - def unmount_root(self): - self.root.unmount() - - def mount_boot(self): - import os.path - destination = os.path.join(self.root.mount_dir, 'boot') - self.boot.mount(destination) - - def unmount_boot(self): - self.boot.unmount() diff --git a/base/fs/partitionmaps/gpt.py b/base/fs/partitionmaps/gpt.py index 76bbd0a..348fb0c 100644 --- a/base/fs/partitionmaps/gpt.py +++ b/base/fs/partitionmaps/gpt.py @@ -20,7 +20,9 @@ class GPTPartitionMap(AbstractPartitionMap): self.mount_points.append(('none', self.root)) self.partitions = filter(lambda p: p is not None, [self.boot, self.root, self.swap]) - def create(self, volume): + super(GPTPartitionMap, self).__init__() + + def _before_create(self, volume): log_check_call(['/sbin/parted', '--script', '--align', 'none', volume.device_path, '--', 'mklabel', 'gpt']) for partition in self.partitions: diff --git a/base/fs/partitionmaps/mbr.py b/base/fs/partitionmaps/mbr.py index 2e635c4..942f5b4 100644 --- a/base/fs/partitionmaps/mbr.py +++ b/base/fs/partitionmaps/mbr.py @@ -20,7 +20,10 @@ class MBRPartitionMap(AbstractPartitionMap): self.mount_points.append(('none', self.root)) self.partitions = filter(lambda p: p is not None, [self.boot, self.root, self.swap]) - def create(self, volume): + super(MBRPartitionMap, self).__init__() + + def _before_create(self, event): + volume = event.volume log_check_call(['/sbin/parted', '--script', '--align', 'none', volume.device_path, '--', 'mklabel', 'msdos']) for partition in self.partitions: diff --git a/base/fs/partitionmaps/none.py b/base/fs/partitionmaps/none.py index ab58fda..fd80f96 100644 --- a/base/fs/partitionmaps/none.py +++ b/base/fs/partitionmaps/none.py @@ -1,7 +1,10 @@ from ..partitions.single import SinglePartition +from common.fsm_proxy import FSMProxy -class NoPartitions(object): +class NoPartitions(FSMProxy): + + events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'created'}] def __init__(self, data): root = data['root'] @@ -9,17 +12,17 @@ class NoPartitions(object): self.partitions = [self.root] self.mount_points = [('/', self.root)] + cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}} + super(NoPartitions, self).__init__(cfg) + + def is_blocking(self): + return self.root.is_blocking() + def get_total_size(self): return self.root.size def create(self, volume): - self.root.create(volume) + self.fsm.create(volume=volume) - def format(self): - self.root.format() - - def mount_root(self, destination): - self.root.mount(destination) - - def unmount_root(self): - self.root.unmount() + def _before_create(self, event): + self.root.create(event.volume) diff --git a/base/fs/partitions/abstract.py b/base/fs/partitions/abstract.py index 15b7f0d..14a0b1a 100644 --- a/base/fs/partitions/abstract.py +++ b/base/fs/partitions/abstract.py @@ -1,10 +1,10 @@ from abc import ABCMeta from abc import abstractmethod from common.tools import log_check_call -from fysom import Fysom +from common.fsm_proxy import FSMProxy -class AbstractPartition(object): +class AbstractPartition(FSMProxy): __metaclass__ = ABCMeta @@ -14,28 +14,16 @@ class AbstractPartition(object): {'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'}, ] - def __init__(self, size, filesystem, callbacks={}): + def __init__(self, size, filesystem): self.size = size self.filesystem = filesystem self.device_path = None - callbacks.update({'onbeforecreate': self._create, - 'onbeforeformat': self._format, - 'onbeforemount': self._mount, - 'onbeforeunmount': self._unmount, - }) + cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}} + super(AbstractPartition, self).__init__(cfg) - self.fsm = Fysom({'initial': 'nonexistent', - 'events': self.events, - 'callbacks': callbacks}) - from common.fsm import attach_proxy_methods - attach_proxy_methods(self, self.events, self.fsm) - - def state(self): - return self.fsm.current - - def force_state(self, state): - self.fsm.current = state + def is_blocking(self): + return self.is_state('mounted') def get_uuid(self): [uuid] = log_check_call(['/sbin/blkid', '-s', 'UUID', '-o', 'value', self.device_path]) @@ -45,20 +33,20 @@ class AbstractPartition(object): self.fsm.create(volume=volume) @abstractmethod - def _create(self, e): + def _before_create(self, e): pass - def _format(self, e): + def _before_format(self, e): mkfs = '/sbin/mkfs.{fs}'.format(fs=self.filesystem) log_check_call([mkfs, self.device_path]) def mount(self, destination): self.fsm.mount(destination=destination) - def _mount(self, e): + def _before_mount(self, e): log_check_call(['/bin/mount', '--types', self.filesystem, self.device_path, e.destination]) self.mount_dir = e.destination - def _unmount(self, e): + def _before_unmount(self, e): log_check_call(['/bin/umount', self.mount_dir]) del self.mount_dir diff --git a/base/fs/partitions/base.py b/base/fs/partitions/base.py index f79ebb3..65d97ee 100644 --- a/base/fs/partitions/base.py +++ b/base/fs/partitions/base.py @@ -5,20 +5,21 @@ class BasePartition(AbstractPartition): events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'unmapped'}, {'name': 'map', 'src': 'unmapped', 'dst': 'mapped'}, - {'name': 'map', 'src': 'unmapped_fmt', 'dst': 'formatted'}, {'name': 'format', 'src': 'mapped', 'dst': 'formatted'}, {'name': 'mount', 'src': 'formatted', 'dst': 'mounted'}, {'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'}, {'name': 'unmap', 'src': 'formatted', 'dst': 'unmapped_fmt'}, + + {'name': 'map', 'src': 'unmapped_fmt', 'dst': 'formatted'}, {'name': 'unmap', 'src': 'mapped', 'dst': 'unmapped'}, ] - def __init__(self, size, filesystem, previous, callbacks={}): + def __init__(self, size, filesystem, previous): self.previous = previous - callbacks.update({'onbeforemap': self._map, - 'onbeforeunmap': self._unmap, - }) - super(BasePartition, self).__init__(size, filesystem, callbacks=callbacks) + super(BasePartition, self).__init__(size, filesystem) + + def is_blocking(self): + return self.get_state() in ['mapped', 'mounted', 'formatted'] def get_index(self): if self.previous is None: @@ -35,8 +36,8 @@ class BasePartition(AbstractPartition): def map(self, device_path): self.fsm.map(device_path=device_path) - def _map(self, e): + def _before_map(self, e): self.device_path = e.device_path - def _unmap(self, e): + def _before_unmap(self, e): self.device_path = None diff --git a/base/fs/partitions/gpt.py b/base/fs/partitions/gpt.py index 01987ad..a50f76d 100644 --- a/base/fs/partitions/gpt.py +++ b/base/fs/partitions/gpt.py @@ -4,11 +4,11 @@ from base import BasePartition class GPTPartition(BasePartition): - def __init__(self, size, filesystem, name, previous, callbacks={}): + def __init__(self, size, filesystem, name, previous): self.name = name - super(GPTPartition, self).__init__(size, filesystem, previous, callbacks=callbacks) + super(GPTPartition, self).__init__(size, filesystem, previous) - def _create(self, e): + def _before_create(self, e): start = self.get_start() # {name} only works for gpt, for msdos that becomes the part-type (primary, extended, logical) parted_command = ('mkpart primary {start}MiB {end}MiB' diff --git a/base/fs/partitions/gpt_swap.py b/base/fs/partitions/gpt_swap.py index 030e58b..0217770 100644 --- a/base/fs/partitions/gpt_swap.py +++ b/base/fs/partitions/gpt_swap.py @@ -7,5 +7,5 @@ class GPTSwapPartition(GPTPartition): def __init__(self, size, previous): super(GPTSwapPartition, self).__init__(size, 'swap', 'swap', previous) - def _format(self, e): + def _before_format(self, e): log_check_call(['/sbin/mkswap', self.device_path]) diff --git a/base/fs/partitions/mbr.py b/base/fs/partitions/mbr.py index 9d4fbbd..511cd10 100644 --- a/base/fs/partitions/mbr.py +++ b/base/fs/partitions/mbr.py @@ -4,7 +4,7 @@ from base import BasePartition class MBRPartition(BasePartition): - def _create(self, e): + def _before_create(self, e): start = self.get_start() parted_command = ('mkpart primary {start}MiB {end}MiB' .format(start=str(start), diff --git a/base/fs/partitions/mbr_swap.py b/base/fs/partitions/mbr_swap.py index 0c5c1a1..4e62e4b 100644 --- a/base/fs/partitions/mbr_swap.py +++ b/base/fs/partitions/mbr_swap.py @@ -7,5 +7,5 @@ class MBRSwapPartition(MBRPartition): def __init__(self, size, previous): super(MBRSwapPartition, self).__init__(size, 'swap', previous) - def _format(self, e): + def _before_format(self, e): log_check_call(['/sbin/mkswap', self.device_path]) diff --git a/base/fs/partitions/single.py b/base/fs/partitions/single.py index c43236a..b7905ea 100644 --- a/base/fs/partitions/single.py +++ b/base/fs/partitions/single.py @@ -3,11 +3,5 @@ from abstract import AbstractPartition class SinglePartition(AbstractPartition): - events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'created'}, - {'name': 'format', 'src': 'created', 'dst': 'formatted'}, - {'name': 'mount', 'src': 'formatted', 'dst': 'mounted'}, - {'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'}, - ] - - def _create(self, e): + def _before_create(self, e): self.device_path = e.volume.device_path diff --git a/base/fs/volume.py b/base/fs/volume.py index 8d063f1..4a4958e 100644 --- a/base/fs/volume.py +++ b/base/fs/volume.py @@ -1,138 +1,48 @@ from abc import ABCMeta -from fysom import Fysom +from common.fsm_proxy import FSMProxy +from common.tools import log_check_call +from exceptions import VolumeError -class Volume(object): +class Volume(FSMProxy): __metaclass__ = ABCMeta events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'detached'}, {'name': 'attach', 'src': 'detached', 'dst': 'attached'}, - {'name': 'partition', 'src': 'attached', 'dst': 'partitioned'}, - {'name': 'map', 'src': 'partitioned', 'dst': 'mapped'}, - {'name': 'format', 'src': 'mapped', 'dst': 'formatted'}, - {'name': 'mount', 'src': ['formatted', 'mounted'], 'dst': 'mounted'}, - {'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'}, - {'name': 'unmap', 'src': 'formatted', 'dst': 'partitioned_fmt'}, - {'name': 'detach', 'src': 'partitioned_fmt', 'dst': 'detached_fmt'}, - {'name': 'delete', 'src': ['detached', 'detached_prt', 'detached_fmt'], 'dst': 'deleted'}, - - {'name': 'attach', 'src': 'detached_fmt', 'dst': 'partitioned_fmt'}, - {'name': 'map', 'src': 'partitioned_fmt', 'dst': 'formatted'}, - - {'name': 'attach', 'src': 'detached_prt', 'dst': 'partitioned'}, - {'name': 'detach', 'src': 'partitioned', 'dst': 'detached_prt'}, - + {'name': 'mount_specials', 'src': 'attached', 'dst': 'specials_mounted'}, + {'name': 'unmount_specials', 'src': 'specials_mounted', 'dst': 'attached'}, {'name': 'detach', 'src': 'attached', 'dst': 'detached'}, - {'name': 'unmap', 'src': 'mapped', 'dst': 'partitioned'}, + {'name': 'delete', 'src': 'detached', 'dst': 'deleted'}, ] - mount_events = [{'name': 'mount_root', 'src': 'unmounted', 'dst': 'root_mounted'}, - {'name': 'mount_boot', 'src': 'root_mounted', 'dst': 'boot_mounted'}, - {'name': 'mount_specials', 'src': 'boot_mounted', 'dst': 'specials_mounted'}, - {'name': 'unmount_specials', 'src': 'specials_mounted', 'dst': 'boot_mounted'}, - {'name': 'unmount_boot', 'src': 'boot_mounted', 'dst': 'root_mounted'}, - {'name': 'unmount_root', 'src': 'root_mounted', 'dst': 'unmounted'}, - - {'name': 'mount_specials', 'src': 'root_mounted', 'dst': 'specials_mounted_no_boot'}, - {'name': 'mount_boot', 'src': 'specials_mounted_no_boot', 'dst': 'specials_mounted'}, - {'name': 'unmount_specials', 'src': 'specials_mounted_no_boot', 'dst': 'root_mounted'}, - {'name': 'unmount_boot', 'src': 'specials_mounted', 'dst': 'specials_mounted_no_boot'}, - ] - - def __init__(self, partition_map, callbacks={}): + def __init__(self, partition_map): self.device_path = None self.partition_map = partition_map self.size = self.partition_map.get_total_size() - callbacks.update({'onbeforepartition': self._partition, - 'onbeforemap': self._map, - 'onbeforeunmap': self._unmap, - 'onbeforeformat': self._format, - 'onbeforeunmount': self._unmount, - }) + callbacks = {'onbeforedetach': self._check_blocking} + from partitionmaps.none import NoPartitions + if isinstance(self.partition_map, NoPartitions): + callbacks['onafterattach'] = lambda e: self.partition_map.create(self) - mount_callbacks = {'onbeforemount_root': self._mount_root, - 'onbeforemount_boot': self._mount_boot, - 'onbeforemount_specials': self._mount_specials, - 'onbeforeunmount_root': self._unmount_root, - 'onbeforeunmount_boot': self._unmount_boot, - 'onbeforeunmount_specials': self._unmount_specials, - } - self.fsm = Fysom({'initial': 'nonexistent', - 'events': self.events, - 'callbacks': callbacks}) + cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': callbacks} + super(Volume, self).__init__(cfg) - self.mount_fsm = Fysom({'initial': 'unmounted', - 'events': self.mount_events, - 'callbacks': mount_callbacks}) - - from common.fsm import attach_proxy_methods - attach_proxy_methods(self, self.events, self.fsm) - attach_proxy_methods(self, self.mount_events, self.mount_fsm) - - def state(self): - return self.fsm.current - - def force_state(self, state): - self.fsm.current = state - - def _partition(self, e): - self.partition_map.create(self) - - def _map(self, e): - self.partition_map.map(self) - - def _unmap(self, e): - self.partition_map.unmap(self) - - def _format(self, e): - self.partition_map.format() - - def _unmount(self, e): - if self.mount_fsm.current is 'specials_mounted': - self.unmount_specials() - if self.mount_fsm.current is 'specials_mounted_no_boot': - self.unmount_specials() - if self.mount_fsm.current is 'boot_mounted': - self.unmount_boot() - if self.mount_fsm.current is 'root_mounted': - self.unmount_root() - - def mount_root(self, destination): - self.mount_fsm.mount_root(destination=destination) - - def unmount_root(self): - self.mount_fsm.unmount_root() - self.fsm.unmount() - - def _mount_root(self, e): - self.mount() - self.partition_map.mount_root(e.destination) - - def _unmount_root(self, e): - self.partition_map.unmount_root() - - def _mount_boot(self, e): - self.mount() - self.partition_map.mount_boot() - - def _unmount_boot(self, e): - self.partition_map.unmount_boot() - - def _mount_specials(self, e): - self.mount() - from common.tools import log_check_call + def _before_mount_specials(self, e): 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']) - def _unmount_specials(self, e): - from common.tools import log_check_call + def _before_unmount_specials(self, e): 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)]) + + def _check_blocking(self, e): + if self.partition_map.is_blocking(): + raise VolumeError('The partitionmap prevents the detach procedure') diff --git a/common/fs/loopbackvolume.py b/common/fs/loopbackvolume.py index 0dcc35b..e670a5e 100644 --- a/common/fs/loopbackvolume.py +++ b/common/fs/loopbackvolume.py @@ -9,45 +9,31 @@ from base.fs.exceptions import VolumeError class LoopbackVolume(Volume): - link_dm_events = [{'name': 'link_dm_node', 'src': 'partitioned', 'dst': 'linked'}, - {'name': 'map', 'src': 'linked', 'dst': 'mapped_lnk'}, - {'name': 'format', 'src': 'mapped_lnk', 'dst': 'formatted_lnk'}, - {'name': 'mount', 'src': ['formatted_lnk', 'mounted_lnk'], 'dst': 'mounted_lnk'}, - {'name': 'unmount', 'src': 'mounted_lnk', 'dst': 'formatted_lnk'}, - {'name': 'unmap', 'src': 'formatted_lnk', 'dst': 'partitioned_fmt_lnk'}, - {'name': 'unlink_dm_node', 'src': 'partitioned_fmt_lnk', 'dst': 'partitioned_fmt'}, - - {'name': 'link_dm_node', 'src': 'partitioned_fmt', 'dst': 'partitioned_fmt_lnk'}, - {'name': 'map', 'src': 'partitioned_fmt_lnk', 'dst': 'formatted_lnk'}, - {'name': 'unmap', 'src': 'mapped_lnk', 'dst': 'linked'}, - {'name': 'unlink_dm_node', 'src': 'linked', 'dst': 'partitioned'}, - ] + events = [{'name': 'create', 'src': 'nonexistent', 'dst': 'detached'}, + {'name': 'attach', 'src': 'detached', 'dst': 'attached'}, + {'name': 'link_dm_node', 'src': 'attached', 'dst': 'linked'}, + {'name': 'unlink_dm_node', 'src': 'linked', 'dst': 'attached'}, + {'name': 'detach', 'src': 'attached', 'dst': 'detached'}, + {'name': 'delete', 'src': 'detached', 'dst': 'deleted'}, + ] extension = 'raw' - def __init__(self, partition_map, callbacks={}): - callbacks.update({'onbeforecreate': self._create, - 'onbeforeattach': self._attach, - 'onbeforedetach': self._detach, - 'onbeforedelete': self._delete, - 'onbeforelink_dm_node': self._link_dm_node, - 'onbeforeunlink_dm_node': self._unlink_dm_node, - }) - self.events.extend(self.link_dm_events) - super(LoopbackVolume, self).__init__(partition_map, callbacks=callbacks) + def __init__(self, partition_map): + super(LoopbackVolume, self).__init__(partition_map) def create(self, image_path): self.fsm.create(image_path=image_path) - def _create(self, e): + def _before_create(self, e): self.image_path = e.image_path log_check_call(['/usr/bin/qemu-img', 'create', '-f', 'raw', self.image_path, str(self.size) + 'M']) - def _attach(self, e): + def _before_attach(self, e): [self.loop_device_path] = log_check_call(['/sbin/losetup', '--show', '--find', self.image_path]) self.device_path = self.loop_device_path - def _link_dm_node(self, e): + def _before_link_dm_node(self, e): import os.path from . import get_partitions proc_partitions = get_partitions() @@ -77,18 +63,18 @@ class LoopbackVolume(Volume): log_check_call(['/sbin/dmsetup', 'create', self.dm_node_name], table) self.device_path = self.dm_node_path - def _unlink_dm_node(self, e): + def _before_unlink_dm_node(self, e): log_check_call(['/sbin/dmsetup', 'remove', self.dm_node_name]) del self.dm_node_name del self.dm_node_path self.device_path = self.loop_device_path - def _detach(self, e): + def _before_detach(self, e): log_check_call(['/sbin/losetup', '--detach', self.loop_device_path]) del self.loop_device_path del self.device_path - def _delete(self, e): + def _before_delete(self, e): from os import remove remove(self.image_path) del self.image_path diff --git a/common/fsm.py b/common/fsm.py deleted file mode 100644 index 44286e0..0000000 --- a/common/fsm.py +++ /dev/null @@ -1,7 +0,0 @@ - - -def attach_proxy_methods(obj, events, fsm): - methods = set([e['name'] for e in events]) - for event in methods: - if not hasattr(obj, event): - setattr(obj, event, lambda e=event: getattr(fsm, e)()) diff --git a/common/fsm_proxy.py b/common/fsm_proxy.py new file mode 100644 index 0000000..6235e10 --- /dev/null +++ b/common/fsm_proxy.py @@ -0,0 +1,51 @@ + + +class FSMProxy(object): + + def __init__(self, cfg): + from fysom import Fysom + events = set([event['name'] for event in cfg['events']]) + cfg['callbacks'] = self.collect_event_listeners(events, cfg['callbacks']) + self.fsm = Fysom(cfg) + self.attach_proxy_methods(self.fsm, events) + + def is_state(self, event): + return self.fsm.isstate(event) + + def set_state(self, event): + self.fsm.current = event + + def get_state(self): + return self.fsm.current + + def collect_event_listeners(self, events, callbacks): + callbacks = callbacks.copy() + callback_names = [] + for event in events: + callback_names.append(('_before_' + event, 'onbefore' + event)) + callback_names.append(('_after_' + event, 'onafter' + event)) + for fn_name, listener in callback_names: + fn = getattr(self, fn_name, None) + if callable(fn): + if listener in callbacks: + old_fn = callbacks[listener] + + def wrapper(e, old_fn=old_fn, fn=fn): + old_fn(e) + fn(e) + callbacks[listener] = wrapper + else: + callbacks[listener] = fn + return callbacks + + def attach_proxy_methods(self, fsm, events): + def make_proxy(fsm, event): + fn = getattr(fsm, event) + + def proxy(): + fn() + return proxy + + for event in events: + if not hasattr(self, event): + setattr(self, event, make_proxy(fsm, event)) diff --git a/common/tasks/filesystem.py b/common/tasks/filesystem.py index 8af2c49..08dd86a 100644 --- a/common/tasks/filesystem.py +++ b/common/tasks/filesystem.py @@ -10,7 +10,8 @@ class Format(Task): phase = phases.volume_preparation def run(self, info): - info.volume.format() + for partition in info.volume.partition_map.partitions: + partition.format() class TuneVolumeFS(Task): @@ -51,7 +52,7 @@ class MountRoot(Task): after = [CreateMountDir] def run(self, info): - info.volume.mount_root(info.root) + info.volume.partition_map.root.mount(info.root) class MountBoot(Task): @@ -60,7 +61,7 @@ class MountBoot(Task): after = [MountRoot] def run(self, info): - info.volume.mount_boot() + info.volume.partition_map.boot.mount(info.boot_dir) class CreateBootMountDir(Task): @@ -71,8 +72,8 @@ class CreateBootMountDir(Task): def run(self, info): import os - boot_dir = os.path.join(info.root, 'boot') - os.makedirs(boot_dir) + info.boot_dir = os.path.join(info.root, 'boot') + os.makedirs(info.boot_dir) class MountSpecials(Task): @@ -90,7 +91,7 @@ class UnmountRoot(Task): before = [volume.Detach] def run(self, info): - info.volume.unmount_root() + info.volume.partition_map.root.unmount() class UnmountBoot(Task): @@ -99,7 +100,7 @@ class UnmountBoot(Task): before = [UnmountRoot] def run(self, info): - info.volume.unmount_boot() + info.volume.partition_map.boot.unmount() class UnmountSpecials(Task): diff --git a/common/tasks/partitioning.py b/common/tasks/partitioning.py index 181bb63..eeca38d 100644 --- a/common/tasks/partitioning.py +++ b/common/tasks/partitioning.py @@ -9,7 +9,7 @@ class PartitionVolume(Task): phase = phases.volume_preparation def run(self, info): - info.volume.partition() + info.volume.partition_map.create() class MapPartitions(Task): @@ -19,7 +19,7 @@ class MapPartitions(Task): after = [PartitionVolume] def run(self, info): - info.volume.map() + info.volume.partition_map.map() class UnmapPartitions(Task): @@ -29,4 +29,4 @@ class UnmapPartitions(Task): after = [filesystem.UnmountRoot] def run(self, info): - info.volume.unmap() + info.volume.partition_map.unmap() diff --git a/providers/ec2/volume.py b/providers/ec2/volume.py index bd1983f..16e4e96 100644 --- a/providers/ec2/volume.py +++ b/providers/ec2/volume.py @@ -19,7 +19,10 @@ class EBSVolume(Volume): self.created = True def attach(self, instance_id): - super(EBSVolume, self).attach(self) + self.fsm.attach(instance_id=instance_id) + + def _before_attach(self, e): + instance_id = e.instance_id import os.path import string for letter in string.ascii_lowercase: @@ -37,14 +40,13 @@ class EBSVolume(Volume): time.sleep(2) self.volume.update() - def detach(self): - super(EBSVolume, self).detach(self) + def _before_detach(self, e): self.volume.detach() while self.volume.attachment_state() is not None: time.sleep(2) self.volume.update() - def delete(self): + def _before_delete(self, e): super(EBSVolume, self).delete(self) self.volume.delete() diff --git a/providers/virtualbox/volume.py b/providers/virtualbox/volume.py index b6d6b0d..6c3d10c 100644 --- a/providers/virtualbox/volume.py +++ b/providers/virtualbox/volume.py @@ -8,11 +8,11 @@ class VirtualBoxVolume(LoopbackVolume): extension = 'vdi' - def _create(self, e): + def _before_create(self, e): self.image_path = e.image_path log_check_call(['/usr/bin/qemu-img', 'create', '-f', 'vdi', self.image_path, str(self.size) + 'M']) - def _attach(self, e): + def _before_attach(self, e): num_partitions = len(self.partition_map.partitions) if not self._module_loaded('nbd'): msg = ('The kernel module `nbd\' must be loaded ' @@ -33,7 +33,7 @@ class VirtualBoxVolume(LoopbackVolume): 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): + def _before_detach(self, e): log_check_call(['/usr/bin/qemu-nbd', '--disconnect', self.loop_device_path]) del self.loop_device_path del self.device_path