Merge "Add erase_devices_metadata cleaning step"
This commit is contained in:
commit
c1b1d7e670
@ -19,7 +19,7 @@ import os
|
|||||||
import shlex
|
import shlex
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ironic_lib import disk_utils
|
||||||
import netifaces
|
import netifaces
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
@ -399,15 +399,7 @@ class HardwareManager(object):
|
|||||||
dict as defined above
|
dict as defined above
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return [
|
return []
|
||||||
{
|
|
||||||
'step': 'erase_devices',
|
|
||||||
'priority': 10,
|
|
||||||
'interface': 'deploy',
|
|
||||||
'reboot_requested': False,
|
|
||||||
'abortable': True
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_version(self):
|
def get_version(self):
|
||||||
"""Get a name and version for this hardware manager.
|
"""Get a name and version for this hardware manager.
|
||||||
@ -437,7 +429,8 @@ class HardwareManager(object):
|
|||||||
|
|
||||||
class GenericHardwareManager(HardwareManager):
|
class GenericHardwareManager(HardwareManager):
|
||||||
HARDWARE_MANAGER_NAME = 'generic_hardware_manager'
|
HARDWARE_MANAGER_NAME = 'generic_hardware_manager'
|
||||||
HARDWARE_MANAGER_VERSION = '1.0'
|
# 1.1 - Added new clean step called erase_devices_metadata
|
||||||
|
HARDWARE_MANAGER_VERSION = '1.1'
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.sys_path = '/sys'
|
self.sys_path = '/sys'
|
||||||
@ -753,6 +746,35 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
LOG.error(msg)
|
LOG.error(msg)
|
||||||
raise errors.IncompatibleHardwareMethodError(msg)
|
raise errors.IncompatibleHardwareMethodError(msg)
|
||||||
|
|
||||||
|
def erase_devices_metadata(self, node, ports):
|
||||||
|
"""Attempt to erase the disk devices metadata.
|
||||||
|
|
||||||
|
:param node: Ironic node object
|
||||||
|
:param ports: list of Ironic port objects
|
||||||
|
:raises BlockDeviceEraseError when there's an error erasing the
|
||||||
|
block device
|
||||||
|
"""
|
||||||
|
block_devices = self.list_block_devices()
|
||||||
|
erase_errors = {}
|
||||||
|
for dev in block_devices:
|
||||||
|
if self._is_virtual_media_device(dev):
|
||||||
|
LOG.info("Skipping the erase of virtual media device %s",
|
||||||
|
dev.name)
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
disk_utils.destroy_disk_metadata(dev.name, node['uuid'])
|
||||||
|
except processutils.ProcessExecutionError as e:
|
||||||
|
LOG.error('Failed to erase the metadata on device "%(dev)s". '
|
||||||
|
'Error: %(error)s', {'dev': dev.name, 'error': e})
|
||||||
|
erase_errors[dev.name] = e
|
||||||
|
|
||||||
|
if erase_errors:
|
||||||
|
excpt_msg = ('Failed to erase the metadata on the device(s): %s' %
|
||||||
|
'; '.join(['"%s": %s' % (k, v)
|
||||||
|
for k, v in erase_errors.items()]))
|
||||||
|
raise errors.BlockDeviceEraseError(excpt_msg)
|
||||||
|
|
||||||
def _shred_block_device(self, node, block_device):
|
def _shred_block_device(self, node, block_device):
|
||||||
"""Erase a block device using shred.
|
"""Erase a block device using shred.
|
||||||
|
|
||||||
@ -897,6 +919,24 @@ class GenericHardwareManager(HardwareManager):
|
|||||||
|
|
||||||
return out.strip()
|
return out.strip()
|
||||||
|
|
||||||
|
def get_clean_steps(self, node, ports):
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
'step': 'erase_devices',
|
||||||
|
'priority': 10,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'step': 'erase_devices_metadata',
|
||||||
|
'priority': 99,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def _compare_extensions(ext1, ext2):
|
def _compare_extensions(ext1, ext2):
|
||||||
mgr1 = ext1.obj
|
mgr1 = ext1.obj
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
from ironic_lib import disk_utils
|
||||||
import mock
|
import mock
|
||||||
import netifaces
|
import netifaces
|
||||||
from oslo_concurrency import processutils
|
from oslo_concurrency import processutils
|
||||||
@ -284,6 +285,26 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
|
|||||||
CONF.clear_override('disk_wait_attempts')
|
CONF.clear_override('disk_wait_attempts')
|
||||||
CONF.clear_override('disk_wait_delay')
|
CONF.clear_override('disk_wait_delay')
|
||||||
|
|
||||||
|
def test_get_clean_steps(self):
|
||||||
|
expected_clean_steps = [
|
||||||
|
{
|
||||||
|
'step': 'erase_devices',
|
||||||
|
'priority': 10,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'step': 'erase_devices_metadata',
|
||||||
|
'priority': 99,
|
||||||
|
'interface': 'deploy',
|
||||||
|
'reboot_requested': False,
|
||||||
|
'abortable': True
|
||||||
|
}
|
||||||
|
]
|
||||||
|
clean_steps = self.hardware.get_clean_steps(self.node, [])
|
||||||
|
self.assertEqual(expected_clean_steps, clean_steps)
|
||||||
|
|
||||||
@mock.patch('netifaces.ifaddresses')
|
@mock.patch('netifaces.ifaddresses')
|
||||||
@mock.patch('os.listdir')
|
@mock.patch('os.listdir')
|
||||||
@mock.patch('os.path.exists')
|
@mock.patch('os.path.exists')
|
||||||
@ -1194,6 +1215,64 @@ class TestGenericHardwareManager(test_base.BaseTestCase):
|
|||||||
test_security_erase_option(
|
test_security_erase_option(
|
||||||
self, False, '--security-erase')
|
self, False, '--security-erase')
|
||||||
|
|
||||||
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
|
'_is_virtual_media_device', autospec=True)
|
||||||
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
|
'list_block_devices', autospec=True)
|
||||||
|
@mock.patch.object(disk_utils, 'destroy_disk_metadata', autospec=True)
|
||||||
|
def test_erase_devices_metadata(
|
||||||
|
self, mock_metadata, mock_list_devs, mock__is_vmedia):
|
||||||
|
block_devices = [
|
||||||
|
hardware.BlockDevice('/dev/sr0', 'vmedia', 12345, True),
|
||||||
|
hardware.BlockDevice('/dev/sda', 'small', 65535, False),
|
||||||
|
]
|
||||||
|
mock_list_devs.return_value = block_devices
|
||||||
|
mock__is_vmedia.side_effect = (True, False)
|
||||||
|
|
||||||
|
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])
|
||||||
|
])
|
||||||
|
|
||||||
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
|
'_is_virtual_media_device', autospec=True)
|
||||||
|
@mock.patch.object(hardware.GenericHardwareManager,
|
||||||
|
'list_block_devices', autospec=True)
|
||||||
|
@mock.patch.object(disk_utils, 'destroy_disk_metadata', autospec=True)
|
||||||
|
def test_erase_devices_metadata_error(
|
||||||
|
self, mock_metadata, mock_list_devs, mock__is_vmedia):
|
||||||
|
block_devices = [
|
||||||
|
hardware.BlockDevice('/dev/sda', 'small', 65535, False),
|
||||||
|
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
|
||||||
|
error_output = 'Booo00000ooommmmm'
|
||||||
|
mock_metadata.side_effect = (
|
||||||
|
processutils.ProcessExecutionError(error_output),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertRaisesRegex(errors.BlockDeviceEraseError, error_output,
|
||||||
|
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])
|
||||||
|
])
|
||||||
|
|
||||||
@mock.patch.object(utils, 'execute')
|
@mock.patch.object(utils, 'execute')
|
||||||
def test_get_bmc_address(self, mocked_execute):
|
def test_get_bmc_address(self, mocked_execute):
|
||||||
mocked_execute.return_value = '192.1.2.3\n', ''
|
mocked_execute.return_value = '192.1.2.3\n', ''
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Add a new cleaning step called "erase_devices_metadata" to the generic
|
||||||
|
hardware manager which is responsible for destroying the metadata
|
||||||
|
on the disk devices (partition tables, signatures, file-system
|
||||||
|
identifications, etc...).
|
Loading…
Reference in New Issue
Block a user