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
This commit is contained in:
Steve Baker 2023-12-08 08:50:20 +13:00
parent 14754b21a4
commit b35e7db0fd
2 changed files with 297 additions and 21 deletions

View File

@ -258,14 +258,16 @@ def find_disk(opts, devices):
break break
if device['TYPE'] == 'disk': if device['TYPE'] == 'disk':
break break
if device['TYPE'] == 'mpath':
break
if not device['PKNAME']: if not device['PKNAME']:
break break
if not device: if not device:
raise Exception('Could not detect disk device') raise Exception('Could not detect disk device')
if device['TYPE'] != 'disk': if device['TYPE'] not in ('disk', 'mpath'):
raise Exception('Expected a device with TYPE="disk", got: %s' raise Exception('Expected a device with TYPE="disk" or TYPE="mpath", '
% device['TYPE']) 'got: %s' % device['TYPE'])
return device return device
@ -321,18 +323,34 @@ def find_group(opts):
return vg_names.pop() return vg_names.pop()
def find_next_partnum(devices, disk_name): def find_next_partnum(devices, disk):
return len([d for d in devices if d['PKNAME'] == disk_name]) + 1 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 existing_partnum = partnum - 1
# try partition scheme for SATA etc, then NVMe # try partition scheme for SATA etc, then NVMe
for part_template in '%s%d', '%sp%d': for part_template in '%s%d', '%sp%d':
part = part_template % (disk_name, existing_partnum) part = part_template % (disk_name, existing_partnum)
LOG.debug('Looking for device %s' % part) 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) return part_template % (disk_name, partnum)
raise Exception('Could not find partition naming scheme for %s' raise Exception('Could not find partition naming scheme for %s'
@ -520,8 +538,8 @@ def main(argv):
return 0 return 0
group = find_group(opts) group = find_group(opts)
partnum = find_next_partnum(devices, disk_name) partnum = find_next_partnum(devices, disk)
devname = find_next_device_name(devices, disk_name, partnum) devname = find_next_device_name(devices, disk, partnum)
thin_pool, thin_pool_name = find_thin_pool(devices, group) thin_pool, thin_pool_name = find_thin_pool(devices, group)
if thin_pool: if thin_pool:
# reserve for the size of the metadata volume # reserve for the size of the metadata volume
@ -533,7 +551,10 @@ def main(argv):
size_bytes -= size_bytes % PHYSICAL_EXTENT_BYTES size_bytes -= size_bytes % PHYSICAL_EXTENT_BYTES
# reduce for metadata overhead # reduce for metadata overhead
size_bytes -= PHYSICAL_EXTENT_BYTES 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) grow_vols = find_grow_vols(opts, devices, group, size_bytes)
commands = [] commands = []
@ -545,6 +566,11 @@ def main(argv):
'/dev/%s' % disk_name '/dev/%s' % disk_name
], 'Create new partition %s' % devname)) ], '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( commands.append(Command(
['partprobe'], ['partprobe'],
'Inform the OS of partition table changes')) 'Inform the OS of partition table changes'))

View File

