mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-22 09:50:37 +00:00

Up until now I didn't see the point of using spaces for indentation. However, the previous commit (a18bec3) was quite eye opening. Given that python is an indentation aware language, the amount of mistakes that went unnoticed because tabs and spaces were used at the same time (tabs for indentation and spaces for alignment) were unacceptable. E101,W191 have been re-enable in the tox flake8 checker and the documentation has been modified accordingly. The following files have been left as-is: * bootstrapvz/common/assets/extlinux/extlinux.conf * bootstrapvz/common/assets/init.d/expand-root * bootstrapvz/common/assets/init.d/generate-ssh-hostkeys * bootstrapvz/common/assets/init.d/squeeze/generate-ssh-hostkeys * bootstrapvz/plugins/docker_daemon/assets/init.d/docker * bootstrapvz/providers/ec2/assets/bin/growpart * bootstrapvz/providers/ec2/assets/grub.d/40_custom * bootstrapvz/providers/ec2/assets/init.d/ec2-get-credentials * bootstrapvz/providers/ec2/assets/init.d/ec2-run-user-data * docs/_static/taskoverview.coffee * docs/_static/taskoverview.less * tests/unit/subprocess.sh
129 lines
5 KiB
Python
129 lines
5 KiB
Python
from abc import ABCMeta
|
|
from abc import abstractmethod
|
|
from bootstrapvz.common.sectors import Sectors
|
|
from bootstrapvz.common.tools import log_check_call
|
|
from bootstrapvz.common.fsm_proxy import FSMProxy
|
|
|
|
|
|
class AbstractPartition(FSMProxy):
|
|
"""Abstract representation of a partiton
|
|
This class is a finite state machine and represents the state of the real partition
|
|
"""
|
|
|
|
__metaclass__ = ABCMeta
|
|
|
|
# Our states
|
|
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 __init__(self, size, filesystem, format_command):
|
|
"""
|
|
:param Bytes size: Size of the partition
|
|
:param str filesystem: Filesystem the partition should be formatted with
|
|
:param list format_command: Optional format command, valid variables are fs, device_path and size
|
|
"""
|
|
self.size = size
|
|
self.filesystem = filesystem
|
|
self.format_command = format_command
|
|
# Initialize the start & end padding to 0 sectors, may be changed later
|
|
self.pad_start = Sectors(0, size.sector_size)
|
|
self.pad_end = Sectors(0, size.sector_size)
|
|
# Path to the partition
|
|
self.device_path = None
|
|
# Dictionary with mount points as keys and Mount objects as values
|
|
self.mounts = {}
|
|
|
|
# Create the configuration for our state machine
|
|
cfg = {'initial': 'nonexistent', 'events': self.events, 'callbacks': {}}
|
|
super(AbstractPartition, self).__init__(cfg)
|
|
|
|
def get_uuid(self):
|
|
"""Gets the UUID of the partition
|
|
|
|
:return: The UUID of the partition
|
|
:rtype: str
|
|
"""
|
|
[uuid] = log_check_call(['blkid', '-s', 'UUID', '-o', 'value', self.device_path])
|
|
return uuid
|
|
|
|
@abstractmethod
|
|
def get_start(self):
|
|
pass
|
|
|
|
def get_end(self):
|
|
"""Gets the end of the partition
|
|
|
|
:return: The end of the partition
|
|
:rtype: Sectors
|
|
"""
|
|
return self.get_start() + self.pad_start + self.size + self.pad_end
|
|
|
|
def _before_format(self, e):
|
|
"""Formats the partition
|
|
"""
|
|
# If there is no explicit format_command define we simply call mkfs.fstype
|
|
if self.format_command is None:
|
|
format_command = ['mkfs.{fs}', '{device_path}']
|
|
else:
|
|
format_command = self.format_command
|
|
variables = {'fs': self.filesystem,
|
|
'device_path': self.device_path,
|
|
'size': self.size,
|
|
}
|
|
command = map(lambda part: part.format(**variables), format_command)
|
|
# Format the partition
|
|
log_check_call(command)
|
|
|
|
def _before_mount(self, e):
|
|
"""Mount the partition
|
|
"""
|
|
log_check_call(['mount', '--types', self.filesystem, self.device_path, e.destination])
|
|
self.mount_dir = e.destination
|
|
|
|
def _after_mount(self, e):
|
|
"""Mount any mounts associated with this partition
|
|
"""
|
|
# Make sure we mount in ascending order of mountpoint path length
|
|
# This ensures that we don't mount /dev/pts before we mount /dev
|
|
for destination in sorted(self.mounts.iterkeys(), key=len):
|
|
self.mounts[destination].mount(self.mount_dir)
|
|
|
|
def _before_unmount(self, e):
|
|
"""Unmount any mounts associated with this partition
|
|
"""
|
|
# Unmount the mounts in descending order of mounpoint path length
|
|
# You cannot unmount /dev before you have unmounted /dev/pts
|
|
for destination in sorted(self.mounts.iterkeys(), key=len, reverse=True):
|
|
self.mounts[destination].unmount()
|
|
log_check_call(['umount', self.mount_dir])
|
|
del self.mount_dir
|
|
|
|
def add_mount(self, source, destination, opts=[]):
|
|
"""Associate a mount with this partition
|
|
Automatically mounts it
|
|
|
|
:param str,AbstractPartition source: The source of the mount
|
|
:param str destination: The path to the mountpoint
|
|
:param list opts: Any options that should be passed to the mount command
|
|
"""
|
|
# Create a new mount object, mount it if the partition is mounted and put it in the mounts dict
|
|
from mount import Mount
|
|
mount = Mount(source, destination, opts)
|
|
if self.fsm.current == 'mounted':
|
|
mount.mount(self.mount_dir)
|
|
self.mounts[destination] = mount
|
|
|
|
def remove_mount(self, destination):
|
|
"""Remove a mount from this partition
|
|
Automatically unmounts it
|
|
|
|
:param str destination: The mountpoint path of the mount that should be removed
|
|
"""
|
|
# Unmount the mount if the partition is mounted and delete it from the mounts dict
|
|
# If the mount is already unmounted and the source is a partition, this will raise an exception
|
|
if self.fsm.current == 'mounted':
|
|
self.mounts[destination].unmount()
|
|
del self.mounts[destination]
|