Skip to content
This repository has been archived by the owner on Jun 10, 2019. It is now read-only.

Commit

Permalink
Merge pull request #355 from n3ph/master
Browse files Browse the repository at this point in the history
Add mountopts and enable definition of additional partitions
  • Loading branch information
andsens authored Feb 13, 2017
2 parents 5bc4937 + 4eb90a5 commit a4e4ad9
Show file tree
Hide file tree
Showing 15 changed files with 165 additions and 22 deletions.
15 changes: 13 additions & 2 deletions bootstrapvz/base/fs/partitionmaps/gpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def last_partition():
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())
data['boot'].get('mountopts', None), 'boot', last_partition())
if self.boot.previous is not None:
# No need to pad if this is the first partition
self.boot.pad_start += partition_gap
Expand All @@ -57,12 +57,23 @@ def last_partition():

self.root = GPTPartition(Sectors(data['root']['size'], sector_size),
data['root']['filesystem'], data['root'].get('format_command', None),
'root', last_partition())
data['root'].get('mountopts', None), 'root', last_partition())
if self.root.previous is not None:
self.root.pad_start += partition_gap
self.root.size -= partition_gap
self.partitions.append(self.root)

# Create all additional partitions
for partition in data:
if partition not in ["boot", "swap", "root", "type"] and not None:
part_tmp = GPTPartition(Sectors(data[partition]['size'], sector_size),
data[partition]['filesystem'], data[partition].get('format_command', None),
data[partition].get('mountopts', None), partition, last_partition())
part_tmp.pad_start += partition_gap
part_tmp.size -= partition_gap
setattr(self, partition, part_tmp)
self.partitions.append(part_tmp)

if hasattr(self, 'grub_boot'):
# Mark the grub partition as a bios_grub partition
self.grub_boot.flags.append('bios_grub')
Expand Down
12 changes: 10 additions & 2 deletions bootstrapvz/base/fs/partitionmaps/msdos.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from abstract import AbstractPartitionMap
from ..exceptions import PartitionError
from ..partitions.msdos import MSDOSPartition
from ..partitions.msdos_swap import MSDOSSwapPartition
from bootstrapvz.common.tools import log_check_call
Expand Down Expand Up @@ -28,7 +29,7 @@ def last_partition():
if 'boot' in data:
self.boot = MSDOSPartition(Sectors(data['boot']['size'], sector_size),
data['boot']['filesystem'], data['boot'].get('format_command', None),
last_partition())
data['boot'].get('mountopts', None), 'boot', last_partition())
self.partitions.append(self.boot)

# Offset all partitions by 1 sector.
Expand All @@ -46,12 +47,19 @@ def last_partition():

self.root = MSDOSPartition(Sectors(data['root']['size'], sector_size),
data['root']['filesystem'], data['root'].get('format_command', None),
last_partition())
data['root'].get('mountopts', None), 'root', last_partition())
if self.root.previous is not None:
self.root.pad_start += partition_gap
self.root.size -= partition_gap
self.partitions.append(self.root)

# Raise exception while trying to create additional partitions
# as its hard to calculate the actual size of the extended partition ATM
# And anyhow - we should go with GPT...
for partition in data:
if partition not in ["boot", "swap", "root", "type"]:
raise PartitionError("If you want to have additional partitions please use GPT partition scheme")

# Mark boot as the boot partition, or root, if boot does not exist
getattr(self, 'boot', self.root).flags.append('boot')

Expand Down
2 changes: 1 addition & 1 deletion bootstrapvz/base/fs/partitionmaps/none.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, data, sector_size, bootloader):

# In the NoPartitions partitions map we only have a single 'partition'
self.root = SinglePartition(Sectors(data['root']['size'], sector_size),
data['root']['filesystem'], data['root'].get('format_command', None))
data['root']['filesystem'], data['root'].get('format_command', None), data['root'].get('mount_opts', None))
self.partitions = [self.root]

def is_blocking(self):
Expand Down
11 changes: 9 additions & 2 deletions bootstrapvz/base/fs/partitions/abstract.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class AbstractPartition(FSMProxy):
{'name': 'unmount', 'src': 'mounted', 'dst': 'formatted'},
]