@ -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" KNAME="dm-3" PKNAME="sda3" NAME="vg-lv_home" LABEL="fs_home" TYPE="lvm" FSTYPE="xfs" MOUNTPOINT="/home"
""" # noqa """ # 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 = [{ DEVICES = [{
"FSTYPE": "", "FSTYPE": "",
"KNAME": "sda", "KNAME": "sda",
@ -180,6 +291,10 @@ class TestGrowvols(base.BaseTestCase):
devices = list(growvols.parse_shell_vars(LSBLK)) devices = list(growvols.parse_shell_vars(LSBLK))
self.assertEqual(DEVICES, devices) 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): def test_find_device(self):
sda = { sda = {
"FSTYPE": "", "FSTYPE": "",
@ -213,6 +328,22 @@ class TestGrowvols(base.BaseTestCase):
growvols.find_device( growvols.find_device(
DEVICES, ['KNAME', 'NAME'], 'asdf')) 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): def test_find_disk(self):
devices = list(growvols.parse_shell_vars(LSBLK)) devices = list(growvols.parse_shell_vars(LSBLK))
opts = mock.Mock() opts = mock.Mock()
@ -242,7 +373,8 @@ class TestGrowvols(base.BaseTestCase):
sda['TYPE'] = 'dissed' sda['TYPE'] = 'dissed'
opts.device = 'sda' opts.device = 'sda'
e = self.assertRaises(Exception, growvols.find_disk, opts, devices) 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)) str(e))
@mock.patch('growvols.execute') @mock.patch('growvols.execute')
@ -298,30 +430,91 @@ class TestGrowvols(base.BaseTestCase):
self.assertEqual('Could not find specified --group: novg', str(e)) self.assertEqual('Could not find specified --group: novg', str(e))
def test_find_next_partnum(self): def test_find_next_partnum(self):
self.assertEqual(5, growvols.find_next_partnum(DEVICES, 'sda')) opts = mock.Mock()
self.assertEqual(1, growvols.find_next_partnum(DEVICES, 'sdb')) 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): def test_find_next_device_name(self):
devices = list(growvols.parse_shell_vars(LSBLK)) devices = list(growvols.parse_shell_vars(LSBLK))
disk = {
"FSTYPE": "",
"KNAME": "sda",
"LABEL": "",
"MOUNTPOINT": "",
"NAME": "sda",
"PKNAME": "",
"TYPE": "disk",
}
# Use SATA etc device naming # Use SATA etc device naming
self.assertEqual( self.assertEqual(
'sda5', '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 # No partitions
e = self.assertRaises(Exception, growvols.find_next_device_name, e = self.assertRaises(Exception, growvols.find_next_device_name,
devices, 'sdb', 1) devices, disk_no_partitions, 1)
self.assertEqual( self.assertEqual(
'Could not find partition naming scheme for sdb', str(e)) '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 # Use NVMe device naming
for i in (1, 2, 3, 4): for i in (1, 2, 3, 4):
d = growvols.find_device(devices, 'KNAME', 'sda%s' % i) d = growvols.find_device(devices, 'KNAME', 'sda%s' % i)
d['KNAME'] = 'nvme0p%s' % i d['KNAME'] = 'nvme0p%s' % i
d['NAME'] = 'nvme0p%s' % i
self.assertEqual( self.assertEqual(
'nvme0p5', '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): def test_amount_unit_to_extent(self):
one_m = growvols.UNIT_BYTES['MiB'] one_m = growvols.UNIT_BYTES['MiB']
@ -431,9 +624,17 @@ class TestGrowvols(base.BaseTestCase):
@mock.patch('growvols.execute') @mock.patch('growvols.execute')
def test_find_thin_pool(self, mock_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 # No thin pool
mock_execute.return_value = LVS 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([ mock_execute.assert_called_once_with([
'lvs', '--noheadings', '--options', 'lvs', '--noheadings', '--options',
'lv_name,lv_dm_path,lv_attr,pool_lv']) 'lv_name,lv_dm_path,lv_attr,pool_lv'])
@ -441,7 +642,7 @@ class TestGrowvols(base.BaseTestCase):
# One thin pool, all volumes use it # One thin pool, all volumes use it
mock_execute.return_value = LVS_THIN mock_execute.return_value = LVS_THIN
self.assertEqual(('/dev/mapper/vg-lv_thinpool', 'lv_thinpool'), 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 # One pool, not used by all volumes
mock_execute.return_value = ''' mock_execute.return_value = '''
@ -449,7 +650,7 @@ class TestGrowvols(base.BaseTestCase):
lv_home /dev/mapper/vg-lv_home Vwi-aotz-- lv_home /dev/mapper/vg-lv_home Vwi-aotz--
lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thinpool''' lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thinpool'''
e = self.assertRaises(Exception, growvols.find_thin_pool, e = self.assertRaises(Exception, growvols.find_thin_pool,
DEVICES, 'vg') devices, 'vg')
self.assertEqual('All volumes need to be in pool lv_thinpool. ' self.assertEqual('All volumes need to be in pool lv_thinpool. '
'lv_home is in pool None', str(e)) '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_home /dev/mapper/vg-lv_home Vwi-aotz-- lv_thin2
lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thin1''' lv_root /dev/mapper/vg-lv_root Vwi-aotz-- lv_thin1'''
e = self.assertRaises(Exception, growvols.find_thin_pool, e = self.assertRaises(Exception, growvols.find_thin_pool,
DEVICES, 'vg') devices, 'vg')
self.assertEqual('All volumes need to be in pool lv_thin1. ' self.assertEqual('All volumes need to be in pool lv_thin1. '
'lv_home is in pool lv_thin2', str(e)) '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_var']),
mock.call(['xfs_growfs', '/dev/mapper/vg-lv_root']), 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']),
])