mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 09:50:37 +00:00
Simplify FSM framework. Only model relevant states
This commit is contained in:
parent
c756eb3f74
commit
ecdc255752
19 changed files with 183 additions and 245 deletions
|
@ -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()
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)())
|
51
common/fsm_proxy.py
Normal file
51
common/fsm_proxy.py
Normal file
|
@ -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))
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue