From 0ed2365fd9cb523c2047dd5fa49fdcfb6c0fcb6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcus=20Sch=C3=A4fer?= Date: Tue, 18 Jul 2023 16:59:36 +0200 Subject: [PATCH] Add parent attribute to volume setup For the btrfs volume management, allow to put a volume into a specific parent volume. If not specified the volume is below the default volume This Fixes #2316 --- kiwi/mount_manager.py | 17 ++++++- kiwi/schema/kiwi.rnc | 8 ++++ kiwi/schema/kiwi.rng | 12 +++++ kiwi/volume_manager/btrfs.py | 41 +++++++++++++---- kiwi/xml_parse.py | 12 ++++- kiwi/xml_state.py | 6 +++ test/unit/mount_manager_test.py | 3 ++ test/unit/volume_manager/btrfs_test.py | 62 +++++++++++++++++--------- test/unit/volume_manager/lvm_test.py | 19 ++++---- test/unit/xml_state_test.py | 26 ++++++----- 10 files changed, 154 insertions(+), 52 deletions(-) diff --git a/kiwi/mount_manager.py b/kiwi/mount_manager.py index 8923ae21467..91397fd6f12 100644 --- a/kiwi/mount_manager.py +++ b/kiwi/mount_manager.py @@ -19,7 +19,9 @@ import time import logging from textwrap import dedent -from typing import List +from typing import ( + List, Dict +) # project from kiwi.path import Path @@ -41,9 +43,14 @@ class MountManager: * :param string device: device node name * :param string mountpoint: mountpoint directory name + * :param dict attributes: optional attributes to store """ - def __init__(self, device: str, mountpoint: str = ''): + def __init__( + self, device: str, mountpoint: str = '', + attributes: Dict[str, str] = {} + ): self.device = device + self.attributes = attributes if not mountpoint: self.mountpoint_tempdir = Temporary( prefix='kiwi_mount_manager.' @@ -53,6 +60,12 @@ def __init__(self, device: str, mountpoint: str = ''): Path.create(mountpoint) self.mountpoint = mountpoint + def get_attributes(self) -> Dict[str, str]: + """ + Return attributes dict for this mount manager + """ + return self.attributes + def bind_mount(self) -> None: """ Bind mount the device to the mountpoint diff --git a/kiwi/schema/kiwi.rnc b/kiwi/schema/kiwi.rnc index b9e380fa1c4..fcae7c00ba3 100644 --- a/kiwi/schema/kiwi.rnc +++ b/kiwi/schema/kiwi.rnc @@ -2564,6 +2564,13 @@ div { ## not specified the name specifies a path which has to ## exist inside the root directory. attribute name { text } + k.volume.parent.attribute = + ## The name/path of the parent volume. + ## Evaluated only for the btrfs volume manager to allow + ## specifying the parent subvolume to nest this volume in. + ## If not specified the parent is always the volume set + ## as the default volume + attribute parent { text } k.volume.mountpoint.attribute = ## volume path. The mountpoint specifies a path which has to ## exist inside the root directory. @@ -2596,6 +2603,7 @@ div { k.volume.mountpoint.attribute? & k.volume.label.attribute? & k.volume.name.attribute & + k.volume.parent.attribute? & k.volume.size.attribute? k.volume = ## Specify which parts of the filesystem should be diff --git a/kiwi/schema/kiwi.rng b/kiwi/schema/kiwi.rng index fdd34d41fce..9d1d9b9e6dd 100644 --- a/kiwi/schema/kiwi.rng +++ b/kiwi/schema/kiwi.rng @@ -3851,6 +3851,15 @@ not specified the name specifies a path which has to exist inside the root directory. + + + The name/path of the parent volume. +Evaluated only for the btrfs volume manager to allow +specifying the parent subvolume to nest this volume in. +If not specified the parent is always the volume set +as the default volume + + volume path. The mountpoint specifies a path which has to @@ -3907,6 +3916,9 @@ The latter is the default. + + + diff --git a/kiwi/volume_manager/btrfs.py b/kiwi/volume_manager/btrfs.py index 441e72e6b4e..5aa97856f2f 100644 --- a/kiwi/volume_manager/btrfs.py +++ b/kiwi/volume_manager/btrfs.py @@ -92,7 +92,6 @@ def post_init(self, custom_args): self.subvol_mount_list = [] self.toplevel_mount = None - self.toplevel_volume = None def setup(self, name=None): """ @@ -154,6 +153,7 @@ def setup(self, name=None): # Mount /{some-name}/.snapshots as /.snapshots inside the root snapshots_mount = MountManager( device=self.device, + attributes={'subvol': f'{self.root_volume_name}/.snapshots'}, mountpoint=snapshot + '/.snapshots' ) self.subvol_mount_list.append(snapshots_mount) @@ -191,6 +191,9 @@ def create_volumes(self, filesystem_name): else: log.info('--> sub volume %s', volume.realpath) toplevel = self.mountpoint + f'/{self.root_volume_name}/' + if volume.parent: + toplevel = self.mountpoint + '/' + volume.parent + volume_parent_path = os.path.normpath( toplevel + os.path.dirname(volume.realpath) ) @@ -207,12 +210,19 @@ def create_volumes(self, filesystem_name): ) volume_mountpoint = self.mountpoint + \ self.root_volume_name + '/' + attributes = { + 'parent': volume.parent or '' + } if self.custom_args['root_is_snapshot']: volume_mountpoint = self.mountpoint + \ f'/{self.root_volume_name}/.snapshots/1/snapshot/' + attributes = { + 'subvol': f'{self.root_volume_name}{volume.realpath}' + } volume_mount = MountManager( device=self.device, + attributes=attributes, mountpoint=os.path.normpath( volume_mountpoint + volume.realpath ) @@ -245,12 +255,17 @@ def get_fstab(self, persistency_type='by-label', filesystem_name=None): fs_check = self._is_volume_enabled_for_fs_check( volume_mount.mountpoint ) + mount_point = volume_mount.mountpoint.replace(self.mountpoint, '') + if self.root_volume_name != '/': + mount_point = mount_point.replace(self.root_volume_name, '') + + if self.custom_args['root_is_snapshot']: + mount_point = subvol_name.replace(self.root_volume_name, '') + fstab_entry = ' '.join( [ blkid_type + '=' + device_id, - subvol_name.replace( - self.root_volume_name, '' - ) if self.root_volume_name != '/' else subvol_name, + mount_point if mount_point.startswith(os.sep) else f'{os.sep}{mount_point}', 'btrfs', ','.join(mount_entry_options), '0 {fs_passno}'.format( fs_passno='2' if fs_check else '0' @@ -295,8 +310,11 @@ def mount_volumes(self): for volume_mount in self.subvol_mount_list: if self.volumes_mounted_initially: + toplevel = self.root_volume_name + if self.custom_args['root_is_snapshot']: + toplevel = f'{self.root_volume_name}/.snapshots/1/snapshot' volume_mount.mountpoint = os.path.normpath( - volume_mount.mountpoint.replace(self.toplevel_volume, '', 1) + volume_mount.mountpoint.replace(toplevel, '', 1) ) if not os.path.exists(volume_mount.mountpoint): Path.create(volume_mount.mountpoint) @@ -432,7 +450,6 @@ def _set_default_volume(self, default_volume): volume_id, self.mountpoint ] ) - self.toplevel_volume = default_volume return raise KiwiVolumeRootIDError( @@ -514,10 +531,16 @@ def _get_subvol_name_from_mountpoint(self, volume_mount): subvol_name = os.sep.join( volume_mount.mountpoint.split(os.sep)[path_start_index:] ) - if self.toplevel_volume and self.toplevel_volume in subvol_name: - subvol_name = subvol_name.replace(self.toplevel_volume, '') + parent = self.root_volume_name + if volume_mount.get_attributes().get('parent'): + parent = volume_mount.attributes.get('parent') + + if volume_mount.get_attributes().get('subvol'): + subvol_name = volume_mount.get_attributes().get('subvol') + parent = '' + return os.path.normpath( - os.sep.join([self.root_volume_name, subvol_name]).replace('//', '/') + os.sep.join([parent, subvol_name]).replace('//', '/').lstrip(os.sep) ) def __del__(self): diff --git a/kiwi/xml_parse.py b/kiwi/xml_parse.py index ffeb57ce8e1..693f1ec452e 100644 --- a/kiwi/xml_parse.py +++ b/kiwi/xml_parse.py @@ -4984,7 +4984,7 @@ class volume(GeneratedsSuper): """Specify which parts of the filesystem should be on an extra volume.""" subclass = None superclass = None - def __init__(self, copy_on_write=None, filesystem_check=None, freespace=None, mountpoint=None, label=None, name=None, size=None): + def __init__(self, copy_on_write=None, filesystem_check=None, freespace=None, mountpoint=None, label=None, name=None, parent=None, size=None): self.original_tagname_ = None self.copy_on_write = _cast(bool, copy_on_write) self.filesystem_check = _cast(bool, filesystem_check) @@ -4992,6 +4992,7 @@ def __init__(self, copy_on_write=None, filesystem_check=None, freespace=None, mo self.mountpoint = _cast(None, mountpoint) self.label = _cast(None, label) self.name = _cast(None, name) + self.parent = _cast(None, parent) self.size = _cast(None, size) def factory(*args_, **kwargs_): if CurrentSubclassModule_ is not None: @@ -5016,6 +5017,8 @@ def get_label(self): return self.label def set_label(self, label): self.label = label def get_name(self): return self.name def set_name(self, name): self.name = name + def get_parent(self): return self.parent + def set_parent(self, parent): self.parent = parent def get_size(self): return self.size def set_size(self, size): self.size = size def validate_volume_size_type(self, value): @@ -5071,6 +5074,9 @@ def exportAttributes(self, outfile, level, already_processed, namespaceprefix_=' if self.name is not None and 'name' not in already_processed: already_processed.add('name') outfile.write(' name=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.name), input_name='name')), )) + if self.parent is not None and 'parent' not in already_processed: + already_processed.add('parent') + outfile.write(' parent=%s' % (self.gds_encode(self.gds_format_string(quote_attrib(self.parent), input_name='parent')), )) if self.size is not None and 'size' not in already_processed: already_processed.add('size') outfile.write(' size=%s' % (quote_attrib(self.size), )) @@ -5120,6 +5126,10 @@ def buildAttributes(self, node, attrs, already_processed): if value is not None and 'name' not in already_processed: already_processed.add('name') self.name = value + value = find_attr_value_('parent', node) + if value is not None and 'parent' not in already_processed: + already_processed.add('parent') + self.parent = value value = find_attr_value_('size', node) if value is not None and 'size' not in already_processed: already_processed.add('size') diff --git a/kiwi/xml_state.py b/kiwi/xml_state.py index 5cce0004e0b..1f640a24ea6 100644 --- a/kiwi/xml_state.py +++ b/kiwi/xml_state.py @@ -67,6 +67,7 @@ volume_type = NamedTuple( 'volume_type', [ ('name', str), + ('parent', str), ('size', str), ('realpath', str), ('mountpoint', Optional[str]), @@ -1574,6 +1575,7 @@ def get_volumes(self) -> List[volume_type]: [ volume_type( name=volume_name, + parent=volume_parent, size=volume_size, realpath=path, mountpoint=path, @@ -1600,6 +1602,7 @@ def get_volumes(self) -> List[volume_type]: # volume setup for a full qualified volume with name and # mountpoint information. See below for exceptions name = volume.get_name() + parent = volume.get_parent() or '' mountpoint = volume.get_mountpoint() realpath = mountpoint size = volume.get_size() @@ -1667,6 +1670,7 @@ def get_volumes(self) -> List[volume_type]: volume_type_list.append( volume_type( name=name, + parent=parent, size=size, fullsize=fullsize, mountpoint=mountpoint, @@ -1694,6 +1698,7 @@ def get_volumes(self) -> List[volume_type]: volume_type_list.append( volume_type( name=root_volume_name, + parent='', size=size, fullsize=fullsize, mountpoint=None, @@ -1708,6 +1713,7 @@ def get_volumes(self) -> List[volume_type]: volume_type_list.append( volume_type( name=swap_name, + parent='', size='size:{0}'.format(swap_mbytes), fullsize=False, mountpoint=None, diff --git a/test/unit/mount_manager_test.py b/test/unit/mount_manager_test.py index c192c14bd30..f976f27d97a 100644 --- a/test/unit/mount_manager_test.py +++ b/test/unit/mount_manager_test.py @@ -25,6 +25,9 @@ def setup(self, mock_path_create): def setup_method(self, cls, mock_path_create): self.setup() + def test_get_attributes(self): + assert self.mount_manager.get_attributes() == {} + @patch('kiwi.mount_manager.Temporary') def test_setup_empty_mountpoint(self, mock_Temporary): mock_Temporary.return_value.new_dir.return_value.name = 'tmpdir' diff --git a/test/unit/volume_manager/btrfs_test.py b/test/unit/volume_manager/btrfs_test.py index 8ccbdf40b53..68bf919af11 100644 --- a/test/unit/volume_manager/btrfs_test.py +++ b/test/unit/volume_manager/btrfs_test.py @@ -27,22 +27,22 @@ def inject_fixtures(self, caplog): def setup(self, mock_path): self.volumes = [ volume_type( - name='@', size='freespace:100', realpath='/', + name='@', parent='', size='freespace:100', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ), volume_type( - name='etc', size='freespace:200', realpath='/etc', + name='etc', parent='', size='freespace:200', realpath='/etc', mountpoint='/etc', fullsize=False, label=None, attributes=[], is_root_volume=False ), volume_type( - name='myvol', size='size:500', realpath='/data', + name='myvol', parent='', size='size:500', realpath='/data', mountpoint='LVdata', fullsize=False, label=None, attributes=[], is_root_volume=False ), volume_type( - name='home', size=None, realpath='/home', + name='home', parent='', size=None, realpath='/home', mountpoint='/home', fullsize=True, label=None, attributes=[], is_root_volume=False ) @@ -60,6 +60,7 @@ def setup(self, mock_path): self.volume_manager = VolumeManagerBtrfs( self.device_map, 'root_dir', self.volumes ) + self.volume_manager.mountpoint = '/var/tmp/kiwi_volumes.XXX' @patch('os.path.exists') def setup_method(self, cls, mock_path): @@ -69,10 +70,10 @@ def test_post_init(self): self.volume_manager.post_init({'some-arg': 'some-val'}) assert self.volume_manager.custom_args['some-arg'] == 'some-val' - def test_post_init_root_is_snapshot_without_toplevel_volume(self): + def test_post_init_root_is_snapshot_without_root_volume(self): self.volume_manager.volumes = [ volume_type( - name='/', size='freespace:100', realpath='/', + name='/', parent='', size='freespace:100', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ) @@ -138,7 +139,11 @@ def test_setup_with_snapshot( assert mock_mount.call_args_list == [ call(device='/dev/storage', mountpoint='tmpdir'), - call(device='/dev/storage', mountpoint='tmpdir/@/.snapshots/1/snapshot/.snapshots') + call( + device='/dev/storage', + attributes={'subvol': '@/.snapshots'}, + mountpoint='tmpdir/@/.snapshots/1/snapshot/.snapshots' + ) ] toplevel_mount.mount.assert_called_once_with([]) assert mock_command.call_args_list == [ @@ -175,7 +180,7 @@ def test_setup_volume_id_not_detected( @patch('kiwi.volume_manager.btrfs.MountManager') @patch('kiwi.volume_manager.btrfs.Path.create') @patch('kiwi.volume_manager.base.VolumeManagerBase.apply_attributes_on_volume') - def test_create_volumes_no_toplevel_volume( + def test_create_volumes_no_root_volume( self, mock_attrs, mock_path, mock_mount, mock_command, mock_os_exists ): volume_mount = Mock() @@ -187,12 +192,12 @@ def test_create_volumes_no_toplevel_volume( self.volume_manager.root_volume_name = '/' self.volume_manager.volumes = [ volume_type( - name='/', size='freespace:100', realpath='/', + name='/', parent='', size='freespace:100', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ), volume_type( - name='home', size=None, realpath='/home', + name='home', parent='/', size=None, realpath='/home', mountpoint='/home', fullsize=True, label=None, attributes=[], is_root_volume=False ) @@ -208,7 +213,9 @@ def test_create_volumes_no_toplevel_volume( ['btrfs', 'subvolume', 'create', 'tmpdir/home'] ) mock_mount.assert_called_once_with( - device='/dev/storage', mountpoint='tmpdir/home' + device='/dev/storage', + attributes={'parent': '/'}, + mountpoint='tmpdir/home' ) @patch('os.path.exists') @@ -230,7 +237,7 @@ def test_create_volumes( assert mock_attrs.call_args_list == [ call( 'tmpdir/@/', volume_type( - name='myvol', size='size:500', realpath='/data', + name='myvol', parent='', size='size:500', realpath='/data', mountpoint='LVdata', fullsize=False, label=None, attributes=[], is_root_volume=False @@ -238,7 +245,7 @@ def test_create_volumes( ), call( 'tmpdir/@/', volume_type( - name='etc', size='freespace:200', realpath='/etc', + name='etc', parent='', size='freespace:200', realpath='/etc', mountpoint='/etc', fullsize=False, label=None, attributes=[], is_root_volume=False @@ -246,7 +253,7 @@ def test_create_volumes( ), call( 'tmpdir/@/', volume_type( - name='home', size=None, realpath='/home', + name='home', parent='', size=None, realpath='/home', mountpoint='/home', fullsize=True, label=None, attributes=[], is_root_volume=False @@ -269,15 +276,18 @@ def test_create_volumes( assert mock_mount.call_args_list == [ call( device='/dev/storage', - mountpoint='tmpdir/@/.snapshots/1/snapshot/data' + mountpoint='tmpdir/@/.snapshots/1/snapshot/data', + attributes={'subvol': '@/data'} ), call( device='/dev/storage', - mountpoint='tmpdir/@/.snapshots/1/snapshot/etc' + mountpoint='tmpdir/@/.snapshots/1/snapshot/etc', + attributes={'subvol': '@/etc'} ), call( device='/dev/storage', - mountpoint='tmpdir/@/.snapshots/1/snapshot/home' + mountpoint='tmpdir/@/.snapshots/1/snapshot/home', + attributes={'subvol': '@/home'} ) ] @@ -286,7 +296,9 @@ def test_get_volumes(self): volume_mount.mountpoint = \ '/var/tmp/kiwi_volumes.xx/@/.snapshots/1/snapshot/boot/grub2' volume_mount.device = 'device' - self.volume_manager.toplevel_volume = '@/.snapshots/1/snapshot' + volume_mount.get_attributes.return_value = { + 'subvol': '@/boot/grub2' + } self.volume_manager.subvol_mount_list = [volume_mount] self.volume_manager.custom_args['root_is_snapshot'] = True assert self.volume_manager.get_volumes() == { @@ -305,14 +317,19 @@ def test_get_fstab(self, mock_command): volume_mount.mountpoint = \ '/var/tmp/kiwi_volumes.XXX/@/.snapshots/1/snapshot/var/tmp' volume_mount.device = 'device' - self.volume_manager.toplevel_volume = '@/.snapshots/1/snapshot' + volume_mount.get_attributes.return_value = { + 'subvol': '@/var/tmp', + 'parent': 'subvol_takes_precedence' + } self.volume_manager.subvol_mount_list = [volume_mount] + self.volume_manager.custom_args['root_is_snapshot'] = True assert self.volume_manager.get_fstab() == [ 'LABEL=id /var/tmp btrfs defaults,subvol=@/var/tmp 0 0' ] self.volumes.append( volume_type( name='device', + parent='', size='freespace:100', realpath='/var/tmp', mountpoint=volume_mount.mountpoint, @@ -337,7 +354,9 @@ def test_mount_volumes(self, mock_path, mock_os_exists): volume_mount = Mock() volume_mount.mountpoint = \ '/var/tmp/kiwi_volumes.xx/@/.snapshots/1/snapshot/var/tmp' - self.volume_manager.toplevel_volume = '@/.snapshots/1/snapshot' + volume_mount.get_attributes.return_value = { + 'subvol': '@/var/tmp' + } self.volume_manager.custom_args['root_is_snapshot'] = True self.volume_manager.subvol_mount_list = [volume_mount] @@ -383,6 +402,9 @@ def test_remount_volumes( volume_mount = Mock() volume_mount.mountpoint = \ '/var/tmp/kiwi_volumes.xx/@/.snapshots/1/snapshot/var/tmp' + volume_mount.get_attributes.return_value = { + 'subvol': '@/var/tmp' + } self.volume_manager.subvol_mount_list = [volume_mount] self.volume_manager.mount_volumes() diff --git a/test/unit/volume_manager/lvm_test.py b/test/unit/volume_manager/lvm_test.py index 56168b77189..588339a82ad 100644 --- a/test/unit/volume_manager/lvm_test.py +++ b/test/unit/volume_manager/lvm_test.py @@ -22,27 +22,27 @@ def inject_fixtures(self, caplog): def setup(self, mock_path): self.volumes = [ volume_type( - name='LVRoot', size='freespace:100', realpath='/', + name='LVRoot', parent='', size='freespace:100', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ), volume_type( - name='LVSwap', size='size:100', realpath='swap', + name='LVSwap', parent='', size='size:100', realpath='swap', mountpoint=None, fullsize=False, label='SWAP', attributes=[], is_root_volume=False ), volume_type( - name='LVetc', size='freespace:200', realpath='/etc', + name='LVetc', parent='', size='freespace:200', realpath='/etc', mountpoint='/etc', fullsize=False, label='etc', attributes=[], is_root_volume=False ), volume_type( - name='myvol', size='size:500', realpath='/data', + name='myvol', parent='', size='size:500', realpath='/data', mountpoint='LVdata', fullsize=False, label=None, attributes=[], is_root_volume=False ), volume_type( - name='LVhome', size=None, realpath='/home', + name='LVhome', parent='', size=None, realpath='/home', mountpoint='/home', fullsize=True, label=None, attributes=[], is_root_volume=False ), @@ -178,28 +178,28 @@ def mock_os_exists_return(path): assert mock_attrs.call_args_list == [ call( 'root_dir', volume_type( - name='LVSwap', size='size:100', realpath='swap', + name='LVSwap', parent='', size='size:100', realpath='swap', mountpoint=None, fullsize=False, label='SWAP', attributes=[], is_root_volume=False ) ), call( 'root_dir', volume_type( - name='LVRoot', size='freespace:100', realpath='/', + name='LVRoot', parent='', size='freespace:100', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ) ), call( 'root_dir', volume_type( - name='myvol', size='size:500', realpath='/data', + name='myvol', parent='', size='size:500', realpath='/data', mountpoint='LVdata', fullsize=False, label=None, attributes=[], is_root_volume=False ) ), call( 'root_dir', volume_type( - name='LVetc', size='freespace:200', realpath='/etc', + name='LVetc', parent='', size='freespace:200', realpath='/etc', mountpoint='/etc', fullsize=False, label='etc', attributes=[], is_root_volume=False ) @@ -342,6 +342,7 @@ def test_get_fstab(self): self.volumes.append( volume_type( name='device', + parent='', size='freespace:100', realpath='/var/tmp', mountpoint=volume_mount.mountpoint, diff --git a/test/unit/xml_state_test.py b/test/unit/xml_state_test.py index 6b0e42bcbe3..dbc7fa0b574 100644 --- a/test/unit/xml_state_test.py +++ b/test/unit/xml_state_test.py @@ -386,6 +386,7 @@ def test_get_volumes_custom_root_volume_name(self): volume_type = namedtuple( 'volume_type', [ 'name', + 'parent', 'size', 'realpath', 'mountpoint', @@ -397,7 +398,7 @@ def test_get_volumes_custom_root_volume_name(self): ) assert state.get_volumes() == [ volume_type( - name='myroot', size='freespace:500', + name='myroot', parent='', size='freespace:500', realpath='/', mountpoint=None, fullsize=False, label=None, @@ -413,6 +414,7 @@ def test_get_volumes(self): volume_type = namedtuple( 'volume_type', [ 'name', + 'parent', 'size', 'realpath', 'mountpoint', @@ -424,7 +426,7 @@ def test_get_volumes(self): ) assert state.get_volumes() == [ volume_type( - name='usr_lib', size='size:1024', + name='usr_lib', parent='', size='size:1024', realpath='usr/lib', mountpoint='usr/lib', fullsize=False, @@ -433,7 +435,7 @@ def test_get_volumes(self): is_root_volume=False ), volume_type( - name='LVRoot', size='freespace:500', + name='LVRoot', parent='', size='freespace:500', realpath='/', mountpoint=None, fullsize=False, label=None, @@ -441,7 +443,7 @@ def test_get_volumes(self): is_root_volume=True ), volume_type( - name='etc_volume', size='freespace:30', + name='etc_volume', parent='', size='freespace:30', realpath='etc', mountpoint='etc', fullsize=False, label=None, @@ -449,7 +451,7 @@ def test_get_volumes(self): is_root_volume=False ), volume_type( - name='bin_volume', size=None, + name='bin_volume', parent='', size=None, realpath='/usr/bin', mountpoint='/usr/bin', fullsize=True, label=None, @@ -457,7 +459,7 @@ def test_get_volumes(self): is_root_volume=False ), volume_type( - name='LVSwap', size='size:128', + name='LVSwap', parent='', size='size:128', realpath='swap', mountpoint=None, fullsize=False, label='SWAP', @@ -473,6 +475,7 @@ def test_get_volumes_no_explicit_root_setup(self): volume_type = namedtuple( 'volume_type', [ 'name', + 'parent', 'size', 'realpath', 'mountpoint', @@ -484,14 +487,14 @@ def test_get_volumes_no_explicit_root_setup(self): ) assert state.get_volumes() == [ volume_type( - name='LVRoot', size=None, realpath='/', + name='LVRoot', parent='', size=None, realpath='/', mountpoint=None, fullsize=True, label=None, attributes=[], is_root_volume=True ), volume_type( - name='LVSwap', size='size:128', + name='LVSwap', parent='', size='size:128', realpath='swap', mountpoint=None, fullsize=False, label='SWAP', @@ -509,6 +512,7 @@ def test_get_volumes_no_explicit_root_setup_other_fullsize_volume(self): volume_type = namedtuple( 'volume_type', [ 'name', + 'parent', 'size', 'realpath', 'mountpoint', @@ -520,21 +524,21 @@ def test_get_volumes_no_explicit_root_setup_other_fullsize_volume(self): ) assert state.get_volumes() == [ volume_type( - name='usr', size=None, realpath='usr', + name='usr', parent='', size=None, realpath='usr', mountpoint='usr', fullsize=True, label=None, attributes=[], is_root_volume=False ), volume_type( - name='LVRoot', size='freespace:30', realpath='/', + name='LVRoot', parent='', size='freespace:30', realpath='/', mountpoint=None, fullsize=False, label=None, attributes=[], is_root_volume=True ), volume_type( - name='LVSwap', size='size:128', + name='LVSwap', parent='', size='size:128', realpath='swap', mountpoint=None, fullsize=False, label='SWAP',