From b35e7db0fde88bd9a1f8ef3eac2024c1183b202b Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Fri, 8 Dec 2023 08:50:20 +1300 Subject: [PATCH] Add san support to growvols In the san case the "disk" device will be of type "mpath", this change adds "mpath" to the allowed partition types to treat as the primary device. Full unit test coverage has been added using an actual mpath lsblk output to validate behaviour. Change-Id: Id593d32e64abdb2ce4b3fd2e43f89fe262d374d1 --- .../growvols/static/usr/local/sbin/growvols | 46 ++- .../elements/growvols/tests/test_growvols.py | 272 +++++++++++++++++- 2 files changed, 297 insertions(+), 21 deletions(-) diff --git a/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols b/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols index e677d8c8e..c05cdc45a 100755 --- a/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols +++ b/diskimage_builder/elements/growvols/static/usr/local/sbin/growvols @@ -258,14 +258,16 @@ def find_disk(opts, devices): break if device['TYPE'] == 'disk': break + if device['TYPE'] == 'mpath': + break if not device['PKNAME']: break if not device: raise Exception('Could not detect disk device') - if device['TYPE'] != 'disk': - raise Exception('Expected a device with TYPE="disk", got: %s' - % device['TYPE']) + if device['TYPE'] not in ('disk', 'mpath'): + raise Exception('Expected a device with TYPE="disk" or TYPE="mpath", ' + 'got: %s' % device['TYPE']) return device @@ -321,18 +323,34 @@ def find_group(opts): return vg_names.pop() -def find_next_partnum(devices, disk_name): - return len([d for d in devices if d['PKNAME'] == disk_name]) + 1 +def find_next_partnum(devices, disk): + if disk['TYPE'] == 'disk': + disk_name = disk['KNAME'] + return len([d for d in devices if d['PKNAME'] == disk_name]) + 1 + if disk['TYPE'] == 'mpath': + max_partnum = 0 + disk_name_length = len(disk['NAME']) + seen_devs = set() + for d in devices: + if d['PKNAME'] != disk['KNAME']: + continue + dev_name = d['NAME'] + if dev_name in seen_devs: + continue + seen_devs.add(dev_name) + max_partnum = max(max_partnum, int(dev_name[disk_name_length:])) + return max_partnum + 1 -def find_next_device_name(devices, disk_name, partnum): +def find_next_device_name(devices, disk, partnum): + disk_name = disk['NAME'] existing_partnum = partnum - 1 # try partition scheme for SATA etc, then NVMe for part_template in '%s%d', '%sp%d': part = part_template % (disk_name, existing_partnum) LOG.debug('Looking for device %s' % part) - if find_device(devices, 'KNAME', part): + if find_device(devices, 'NAME', part): return part_template % (disk_name, partnum) raise Exception('Could not find partition naming scheme for %s' @@ -520,8 +538,8 @@ def main(argv): return 0 group = find_group(opts) - partnum = find_next_partnum(devices, disk_name) - devname = find_next_device_name(devices, disk_name, partnum) + partnum = find_next_partnum(devices, disk) + devname = find_next_device_name(devices, disk, partnum) thin_pool, thin_pool_name = find_thin_pool(devices, group) if thin_pool: # reserve for the size of the metadata volume @@ -533,7 +551,10 @@ def main(argv): size_bytes -= size_bytes % PHYSICAL_EXTENT_BYTES # reduce for metadata overhead size_bytes -= PHYSICAL_EXTENT_BYTES - dev_path = '/dev/%s' % devname + if disk['TYPE'] == 'mpath': + dev_path = '/dev/mapper/%s' % devname + else: + dev_path = '/dev/%s' % devname grow_vols = find_grow_vols(opts, devices, group, size_bytes) commands = [] @@ -545,6 +566,11 @@ def main(argv): '/dev/%s' % disk_name ], 'Create new partition %s' % devname)) + if disk['TYPE'] == 'mpath': + commands.append(Command( + ['multipath', '-r'], + 'Force a reload of all existing multipath maps')) + commands.append(Command( ['partprobe'], 'Inform the OS of partition table changes')) diff --git a/diskimage_builder/elements/growvols/tests/test_growvols.py b/diskimage_builder/elements/growvols/tests/test_growvols.py index 5817b6def..e60d54477 100644 --- a/diskimage_builder/elements/growvols/tests/test_growvols.py +++ b/diskimage_builder/elements/growvols/tests/test_growvols.py @@ -32,6 +32,117 @@ KNAME="dm-2" PKNAME="sda3" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xf KNAME="dm-3" PKNAME="sda3" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" """ # noqa +# output of multipath lsblk +LSBLK_MULTIPATH = """KNAME="sda" PKNAME="" NAME="sda" LABEL="" TYPE="disk" FSTYPE="mpath_member" MOUNTPOINT="" +KNAME="dm-0" PKNAME="sda" NAME="mpatha" LABEL="" TYPE="mpath" FSTYPE="" MOUNTPOINT="" +KNAME="dm-1" PKNAME="dm-0" NAME="mpatha1" LABEL="MKFS_ESP" TYPE="part" FSTYPE="vfat" MOUNTPOINT="/boot/efi" +KNAME="dm-2" PKNAME="dm-0" NAME="mpatha2" LABEL="" TYPE="part" FSTYPE="" MOUNTPOINT="" +KNAME="dm-3" PKNAME="dm-0" NAME="mpatha3" LABEL="mkfs_boot" TYPE="part" FSTYPE="ext4" MOUNTPOINT="/boot" +KNAME="dm-4" PKNAME="dm-0" NAME="mpatha4" LABEL="" TYPE="part" FSTYPE="LVM2_member" MOUNTPOINT="" +KNAME="dm-6" PKNAME="dm-4" NAME="vg-lv_thinpool_tmeta" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-6" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-7" PKNAME="dm-4" NAME="vg-lv_thinpool_tdata" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-7" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-5" PKNAME="dm-0" NAME="mpatha5" LABEL="config-2" TYPE="part" FSTYPE="iso9660" MOUNTPOINT="" +KNAME="sdb" PKNAME="" NAME="sdb" LABEL="" TYPE="disk" FSTYPE="mpath_member" MOUNTPOINT="" +KNAME="dm-0" PKNAME="sdb" NAME="mpatha" LABEL="" TYPE="mpath" FSTYPE="" MOUNTPOINT="" +KNAME="dm-1" PKNAME="dm-0" NAME="mpatha1" LABEL="MKFS_ESP" TYPE="part" FSTYPE="vfat" MOUNTPOINT="/boot/efi" +KNAME="dm-2" PKNAME="dm-0" NAME="mpatha2" LABEL="" TYPE="part" FSTYPE="" MOUNTPOINT="" +KNAME="dm-3" PKNAME="dm-0" NAME="mpatha3" LABEL="mkfs_boot" TYPE="part" FSTYPE="ext4" MOUNTPOINT="/boot" +KNAME="dm-4" PKNAME="dm-0" NAME="mpatha4" LABEL="" TYPE="part" FSTYPE="LVM2_member" MOUNTPOINT="" +KNAME="dm-6" PKNAME="dm-4" NAME="vg-lv_thinpool_tmeta" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-6" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-7" PKNAME="dm-4" NAME="vg-lv_thinpool_tdata" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-7" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-5" PKNAME="dm-0" NAME="mpatha5" LABEL="config-2" TYPE="part" FSTYPE="iso9660" MOUNTPOINT="" +KNAME="sdc" PKNAME="" NAME="sdc" LABEL="" TYPE="disk" FSTYPE="mpath_member" MOUNTPOINT="" +KNAME="dm-0" PKNAME="sdc" NAME="mpatha" LABEL="" TYPE="mpath" FSTYPE="" MOUNTPOINT="" +KNAME="dm-1" PKNAME="dm-0" NAME="mpatha1" LABEL="MKFS_ESP" TYPE="part" FSTYPE="vfat" MOUNTPOINT="/boot/efi" +KNAME="dm-2" PKNAME="dm-0" NAME="mpatha2" LABEL="" TYPE="part" FSTYPE="" MOUNTPOINT="" +KNAME="dm-3" PKNAME="dm-0" NAME="mpatha3" LABEL="mkfs_boot" TYPE="part" FSTYPE="ext4" MOUNTPOINT="/boot" +KNAME="dm-4" PKNAME="dm-0" NAME="mpatha4" LABEL="" TYPE="part" FSTYPE="LVM2_member" MOUNTPOINT="" +KNAME="dm-6" PKNAME="dm-4" NAME="vg-lv_thinpool_tmeta" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-6" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-7" PKNAME="dm-4" NAME="vg-lv_thinpool_tdata" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-7" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-5" PKNAME="dm-0" NAME="mpatha5" LABEL="config-2" TYPE="part" FSTYPE="iso9660" MOUNTPOINT="" +KNAME="sdd" PKNAME="" NAME="sdd" LABEL="" TYPE="disk" FSTYPE="mpath_member" MOUNTPOINT="" +KNAME="dm-0" PKNAME="sdd" NAME="mpatha" LABEL="" TYPE="mpath" FSTYPE="" MOUNTPOINT="" +KNAME="dm-1" PKNAME="dm-0" NAME="mpatha1" LABEL="MKFS_ESP" TYPE="part" FSTYPE="vfat" MOUNTPOINT="/boot/efi" +KNAME="dm-2" PKNAME="dm-0" NAME="mpatha2" LABEL="" TYPE="part" FSTYPE="" MOUNTPOINT="" +KNAME="dm-3" PKNAME="dm-0" NAME="mpatha3" LABEL="mkfs_boot" TYPE="part" FSTYPE="ext4" MOUNTPOINT="/boot" +KNAME="dm-4" PKNAME="dm-0" NAME="mpatha4" LABEL="" TYPE="part" FSTYPE="LVM2_member" MOUNTPOINT="" +KNAME="dm-6" PKNAME="dm-4" NAME="vg-lv_thinpool_tmeta" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-6" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-7" PKNAME="dm-4" NAME="vg-lv_thinpool_tdata" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-8" PKNAME="dm-7" NAME="vg-lv_thinpool-tpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-9" PKNAME="dm-8" NAME="vg-lv_thinpool" LABEL="" TYPE="lvm" FSTYPE="" MOUNTPOINT="" +KNAME="dm-10" PKNAME="dm-8" NAME="vg-lv_root" LABEL="img-rootfs" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/" +KNAME="dm-11" PKNAME="dm-8" NAME="vg-lv_tmp" LABEL="fs_tmp" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/tmp" +KNAME="dm-12" PKNAME="dm-8" NAME="vg-lv_var" LABEL="fs_var" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var" +KNAME="dm-13" PKNAME="dm-8" NAME="vg-lv_log" LABEL="fs_log" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log" +KNAME="dm-14" PKNAME="dm-8" NAME="vg-lv_audit" LABEL="fs_audit" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/var/log/audit" +KNAME="dm-15" PKNAME="dm-8" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home" +KNAME="dm-16" PKNAME="dm-8" NAME="vg-lv_srv" LABEL="fs_srv" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/srv" +KNAME="dm-5" PKNAME="dm-0" NAME="mpatha5" LABEL="config-2" TYPE="part" FSTYPE="iso9660" MOUNTPOINT="" +""" # noqa + DEVICES = [{ "FSTYPE": "", "KNAME": "sda", @@ -180,6 +291,10 @@ class TestGrowvols(base.BaseTestCase): devices = list(growvols.parse_shell_vars(LSBLK)) self.assertEqual(DEVICES, devices) + def test_parse_shell_vars_multipath(self): + devices = list(growvols.parse_shell_vars(LSBLK_MULTIPATH)) + self.assertEqual(108, len(devices)) + def test_find_device(self): sda = { "FSTYPE": "", @@ -213,6 +328,22 @@ class TestGrowvols(base.BaseTestCase): growvols.find_device( DEVICES, ['KNAME', 'NAME'], 'asdf')) + def test_find_device_multipath(self): + mpatha = { + 'FSTYPE': '', + 'KNAME': 'dm-0', + 'LABEL': '', + 'MOUNTPOINT': '', + 'NAME': 'mpatha', + 'PKNAME': 'sda', + 'TYPE': 'mpath' + } + devices = list(growvols.parse_shell_vars(LSBLK_MULTIPATH)) + self.assertEqual( + mpatha, + growvols.find_device( + devices, ['KNAME', 'NAME'], 'mpatha')) + def test_find_disk(self): devices = list(growvols.parse_shell_vars(LSBLK)) opts = mock.Mock() @@ -242,7 +373,8 @@ class TestGrowvols(base.BaseTestCase): sda['TYPE'] = 'dissed' opts.device = 'sda' e = self.assertRaises(Exception, growvols.find_disk, opts, devices) - self.assertEqual('Expected a device with TYPE="disk", got: dissed', + self.assertEqual('Expected a device with TYPE="disk" or TYPE="mpath"' + ', got: dissed', str(e)) @mock.patch('growvols.execute') @@ -298,30 +430,91 @@ class TestGrowvols(base.BaseTestCase): self.assertEqual('Could not find specified --group: novg', str(e)) def test_find_next_partnum(self): - self.assertEqual(5, growvols.find_next_partnum(DEVICES, 'sda')) - self.assertEqual(1, growvols.find_next_partnum(DEVICES, 'sdb')) + opts = mock.Mock() + opts.device = None + disk = growvols.find_disk(opts, DEVICES) + self.assertEqual(5, growvols.find_next_partnum(DEVICES, disk)) + disk = { + "FSTYPE": "", + "KNAME": "sdb", + "LABEL": "", + "MOUNTPOINT": "", + "NAME": "sdb", + "PKNAME": "", + "TYPE": "disk", + } + self.assertEqual(1, growvols.find_next_partnum(DEVICES, disk)) + + def test_find_next_partnum_multipath(self): + opts = mock.Mock() + opts.device = 'mpatha' + devices = list(growvols.parse_shell_vars(LSBLK_MULTIPATH)) + disk = growvols.find_disk(opts, devices) + self.assertEqual(6, growvols.find_next_partnum(devices, disk)) def test_find_next_device_name(self): devices = list(growvols.parse_shell_vars(LSBLK)) - + disk = { + "FSTYPE": "", + "KNAME": "sda", + "LABEL": "", + "MOUNTPOINT": "", + "NAME": "sda", + "PKNAME": "", + "TYPE": "disk", + } # Use SATA etc device naming self.assertEqual( 'sda5', - growvols.find_next_device_name(devices, 'sda', 5)) + growvols.find_next_device_name(devices, disk, 5)) + def test_find_next_device_name_no_partitions(self): + devices = list(growvols.parse_shell_vars(LSBLK)) + disk_no_partitions = { + "FSTYPE": "", + "KNAME": "sdb", + "LABEL": "", + "MOUNTPOINT": "", + "NAME": "sdb", + "PKNAME": "", + "TYPE": "disk", + } # No partitions e = self.assertRaises(Exception, growvols.find_next_device_name, - devices, 'sdb', 1) + devices, disk_no_partitions, 1) self.assertEqual( 'Could not find partition naming scheme for sdb', str(e)) + def test_find_next_device_name_nvme(self): + devices = list(growvols.parse_shell_vars(LSBLK)) + disk = { + "FSTYPE": "", + "KNAME": "nvme0", + "LABEL": "", + "MOUNTPOINT": "", + "NAME": "nvme0", + "PKNAME": "", + "TYPE": "disk", + } # Use NVMe device naming for i in (1, 2, 3, 4): d = growvols.find_device(devices, 'KNAME', 'sda%s' % i) d['KNAME'] = 'nvme0p%s' % i + d['NAME'] = 'nvme0p%s' % i self.assertEqual( 'nvme0p5', - growvols.find_next_device_name(devices, 'nvme0', 5)) + growvols.find_next_device_name(devices, disk, 5)) + + def test_find_next_device_name_multipath(self): + opts = mock.Mock() + opts.device = 'mpatha' + devices = list(growvols.parse_shell_vars(LSBLK_MULTIPATH)) + disk = growvols.find_disk(opts, devices) + + # Use dm device naming + self.assertEqual( + 'mpatha6', + growvols.find_next_device_name(devices, disk, 6)) def test_amount_unit_to_extent(self): one_m = growvols.UNIT_BYTES['MiB'] @@ -431,9 +624,17 @@ class TestGrowvols(base.BaseTestCase): @mock.patch('growvols.execute') def test_find_thin_pool(self, mock_execute): + self._find_thin_pool(mock_execute, DEVICES) + + @mock.patch('growvols.execute') + def test_find_thin_pool_multipath(self, mock_execute): + devices = list(growvols.parse_shell_vars(LSBLK_MULTIPATH)) + self._find_thin_pool(mock_execute, devices) + + def _find_thin_pool(self, mock_execute, devices): # No thin pool mock_execute.return_value = LVS - self.assertEqual((None, None), growvols.find_thin_pool(DEVICES, 'vg')) + self.assertEqual((None, None), growvols.find_thin_pool(devices, 'vg')) mock_execute.assert_called_once_with([ 'lvs', '--noheadings', '--options', 'lv_name,lv_dm_path,lv_attr,pool_lv']) @@ -441,7 +642,7 @@ class TestGrowvols(base.BaseTestCase): # One thin pool, all volumes use it mock_execute.return_value = LVS_THIN self.assertEqual(('/dev/mapper/vg-lv_thinpool', 'lv_thinpool'), - growvols.find_thin_pool(DEVICES, 'vg')) + growvols.find_thin_pool(devices, 'vg')) # One pool, not used by all volumes mock_execute.return_value = ''' @@ -449,7 +650,7 @@ class TestGrowvols(base.BaseTestCase): lv_home /dev/mapper/vg-lv_home Vwi-aotz-- lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thinpool''' e = self.assertRaises(Exception, growvols.find_thin_pool, - DEVICES, 'vg') + devices, 'vg') self.assertEqual('All volumes need to be in pool lv_thinpool. ' 'lv_home is in pool None', str(e)) @@ -460,7 +661,7 @@ class TestGrowvols(base.BaseTestCase): lv_home /dev/mapper/vg-lv_home Vwi-aotz-- lv_thin2 lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thin1''' e = self.assertRaises(Exception, growvols.find_thin_pool, - DEVICES, 'vg') + devices, 'vg') self.assertEqual('All volumes need to be in pool lv_thin1. ' 'lv_home is in pool lv_thin2', str(e)) @@ -634,3 +835,52 @@ class TestGrowvols(base.BaseTestCase): mock.call(['xfs_growfs', '/dev/mapper/vg-lv_var']), mock.call(['xfs_growfs', '/dev/mapper/vg-lv_root']), ]) + + @mock.patch('growvols.find_sector_size') + @mock.patch('growvols.execute') + def test_main_thin_provision_multipath(self, mock_execute, + mock_sector_size): + mock_sector_size.return_value = 512 + + # assign to /home, /var, remainder to / + mock_execute.reset_mock() + mock_execute.side_effect = [ + LSBLK_MULTIPATH, + '', + SGDISK_LARGEST, + VGS, + LVS_THIN, + '', '', '', '', '', '', '', '', '', '', '', '', '' + ] + growvols.main(['growvols', '--yes', '--device', 'mpatha', + '--group', 'vg', + '/home=20%', 'fs_var=40%']) + mock_execute.assert_has_calls([ + mock.call(['lsblk', '-Po', + 'kname,pkname,name,label,type,fstype,mountpoint']), + mock.call(['sgdisk', '-v', '/dev/dm-0']), + mock.call(['sgdisk', '--first-aligned-in-largest', + '--end-of-largest', '/dev/dm-0']), + mock.call(['vgs', '--noheadings', '--options', 'vg_name']), + mock.call(['lvs', '--noheadings', '--options', + 'lv_name,lv_dm_path,lv_attr,pool_lv']), + mock.call(['sgdisk', '--new=6:79267840:488265727', + '--change-name=6:growvols', '/dev/dm-0']), + mock.call(['multipath', '-r']), + mock.call(['partprobe']), + mock.call(['pvcreate', '/dev/mapper/mpatha6']), + mock.call(['vgextend', 'vg', '/dev/mapper/mpatha6']), + mock.call(['lvextend', '--poolmetadatasize', '+1073741824B', + 'vg/lv_thinpool']), + mock.call(['lvextend', '-L+207253143552B', + '/dev/mapper/vg-lv_thinpool', '/dev/mapper/mpatha6']), + mock.call(['lvextend', '--size', '+41448112128B', + '/dev/mapper/vg-lv_home']), + mock.call(['lvextend', '--size', '+82900418560B', + '/dev/mapper/vg-lv_var']), + mock.call(['lvextend', '--size', '+82904612864B', + '/dev/mapper/vg-lv_root']), + mock.call(['xfs_growfs', '/dev/mapper/vg-lv_home']), + mock.call(['xfs_growfs', '/dev/mapper/vg-lv_var']), + mock.call(['xfs_growfs', '/dev/mapper/vg-lv_root']), + ])