Adds software raid creation support on nvme drives.

Change-Id: Ia725fcaee6018255af3dd7ff0eb2fb1cfbd2b322
Story: #2006341
Task: #36091
This commit is contained in:
Raphael Glon 2019-08-06 11:18:29 +02:00
parent 248a4ccda5
commit 570584f9ab
3 changed files with 135 additions and 5 deletions

View File

@ -1454,6 +1454,15 @@ class GenericHardwareManager(HardwareManager):
utils.execute('parted', device.name, '-s', '-a',
'optimal', '--', 'mkpart', 'primary',
sector, psize)
# Necessary, if we want to avoid hitting
# an error when creating the mdadm array below
# 'mdadm: cannot open /dev/nvme1n1p1: No such file
# or directory'.
# The real difference between partx and partprobe is
# unclear, but note that partprobe does not seem to
# work synchronously for nvme drives...
utils.execute("partx", "-u", device.name,
check_exit_code=False)
except processutils.ProcessExecutionError as e:
msg = "Failed to create partitions on {}: {}".format(
device.name, e)
@ -1464,8 +1473,14 @@ class GenericHardwareManager(HardwareManager):
raid_device_count = len(block_devices)
for index, logical_disk in enumerate(logical_disks):
md_device = '/dev/md%d' % index
component_devices = [device.name + str(index + 1)
for device in block_devices]
component_devices = []
for device in block_devices:
# The partition delimiter for all common harddrives (sd[a-z]+)
part_delimiter = ''
if 'nvme' in device.name:
part_delimiter = 'p'
component_devices.append(
device.name + part_delimiter + str(index + 1))
raid_level = logical_disk['raid_level']
# The schema check allows '1+0', but mdadm knows it as '10'.
if raid_level == '1+0':

View File