def __init__(self, size, filesystem, format_command):
def __init__(self, size, filesystem, format_command, mountopts):
"""
:param Bytes size: Size of the partition
:param str filesystem: Filesystem the partition should be formatted with
Expand All @@ -28,6 +28,8 @@ def __init__(self, size, filesystem, format_command):
self.size = size
self.filesystem = filesystem
self.format_command = format_command
# List of mount options
self.mountopts = mountopts
# 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)
Expand Down Expand Up @@ -80,7 +82,12 @@ def _before_format(self, e):
def _before_mount(self, e):
"""Mount the partition
"""
log_check_call(['mount', '--types', self.filesystem, self.device_path, e.destination])
if self.mountopts is None:
mount_command = ['mount', '--types', self.filesystem, self.device_path, e.destination]
else:
mount_command = ['mount', '--options', ",".join(self.mountopts), '--types', self.filesystem, self.device_path, e.destination]
# Mount the partition
log_check_call(mount_command)
self.mount_dir = e.destination

def _after_mount(self, e):
Expand Down
4 changes: 2 additions & 2 deletions bootstrapvz/base/fs/partitions/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class BasePartition(AbstractPartition):
{'name': 'unmap', 'src': 'mapped', 'dst': 'unmapped'},
]

def __init__(self, size, filesystem, format_command, previous):
def __init__(self, size, filesystem, format_command, mountopts, previous):
"""
:param Bytes size: Size of the partition
:param str filesystem: Filesystem the partition should be formatted with
Expand All @@ -34,7 +34,7 @@ def __init__(self, size, filesystem, format_command, previous):
self.flags = []
# Path to symlink in /dev/disk/by-uuid (manually maintained by this class)
self.disk_by_uuid_path = None
super(BasePartition, self).__init__(size, filesystem, format_command)
super(BasePartition, self).__init__(size, filesystem, format_command, mountopts)

def create(self, volume):
"""Creates the partition
Expand Down
4 changes: 2 additions & 2 deletions bootstrapvz/base/fs/partitions/gpt.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class GPTPartition(BasePartition):
"""Represents a GPT partition
"""

def __init__(self, size, filesystem, format_command, name, previous):
def __init__(self, size, filesystem, format_command, mountopts, name, previous):
"""
:param Bytes size: Size of the partition
:param str filesystem: Filesystem the partition should be formatted with
Expand All @@ -15,7 +15,7 @@ def __init__(self, size, filesystem, format_command, name, previous):
:param BasePartition previous: The partition that preceeds this one
"""
self.name = name
super(GPTPartition, self).__init__(size, filesystem, format_command, previous)
super(GPTPartition, self).__init__(size, filesystem, format_command, mountopts, previous)

def _before_create(self, e):
# Create the partition and then set the name of the partition afterwards
Expand Down
2 changes: 1 addition & 1 deletion bootstrapvz/base/fs/partitions/gpt_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self, size, previous):
:param Bytes size: Size of the partition
:param BasePartition previous: The partition that preceeds this one
"""
super(GPTSwapPartition, self).__init__(size, 'swap', None, 'swap', previous)
super(GPTSwapPartition, self).__init__(size, 'swap', None, None, 'swap', previous)

def _before_format(self, e):
log_check_call(['mkswap', self.device_path])
11 changes: 10 additions & 1 deletion bootstrapvz/base/fs/partitions/msdos.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,13 @@
class MSDOSPartition(BasePartition):
"""Represents an MS-DOS partition
"""
pass
def __init__(self, size, filesystem, format_command, mountopts, name, previous):
"""
: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
:param str name: The name of the partition
:param BasePartition previous: The partition that preceeds this one
"""
self.name = name
super(MSDOSPartition, self).__init__(size, filesystem, format_command, mountopts, previous)
2 changes: 1 addition & 1 deletion bootstrapvz/base/fs/partitions/msdos_swap.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def __init__(self, size, previous):
:param Bytes size: Size of the partition
:param BasePartition previous: The partition that preceeds this one
"""
super(MSDOSSwapPartition, self).__init__(size, 'swap', None, previous)
super(MSDOSSwapPartition, self).__init__(size, 'swap', None, None, 'swap', previous)

def _before_format(self, e):
log_check_call(['mkswap', self.device_path])
2 changes: 1 addition & 1 deletion bootstrapvz/base/fs/partitions/unformatted.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ def __init__(self, size, previous):
:param Bytes size: Size of the partition
:param BasePartition previous: The partition that preceeds this one
"""
super(UnformattedPartition, self).__init__(size, None, None, previous)
super(UnformattedPartition, self).__init__(size, None, None, None, previous)
12 changes: 8 additions & 4 deletions bootstrapvz/base/manifest-schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ definitions:
properties:
root: {$ref: '#/definitions/partition'}
type: {enum: [none]}
required: [root]
required: [type, root]
additionalProperties: false
partition:
type: object
Expand All @@ -164,21 +164,25 @@ definitions:
items: {type: string}
minItems: 1
type: array
mountopts:
items: {type: string}
minItems: 1
type: array
size: {$ref: '#/definitions/bytes'}
required: [size, filesystem]
additionalProperties: false
partition_table:
type: object
patternProperties:
^(?!type|swap).*: {$ref: '#/definitions/partition'}
properties:
boot: {$ref: '#/definitions/partition'}
root: {$ref: '#/definitions/partition'}
swap:
type: object
properties:
size: {$ref: '#/definitions/bytes'}
required: [size]
type: {enum: [msdos, gpt]}
required: [root]
required: [type, root]
additionalProperties: false
path:
type: string
Expand Down
1 change: 1 addition & 0 deletions bootstrapvz/common/task_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ def get_base_group(manifest):

