Merge "Allow erasing metadata from disk partitions"

This commit is contained in:
Zuul 2018-11-26 22:47:02 +00:00 committed by Gerrit Code Review
commit cfb62c8765
3 changed files with 72 additions and 25 deletions

View File

@ -363,7 +363,12 @@ class HardwareManager(object):
def get_cpus(self):
raise errors.IncompatibleHardwareMethodError
def list_block_devices(self):
def list_block_devices(self, include_partitions=False):
"""List physical block devices
:param include_partitions: If to include partitions
:return: A list of BlockDevices
"""
raise errors.IncompatibleHardwareMethodError
def get_memory(self):
@ -762,8 +767,14 @@ class GenericHardwareManager(HardwareManager):
return Memory(total=total, physical_mb=physical)
def list_block_devices(self):
return list_all_block_devices()
def list_block_devices(self, include_partitions=False):
block_devices = list_all_block_devices()
if include_partitions:
block_devices.extend(
list_all_block_devices(block_type='part',
ignore_raid=True)
)
return block_devices
def get_os_install_device(self):
cached_node = get_cached_node()
@ -866,7 +877,11 @@ class GenericHardwareManager(HardwareManager):
:raises BlockDeviceEraseError: when there's an error erasing the
block device
"""
block_devices = self.list_block_devices()
block_devices = self.list_block_devices(include_partitions=True)
# NOTE(coreywright): Reverse sort by device name so a partition (eg
# sda1) is processed before it disappears when its associated disk (eg
# sda) has its partition table erased and the kernel notified.
block_devices.sort(key=lambda dev: dev.name, reverse=True)
erase_errors = {}
for dev in block_devices:
if self._is_virtual_media_device(dev):

View File

@ -1148,6 +1148,19 @@ class TestGenericHardwareManager(base.IronicAgentTest):
list_mock.assert_called_once_with()
@mock.patch.object(hardware, 'list_all_block_devices', autospec=True)
def test_list_block_devices_including_partitions(self, list_mock):
device = hardware.BlockDevice('/dev/hdaa', 'small', 65535, False)
partition = hardware.BlockDevice('/dev/hdaa1', '', 32767, False)
list_mock.side_effect = [[device], [partition]]
devices = self.hardware.list_block_devices(include_partitions=True)
self.assertEqual([device, partition], devices)
self.assertEqual([mock.call(), mock.call(block_type='part',
ignore_raid=True)],
list_mock.call_args_list)
@mock.patch.object(os, 'readlink', autospec=True)
@mock.patch.object(os, 'listdir', autospec=True)
@mock.patch.object(hardware, '_get_device_info', autospec=True)
@ -1965,18 +1978,24 @@ class TestGenericHardwareManager(base.IronicAgentTest):
block_devices = [
hardware.BlockDevice('/dev/sr0', 'vmedia', 12345, True),
hardware.BlockDevice('/dev/sda', 'small', 65535, False),
hardware.BlockDevice('/dev/sda1', '', 32767, False),
]
mock_list_devs.return_value = block_devices
mock__is_vmedia.side_effect = (True, False)
# NOTE(coreywright): Don't return the list, but a copy of it, because
# we depend on its elements' order when referencing it later during
# verification, but the method under test sorts the list changing it.
mock_list_devs.return_value = list(block_devices)
mock__is_vmedia.side_effect = lambda _, dev: dev.name == '/dev/sr0'
self.hardware.erase_devices_metadata(self.node, [])
mock_metadata.assert_called_once_with(
'/dev/sda', self.node['uuid'])
mock_list_devs.assert_called_once_with(mock.ANY)
mock__is_vmedia.assert_has_calls([
mock.call(mock.ANY, block_devices[0]),
mock.call(mock.ANY, block_devices[1])
])
self.assertEqual([mock.call('/dev/sda1', self.node['uuid']),
mock.call('/dev/sda', self.node['uuid'])],
mock_metadata.call_args_list)
mock_list_devs.assert_called_once_with(self.hardware,
include_partitions=True)
self.assertEqual([mock.call(self.hardware, block_devices[0]),
mock.call(self.hardware, block_devices[2]),
mock.call(self.hardware, block_devices[1])],
mock__is_vmedia.call_args_list)
@mock.patch.object(hardware.GenericHardwareManager,
'_is_virtual_media_device', autospec=True)
@ -1990,28 +2009,33 @@ class TestGenericHardwareManager(base.IronicAgentTest):
hardware.BlockDevice('/dev/sdb', 'big', 10737418240, True),
]
mock__is_vmedia.return_value = False
mock_list_devs.return_value = block_devices
# Simulate /dev/sda failing and /dev/sdb succeeding
# NOTE(coreywright): Don't return the list, but a copy of it, because
# we depend on its elements' order when referencing it later during
# verification, but the method under test sorts the list changing it.
mock_list_devs.return_value = list(block_devices)
# Simulate first call to destroy_disk_metadata() failing, which is for
# /dev/sdb due to erase_devices_metadata() reverse sorting block
# devices by name, and second call succeeding, which is for /dev/sda
error_output = 'Booo00000ooommmmm'
error_regex = '(?s)/dev/sdb.*' + error_output
mock_metadata.side_effect = (
processutils.ProcessExecutionError(error_output),
None,
)
self.assertRaisesRegex(errors.BlockDeviceEraseError, error_output,
self.assertRaisesRegex(errors.BlockDeviceEraseError, error_regex,
self.hardware.erase_devices_metadata,
self.node, [])
# Assert all devices are erased independent if one of them
# failed previously
mock_metadata.assert_has_calls([
mock.call('/dev/sda', self.node['uuid']),
mock.call('/dev/sdb', self.node['uuid']),
])
mock_list_devs.assert_called_once_with(mock.ANY)
mock__is_vmedia.assert_has_calls([
mock.call(mock.ANY, block_devices[0]),
mock.call(mock.ANY, block_devices[1])
])
self.assertEqual([mock.call('/dev/sdb', self.node['uuid']),
mock.call('/dev/sda', self.node['uuid'])],
mock_metadata.call_args_list)
mock_list_devs.assert_called_once_with(self.hardware,
include_partitions=True)
self.assertEqual([mock.call(self.hardware, block_devices[1]),
mock.call(self.hardware, block_devices[0])],
mock__is_vmedia.call_args_list)
@mock.patch.object(utils, 'execute', autospec=True)
def test_get_bmc_address(self, mocked_execute):

View File

@ -0,0 +1,8 @@
---
features:
- |
Erase metadata on disk partitions to prevent the Linux kernel from
automatically recreating storage entities (eg LVM, RAID) described by the
metadata. The Hardware Manager API was correspondingly modified to
optionally include partitions when listing block devices. See `story
2003673 <https://storyboard.openstack.org/#!/story/2003673>`_ for details.