@ -2594,12 +2594,16 @@ class TestGenericHardwareManager(base.IronicAgentTest):
mock.call('parted', '/dev/sdb', '-s', '--', 'mklabel', 'msdos'),
mock.call('parted', '/dev/sda', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', '2048s', 102400),
mock.call('partx', '-u', '/dev/sda', check_exit_code=False),
mock.call('parted', '/dev/sdb', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', '2048s', 102400),
mock.call('partx', '-u', '/dev/sdb', check_exit_code=False),
mock.call('parted', '/dev/sda', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', 102400, '-1'),
mock.call('partx', '-u', '/dev/sda', check_exit_code=False),
mock.call('parted', '/dev/sdb', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', 102400, '-1'),
mock.call('partx', '-u', '/dev/sdb', check_exit_code=False),
mock.call('mdadm', '--create', '/dev/md0', '--force', '--run',
'--metadata=1', '--level', '1', '--raid-devices', 2,
'/dev/sda1', '/dev/sdb1'),
@ -2696,7 +2700,7 @@ class TestGenericHardwareManager(base.IronicAgentTest):
# partition creation
error_regex = "Failed to create partitions on /dev/sda"
mocked_execute.side_effect = [
None, None, # partition tables on sd{a,b}
None, None, # partition tables and partx on sd{a,b}
processutils.ProcessExecutionError]
self.assertRaisesRegex(errors.SoftwareRAIDError, error_regex,
self.hardware.create_configuration,
@ -2706,8 +2710,116 @@ class TestGenericHardwareManager(base.IronicAgentTest):
"on /dev/sda1 /dev/sdb1")
mocked_execute.side_effect = [
None, None, # partition tables on sd{a,b}
None, None, # RAID-1 partitions on sd{a,b}
None, None, # RAID-N partitions on sd{a,b}
None, None, None, None, # RAID-1 partitions on sd{a,b} + partx
None, None, None, None, # RAID-N partitions on sd{a,b} + partx
processutils.ProcessExecutionError]
self.assertRaisesRegex(errors.SoftwareRAIDError, error_regex,
self.hardware.create_configuration,
self.node, [])
@mock.patch.object(utils, 'execute', autospec=True)
def test_create_configuration_with_nvme(self, mocked_execute):
raid_config = {
"logical_disks": [
{
"size_gb": "100",
"raid_level": "1",
"controller": "software",
},
{
"size_gb": "MAX",
"raid_level": "0",
"controller": "software",
},
]
}
self.node['target_raid_config'] = raid_config
device1 = hardware.BlockDevice('/dev/nvme0n1', 'nvme0n1',
1073741824, True)
device2 = hardware.BlockDevice('/dev/nvme1n1', 'nvme1n1',
1073741824, True)
self.hardware.list_block_devices = mock.Mock()
self.hardware.list_block_devices.return_value = [device1, device2]
result = self.hardware.create_configuration(self.node, [])
mocked_execute.assert_has_calls([
mock.call('parted', '/dev/nvme0n1', '-s', '--', 'mklabel',
'msdos'),
mock.call('parted', '/dev/nvme1n1', '-s', '--', 'mklabel',
'msdos'),
mock.call('parted', '/dev/nvme0n1', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', '2048s', 102400),
mock.call('partx', '-u', '/dev/nvme0n1', check_exit_code=False),
mock.call('parted', '/dev/nvme1n1', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', '2048s', 102400),
mock.call('partx', '-u', '/dev/nvme1n1', check_exit_code=False),
mock.call('parted', '/dev/nvme0n1', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', 102400, '-1'),
mock.call('partx', '-u', '/dev/nvme0n1', check_exit_code=False),
mock.call('parted', '/dev/nvme1n1', '-s', '-a', 'optimal', '--',
'mkpart', 'primary', 102400, '-1'),
mock.call('partx', '-u', '/dev/nvme1n1', check_exit_code=False),
mock.call('mdadm', '--create', '/dev/md0', '--force', '--run',
'--metadata=1', '--level', '1', '--raid-devices', 2,
'/dev/nvme0n1p1', '/dev/nvme1n1p1'),
mock.call('mdadm', '--create', '/dev/md1', '--force', '--run',
'--metadata=1', '--level', '0', '--raid-devices', 2,
'/dev/nvme0n1p2', '/dev/nvme1n1p2')])
self.assertEqual(raid_config, result)
@mock.patch.object(utils, 'execute', autospec=True)
def test_create_configuration_failure_with_nvme(self, mocked_execute):
raid_config = {
"logical_disks": [
{
"size_gb": "100",
"raid_level": "1",
"controller": "software",
},
{
"size_gb": "MAX",
"raid_level": "0",
"controller": "software",
},
]
}
self.node['target_raid_config'] = raid_config
device1 = hardware.BlockDevice('/dev/nvme0n1', 'nvme0n1',
1073741824, True)
device2 = hardware.BlockDevice('/dev/nvme1n1', 'nvme1n1',
1073741824, True)
self.hardware.list_block_devices = mock.Mock()
self.hardware.list_block_devices.side_effect = [
[device1, device2],
[device1, device2],
[device1, device2],
[device1, device2],
[device1, device2],
[device1, device2]]
# partition table creation
error_regex = "Failed to create partition table on /dev/nvme0n1"
mocked_execute.side_effect = [
processutils.ProcessExecutionError]
self.assertRaisesRegex(errors.SoftwareRAIDError, error_regex,
self.hardware.create_configuration,
self.node, [])
# partition creation
error_regex = "Failed to create partitions on /dev/nvme0n1"
mocked_execute.side_effect = [
None, None, # partition tables and partx on sd{a,b}
processutils.ProcessExecutionError]
self.assertRaisesRegex(errors.SoftwareRAIDError, error_regex,
self.hardware.create_configuration,
self.node, [])
# raid device creation
error_regex = ("Failed to create md device /dev/md0 "
"on /dev/nvme0n1p1 /dev/nvme1n1p1")
mocked_execute.side_effect = [
None, None, # partition tables on sd{a,b}
None, None, None, None, # RAID-1 partitions on sd{a,b} + partx
None, None, None, None, # RAID-N partitions on sd{a,b} + partx
processutils.ProcessExecutionError]
self.assertRaisesRegex(errors.SoftwareRAIDError, error_regex,
self.hardware.create_configuration,

View File

@ -0,0 +1,3 @@
---
features:
- Adds software raid creation support on nvme drives.