mounting_group = [filesystem.CreateMountDir,
filesystem.MountRoot,
filesystem.MountAdditional,
filesystem.MountSpecials,
filesystem.CopyMountTable,
filesystem.RemoveMountTable,
Expand Down
47 changes: 46 additions & 1 deletion bootstrapvz/common/tasks/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,33 @@ def run(cls, info):
p_map.root.add_mount(p_map.boot, 'boot')


class MountAdditional(Task):
description = 'Mounting additional partitions'
phase = phases.volume_mounting
predecessors = [MountRoot]

@classmethod
def run(cls, info):
import os
from bootstrapvz.base.fs.partitions.unformatted import UnformattedPartition

def is_additional(partition):
return (not isinstance(partition, UnformattedPartition) and
partition.name not in ["boot", "swap", "root"])

p_map = info.volume.partition_map
partitions = p_map.partitions
for partition in sorted(
filter(is_additional, partitions),
key=lambda partition: len(partition.name)):
partition = getattr(p_map, partition.name)
os.makedirs(os.path.join(info.root, partition.name))
if partition.mountopts is None:
p_map.root.add_mount(getattr(p_map, partition.name), partition.name)
else:
p_map.root.add_mount(getattr(p_map, partition.name), partition.name, ['--options'] + partition.mountopts)


class MountSpecials(Task):
description = 'Mounting special block devices'
phase = phases.os_installation
Expand Down Expand Up @@ -165,7 +192,14 @@ class FStab(Task):
@classmethod
def run(cls, info):
import os.path
from bootstrapvz.base.fs.partitions.unformatted import UnformattedPartition

def is_additional(partition):
return (not isinstance(partition, UnformattedPartition) and
partition.name not in ["boot", "swap", "root"])

p_map = info.volume.partition_map
partitions = p_map.partitions
mount_points = [{'path': '/',
'partition': p_map.root,
'dump': '1',
Expand All @@ -184,10 +218,21 @@ def run(cls, info):
'pass_num': '0',
})

for partition in sorted(
filter(is_additional, partitions),
key=lambda partition: len(partition.name)):
mount_points.append({'path': "/" + partition.name,
'partition': getattr(p_map, partition.name),
'dump': '1',
'pass_num': '2',
})
fstab_lines = []
for mount_point in mount_points:
partition = mount_point['partition']
mount_opts = ['defaults']
if partition.mountopts is None:
mount_opts = ['defaults']
else:
mount_opts = partition.mountopts
fstab_lines.append('UUID={uuid} {mountpoint} {filesystem} {mount_opts} {dump} {pass_num}'
.format(uuid=partition.get_uuid(),
mountpoint=mount_point['path'],
Expand Down
16 changes: 14 additions & 2 deletions manifests/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -302,17 +302,29 @@ boot, root and swap.
- ``{fs}``: The filesystem of the partition.
- ``{device_path}``: The device path of the partition.
- ``{size}``: The size of the partition.
- ``{mount_opts}``: Options to mount the partition with. This optional
setting overwrites the default option list bootstrap-vz would
normally use to mount the partiton (defaults). The List is specified
as a string array where each option/argument is an item in that array.
``optional`` Here some examples:
- ``nodev``
- ``nosuid``
- ``noexec``
- ``journal_ioprio=3``

The default command used by boostrap-vz is
``['mkfs.{fs}', '{device_path}']``.

- ``boot``: Configuration of the boot partition. The three
settings equal those of the root partition.
- ``boot``: Configuration of the boot partition. All settings equal
those of the root partition.
``optional``
- ``swap``: Configuration of the swap partition. Since the swap
partition has its own filesystem you can only specify the size for
this partition.
``optional``
- ``additional_path``: Configuration of additional partitions. (e.g. /var/tmp)
All settings equal those of the root partition.


Example:

Expand Down
46 changes: 46 additions & 0 deletions manifests/examples/kvm/stretch-virtio-partitions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: debian-{system.release}-{system.architecture}-{%Y}{%m}{%d}
provider:
name: kvm
virtio_modules:
- virtio_pci
- virtio_blk
bootstrapper:
workspace: /target
system:
release: stretch
architecture: amd64
bootloader: grub
charmap: UTF-8
locale: en_US
timezone: UTC
volume:
backing: raw
partitions:
type: gpt
boot:
filesystem: ext2
size: 1GiB
swap:
size: 128MiB
root:
filesystem: ext4
size: 8GiB
tmp:
mountopts:
- nodev
- noexec
- nosuid
- journal_ioprio=3
filesystem: ext4
size: 1GiB
var:
filesystem: ext4
size: 1GiB
var/tmp:
filesystem: ext4
size: 1GiB

plugins:
root_password:
password: test

0 comments on commit a4e4ad9

Please sign in to comment.