diff --git a/bootstrapvz/base/fs/partitionmaps/abstract.py b/bootstrapvz/base/fs/partitionmaps/abstract.py index ed25770..cde7c2f 100644 --- a/bootstrapvz/base/fs/partitionmaps/abstract.py +++ b/bootstrapvz/base/fs/partitionmaps/abstract.py @@ -1,6 +1,5 @@ from abc import ABCMeta from abc import abstractmethod -from ..partitions.gap import PartitionGap from bootstrapvz.common.tools import log_check_call from bootstrapvz.common.fsm_proxy import FSMProxy from ..exceptions import PartitionError @@ -76,8 +75,6 @@ class AbstractPartitionMap(FSMProxy): .format(device_path=volume.device_path)) log_check_call(['kpartx', '-as', volume.device_path]) - mappable_partitions = filter(lambda p: not isinstance(p, PartitionGap), self.partitions) - import os.path # Run through the kpartx output and map the paths to the partitions for mapping in mappings: @@ -86,12 +83,10 @@ class AbstractPartitionMap(FSMProxy): raise PartitionError('Unable to parse kpartx output: ' + mapping) partition_path = os.path.join('/dev/mapper', match.group('name')) p_idx = int(match.group('p_idx')) - 1 - mappable_partitions[p_idx].map(partition_path) + self.partitions[p_idx].map(partition_path) # Check if any partition was not mapped for idx, partition in enumerate(self.partitions): - if isinstance(partition, PartitionGap): - continue if partition.fsm.current not in ['mapped', 'formatted']: raise PartitionError('kpartx did not map partition #' + str(partition.get_index())) @@ -117,8 +112,6 @@ class AbstractPartitionMap(FSMProxy): volume = event.volume # Run through all partitions before unmapping and make sure they can all be unmapped for partition in self.partitions: - if isinstance(partition, PartitionGap): - continue if partition.fsm.cannot('unmap'): msg = 'The partition {partition} prevents the unmap procedure'.format(partition=partition) raise PartitionError(msg) @@ -126,6 +119,4 @@ class AbstractPartitionMap(FSMProxy): log_check_call(['kpartx', '-ds', volume.device_path]) # Call unmap on all partitions for partition in self.partitions: - if isinstance(partition, PartitionGap): - continue partition.unmap() diff --git a/bootstrapvz/base/fs/partitionmaps/gpt.py b/bootstrapvz/base/fs/partitionmaps/gpt.py index afae06a..b8918d3 100644 --- a/bootstrapvz/base/fs/partitionmaps/gpt.py +++ b/bootstrapvz/base/fs/partitionmaps/gpt.py @@ -1,7 +1,6 @@ from abstract import AbstractPartitionMap from ..partitions.gpt import GPTPartition from ..partitions.gpt_swap import GPTSwapPartition -from ..partitions.gap import PartitionGap from bootstrapvz.common.tools import log_check_call @@ -24,57 +23,60 @@ class GPTPartitionMap(AbstractPartitionMap): def last_partition(): return self.partitions[-1] if len(self.partitions) > 0 else None - # The first 34 sectors are reserved for the primary GPT - primary_gpt = PartitionGap(Sectors(34, sector_size), last_partition()) - self.partitions.append(primary_gpt) - if bootloader == 'grub': # If we are using the grub bootloader we need to create an unformatted partition # at the beginning of the map. Its size is 1007kb, which seems to be chosen so that - # gpt_primary + grub = 1024KiB - # So lets just specify grub size as 1MiB - 34 sectors + # primary gpt + grub = 1024KiB + # The 34 sectors for the primary gpt will be subtracted later on from ..partitions.unformatted import UnformattedPartition - grub_size = Sectors('1MiB', sector_size) - primary_gpt.size - self.grub_boot = UnformattedPartition(grub_size, last_partition()) + self.grub_boot = UnformattedPartition(Sectors('1MiB', sector_size), last_partition()) self.partitions.append(self.grub_boot) + # Offset all partitions by 1 sector. + # parted in jessie has changed and no longer allows + # gpt partitions to be right next to each other. + partition_gap = Sectors(1, sector_size) + # The boot and swap partitions are optional if 'boot' in data: self.boot = GPTPartition(Sectors(data['boot']['size'], sector_size), data['boot']['filesystem'], data['boot'].get('format_command', None), 'boot', last_partition()) - # Offset all partitions by 1 sector. - # parted in jessie has changed and no longer allows partitions to be right next to each other. - self.boot.offset = Sectors(1, sector_size) - self.boot.size -= self.boot.offset + if self.boot.previous is not None: + # No need to pad if this is the first partition + self.boot.pad_start += partition_gap + self.boot.size -= partition_gap self.partitions.append(self.boot) + if 'swap' in data: self.swap = GPTSwapPartition(Sectors(data['swap']['size'], sector_size), last_partition()) - self.swap.offset = Sectors(1, sector_size) - self.swap.size -= self.swap.offset + if self.swap.previous is not None: + self.swap.pad_start += partition_gap + self.swap.size -= partition_gap self.partitions.append(self.swap) + self.root = GPTPartition(Sectors(data['root']['size'], sector_size), data['root']['filesystem'], data['root'].get('format_command', None), 'root', last_partition()) - self.root.offset = Sectors(1, sector_size) - self.root.size -= self.root.offset + if self.root.previous is not None: + self.root.pad_start += partition_gap + self.root.size -= partition_gap self.partitions.append(self.root) - # The last 34 sectors are reserved for the secondary GPT - secondary_gpt = PartitionGap(Sectors(34, sector_size), last_partition()) - self.partitions.append(secondary_gpt) + # The first and last 34 sectors are reserved for the primary/secondary GPT + primary_gpt_size = Sectors(34, sector_size) + self.partitions[0].pad_start += primary_gpt_size + self.partitions[0].size -= primary_gpt_size - # reduce the size of the root partition so that the overall volume size is not exceeded - self.root.size -= primary_gpt.size + secondary_gpt.size - if hasattr(self, 'grub_boot'): - self.root.size -= self.grub_boot.size + secondary_gpt_size = Sectors(34, sector_size) + self.partitions[-1].pad_end += secondary_gpt_size + self.partitions[-1].size -= secondary_gpt_size - # Set the boot flag on the right partition if hasattr(self, 'grub_boot'): - # Mark the partition as a bios_grub partition + # Mark the grub partition as a bios_grub partition self.grub_boot.flags.append('bios_grub') else: - # Mark the boot partition, or root, if boot does not exist + # Not using grub, mark the boot partition or root as bootable getattr(self, 'boot', self.root).flags.append('legacy_boot') super(GPTPartitionMap, self).__init__(bootloader) @@ -89,6 +91,4 @@ class GPTPartitionMap(AbstractPartitionMap): '--', 'mklabel', 'gpt']) # Create the partitions for partition in self.partitions: - if isinstance(partition, PartitionGap): - continue partition.create(volume) diff --git a/bootstrapvz/base/fs/partitionmaps/msdos.py b/bootstrapvz/base/fs/partitionmaps/msdos.py index d959e37..89934c5 100644 --- a/bootstrapvz/base/fs/partitionmaps/msdos.py +++ b/bootstrapvz/base/fs/partitionmaps/msdos.py @@ -1,7 +1,6 @@ from abstract import AbstractPartitionMap from ..partitions.msdos import MSDOSPartition from ..partitions.msdos_swap import MSDOSSwapPartition -from ..partitions.gap import PartitionGap from bootstrapvz.common.tools import log_check_call @@ -31,9 +30,11 @@ class MSDOSPartitionMap(AbstractPartitionMap): data['boot']['filesystem'], data['boot'].get('format_command', None), last_partition()) self.partitions.append(self.boot) + if 'swap' in data: self.swap = MSDOSSwapPartition(Sectors(data['swap']['size'], sector_size), last_partition()) self.partitions.append(self.swap) + self.root = MSDOSPartition(Sectors(data['root']['size'], sector_size), data['root']['filesystem'], data['root'].get('format_command', None), last_partition()) @@ -47,16 +48,18 @@ class MSDOSPartitionMap(AbstractPartitionMap): # The MBR offset is included in the grub offset, so if we don't use grub # we should reduce the size of the first partition and move it by only 512 bytes. if bootloader == 'grub': - offset = Sectors('2MiB', sector_size) + mbr_offset = Sectors('2MiB', sector_size) else: - offset = Sectors('512B', sector_size) + mbr_offset = Sectors('512B', sector_size) - self.partitions[0].offset += offset - self.partitions[0].size -= offset + self.partitions[0].pad_start += mbr_offset + self.partitions[0].size -= mbr_offset # Leave the last sector unformatted + # parted in jessie thinks that a partition 10 sectors in size + # goes from sector 0 to sector 9 (instead of 0 to 10) + self.partitions[-1].pad_end += 1 self.partitions[-1].size -= 1 - self.partitions.append(PartitionGap(Sectors(1, sector_size), last_partition())) super(MSDOSPartitionMap, self).__init__(bootloader) @@ -68,6 +71,4 @@ class MSDOSPartitionMap(AbstractPartitionMap): '--', 'mklabel', 'msdos']) # Create the partitions for partition in self.partitions: - if isinstance(partition, PartitionGap): - continue partition.create(volume) diff --git a/bootstrapvz/base/fs/partitions/abstract.py b/bootstrapvz/base/fs/partitions/abstract.py index 10e66e4..9d481d7 100644 --- a/bootstrapvz/base/fs/partitions/abstract.py +++ b/bootstrapvz/base/fs/partitions/abstract.py @@ -1,5 +1,6 @@ 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 @@ -27,6 +28,9 @@ class AbstractPartition(FSMProxy): 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 @@ -55,7 +59,7 @@ class AbstractPartition(FSMProxy): :return: The end of the partition :rtype: Sectors """ - return self.get_start() + self.size + return self.get_start() + self.pad_start + self.size + self.pad_end def _before_format(self, e): """Formats the partition diff --git a/bootstrapvz/base/fs/partitions/base.py b/bootstrapvz/base/fs/partitions/base.py index 23af1b8..3e5cbab 100644 --- a/bootstrapvz/base/fs/partitions/base.py +++ b/bootstrapvz/base/fs/partitions/base.py @@ -1,4 +1,5 @@ from abstract import AbstractPartition +from bootstrapvz.common.sectors import Sectors class BasePartition(AbstractPartition): @@ -25,12 +26,9 @@ class BasePartition(AbstractPartition): :param list format_command: Optional format command, valid variables are fs, device_path and size :param BasePartition previous: The partition that preceeds this one """ - # By saving the previous partition we have - # a linked list that partitions can go backwards in to find the first partition. + # By saving the previous partition we have a linked list + # that partitions can go backwards in to find the first partition. self.previous = previous - from bootstrapvz.common.sectors import Sectors - # Initialize the offset to 0 sectors, may be changed later - self.offset = Sectors(0, size.sector_size) # List of flags that parted should put on the partition self.flags = [] super(BasePartition, self).__init__(size, filesystem, format_command) @@ -62,11 +60,9 @@ class BasePartition(AbstractPartition): :rtype: Sectors """ if self.previous is None: - # If there is no previous partition, this partition begins at the offset - return self.offset + return Sectors(0, self.size.sector_size) else: - # Get the end of the previous partition and add the offset of this partition - return self.previous.get_end() + self.offset + return self.previous.get_end() def map(self, device_path): """Maps the partition to a device_path @@ -81,8 +77,8 @@ class BasePartition(AbstractPartition): from bootstrapvz.common.tools import log_check_call # The create command is failry simple, start and end are just Bytes objects coerced into strings create_command = ('mkpart primary {start} {end}' - .format(start=str(self.get_start()), - end=str(self.get_end()))) + .format(start=str(self.get_start() + self.pad_start), + end=str(self.get_end() - self.pad_end))) # Create the partition log_check_call(['parted', '--script', '--align', 'none', e.volume.device_path, '--', create_command]) diff --git a/bootstrapvz/base/fs/partitions/gap.py b/bootstrapvz/base/fs/partitions/gap.py deleted file mode 100644 index e7b197b..0000000 --- a/bootstrapvz/base/fs/partitions/gap.py +++ /dev/null @@ -1,34 +0,0 @@ -from base import BasePartition - - -class PartitionGap(BasePartition): - """Represents a non-existent partition - A gap in the partitionmap - """ - - # The states for our state machine. It can neither be create nor mapped. - events = [] - - def __init__(self, size, previous): - """ - :param Bytes size: Size of the partition - :param BasePartition previous: The partition that preceeds this one - """ - super(PartitionGap, self).__init__(size, None, None, previous) - - def get_index(self): - """Gets the index of this partition in the partition map - Note that PartitionGap.get_index() simply returns the index of the - previous partition, since a gap does not count towards - the number of partitions. - If there is no previous partition 0 will be returned - (although partitions really are 1 indexed) - - :return: The index of the partition in the partition map - :rtype: int - """ - if self.previous is None: - return 0 - else: - # Recursive call to the previous partition, walking up the chain... - return self.previous.get_index() diff --git a/bootstrapvz/base/fs/partitions/single.py b/bootstrapvz/base/fs/partitions/single.py index e890493..e10b74c 100644 --- a/bootstrapvz/base/fs/partitions/single.py +++ b/bootstrapvz/base/fs/partitions/single.py @@ -12,5 +12,4 @@ class SinglePartition(AbstractPartition): :rtype: Sectors """ from bootstrapvz.common.sectors import Sectors - # On an unpartitioned volume there is no offset and no previous partition return Sectors(0, self.size.sector_size) diff --git a/bootstrapvz/common/tasks/filesystem.py b/bootstrapvz/common/tasks/filesystem.py index 7fb7511..a6cb782 100644 --- a/bootstrapvz/common/tasks/filesystem.py +++ b/bootstrapvz/common/tasks/filesystem.py @@ -25,9 +25,8 @@ class Format(Task): @classmethod def run(cls, info): from bootstrapvz.base.fs.partitions.unformatted import UnformattedPartition - from bootstrapvz.base.fs.partitions.gap import PartitionGap for partition in info.volume.partition_map.partitions: - if isinstance(partition, (UnformattedPartition, PartitionGap)): + if isinstance(partition, UnformattedPartition): continue partition.format() @@ -40,11 +39,10 @@ class TuneVolumeFS(Task): @classmethod def run(cls, info): from bootstrapvz.base.fs.partitions.unformatted import UnformattedPartition - from bootstrapvz.base.fs.partitions.gap import PartitionGap import re # Disable the time based filesystem check for partition in info.volume.partition_map.partitions: - if isinstance(partition, (UnformattedPartition, PartitionGap)): + if isinstance(partition, UnformattedPartition): continue if re.match('^ext[2-4]$', partition.filesystem) is not None: log_check_call(['tune2fs', '-i', '0', partition.device_path]) diff --git a/bootstrapvz/common/tasks/grub.py b/bootstrapvz/common/tasks/grub.py index ab5bec2..b528712 100644 --- a/bootstrapvz/common/tasks/grub.py +++ b/bootstrapvz/common/tasks/grub.py @@ -68,10 +68,7 @@ class InstallGrub_1_99(Task): with open(device_map_path, 'w') as device_map: device_map.write('(hd0) {device_path}\n'.format(device_path=device_path)) if not isinstance(p_map, partitionmaps.none.NoPartitions): - from bootstrapvz.base.fs.partitions.gap import PartitionGap for idx, partition in enumerate(info.volume.partition_map.partitions): - if isinstance(partition, PartitionGap): - continue device_map.write('(hd0,{prefix}{idx}) {device_path}\n' .format(device_path=partition.device_path, prefix=partition_prefix, diff --git a/bootstrapvz/plugins/prebootstrapped/tasks.py b/bootstrapvz/plugins/prebootstrapped/tasks.py index b1074c2..4711e46 100644 --- a/bootstrapvz/plugins/prebootstrapped/tasks.py +++ b/bootstrapvz/plugins/prebootstrapped/tasks.py @@ -84,12 +84,9 @@ def set_fs_states(volume): if not isinstance(p_map, NoPartitions): p_map.fsm.current = 'unmapped' - from bootstrapvz.base.fs.partitions.gap import PartitionGap from bootstrapvz.base.fs.partitions.unformatted import UnformattedPartition from bootstrapvz.base.fs.partitions.single import SinglePartition for partition in p_map.partitions: - if isinstance(partition, PartitionGap): - continue if isinstance(partition, UnformattedPartition): partition.fsm.current = 'unmapped' continue diff --git a/bootstrapvz/remote/__init__.py b/bootstrapvz/remote/__init__.py index 1b61c35..7397a5a 100644 --- a/bootstrapvz/remote/__init__.py +++ b/bootstrapvz/remote/__init__.py @@ -20,7 +20,6 @@ supported_classes = ['bootstrapvz.base.manifest.Manifest', 'bootstrapvz.base.fs.partitions.msdos_swap.MSDOSSwapPartition', 'bootstrapvz.base.fs.partitions.single.SinglePartition', 'bootstrapvz.base.fs.partitions.unformatted.UnformattedPartition', - 'bootstrapvz.base.fs.partitions.gap.PartitionGap', 'bootstrapvz.common.bytes.Bytes', 'bootstrapvz.common.sectors.Sectors', ]