Merge "Out-of-band erase_devices
clean step for Proliant Servers"
This commit is contained in:
commit
b781042bee
@ -4,7 +4,7 @@
|
|||||||
# python projects they should package as optional dependencies for Ironic.
|
# python projects they should package as optional dependencies for Ironic.
|
||||||
|
|
||||||
# These are available on pypi
|
# These are available on pypi
|
||||||
proliantutils>=2.7.0
|
proliantutils>=2.9.0
|
||||||
pysnmp>=4.3.0,<5.0.0
|
pysnmp>=4.3.0,<5.0.0
|
||||||
python-scciclient>=0.8.0
|
python-scciclient>=0.8.0
|
||||||
python-dracclient>=3.0.0,<4.0.0
|
python-dracclient>=3.0.0,<4.0.0
|
||||||
|
@ -66,6 +66,13 @@ opts = [
|
|||||||
default=2,
|
default=2,
|
||||||
help=_('Amount of time in seconds to wait in between power '
|
help=_('Amount of time in seconds to wait in between power '
|
||||||
'operations')),
|
'operations')),
|
||||||
|
cfg.IntOpt('oob_erase_devices_job_status_interval',
|
||||||
|
min=10,
|
||||||
|
default=300,
|
||||||
|
help=_('Interval (in seconds) between periodic erase-devices '
|
||||||
|
'status checks to determine whether the asynchronous '
|
||||||
|
'out-of-band erase-devices was successfully finished or '
|
||||||
|
'not.')),
|
||||||
cfg.StrOpt('ca_file',
|
cfg.StrOpt('ca_file',
|
||||||
help=_('CA certificate file to validate iLO.')),
|
help=_('CA certificate file to validate iLO.')),
|
||||||
cfg.StrOpt('default_boot_mode',
|
cfg.StrOpt('default_boot_mode',
|
||||||
|
@ -82,3 +82,8 @@ class Ilo5Hardware(IloHardware):
|
|||||||
def supported_raid_interfaces(self):
|
def supported_raid_interfaces(self):
|
||||||
"""List of supported raid interfaces."""
|
"""List of supported raid interfaces."""
|
||||||
return [raid.Ilo5RAID, noop.NoRAID]
|
return [raid.Ilo5RAID, noop.NoRAID]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_management_interfaces(self):
|
||||||
|
"""List of supported management interfaces."""
|
||||||
|
return [management.Ilo5Management]
|
||||||
|
@ -17,6 +17,7 @@ iLO Management Interface
|
|||||||
|
|
||||||
from ironic_lib import metrics_utils
|
from ironic_lib import metrics_utils
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
|
from oslo_service import loopingcall
|
||||||
from oslo_utils import excutils
|
from oslo_utils import excutils
|
||||||
from oslo_utils import importutils
|
from oslo_utils import importutils
|
||||||
import six
|
import six
|
||||||
@ -25,7 +26,9 @@ import six.moves.urllib.parse as urlparse
|
|||||||
from ironic.common import boot_devices
|
from ironic.common import boot_devices
|
||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common.i18n import _
|
from ironic.common.i18n import _
|
||||||
|
from ironic.common import states
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
|
from ironic.conductor import utils as manager_utils
|
||||||
from ironic.conf import CONF
|
from ironic.conf import CONF
|
||||||
from ironic.drivers import base
|
from ironic.drivers import base
|
||||||
from ironic.drivers.modules import agent_base_vendor
|
from ironic.drivers.modules import agent_base_vendor
|
||||||
@ -614,3 +617,163 @@ class IloManagement(base.ManagementInterface):
|
|||||||
except ilo_error.IloError as ilo_exception:
|
except ilo_error.IloError as ilo_exception:
|
||||||
raise exception.IloOperationError(operation=operation,
|
raise exception.IloOperationError(operation=operation,
|
||||||
error=ilo_exception)
|
error=ilo_exception)
|
||||||
|
|
||||||
|
|
||||||
|
class Ilo5Management(IloManagement):
|
||||||
|
|
||||||
|
def _set_driver_internal_value(self, task, value, *keys):
|
||||||
|
driver_internal_info = task.node.driver_internal_info
|
||||||
|
for key in keys:
|
||||||
|
driver_internal_info[key] = value
|
||||||
|
task.node.driver_internal_info = driver_internal_info
|
||||||
|
task.node.save()
|
||||||
|
|
||||||
|
def _pop_driver_internal_values(self, task, *keys):
|
||||||
|
driver_internal_info = task.node.driver_internal_info
|
||||||
|
for key in keys:
|
||||||
|
driver_internal_info.pop(key, None)
|
||||||
|
task.node.driver_internal_info = driver_internal_info
|
||||||
|
task.node.save()
|
||||||
|
|
||||||
|
def _set_clean_failed(self, task, msg):
|
||||||
|
LOG.error("Out-of-band sanitize disk erase job failed for node "
|
||||||
|
"%(node)s. Message: '%(message)s'.",
|
||||||
|
{'node': task.node.uuid, 'message': msg})
|
||||||
|
task.node.last_error = msg
|
||||||
|
task.process_event('fail')
|
||||||
|
|
||||||
|
def _wait_for_disk_erase_status(self, node):
|
||||||
|
"""Wait for out-of-band sanitize disk erase to be completed."""
|
||||||
|
interval = CONF.ilo.oob_erase_devices_job_status_interval
|
||||||
|
ilo_object = ilo_common.get_ilo_object(node)
|
||||||
|
time_elps = [0]
|
||||||
|
|
||||||
|
# This will loop indefinitely till disk erase is complete
|
||||||
|
def _wait():
|
||||||
|
if ilo_object.has_disk_erase_completed():
|
||||||
|
raise loopingcall.LoopingCallDone()
|
||||||
|
|
||||||
|
time_elps[0] += interval
|
||||||
|
LOG.debug("%(tim)s secs elapsed while waiting for out-of-band "
|
||||||
|
"sanitize disk erase to complete for node %(node)s.",
|
||||||
|
{'tim': time_elps[0], 'node': node.uuid})
|
||||||
|
|
||||||
|
# Start a timer and wait for the operation to complete.
|
||||||
|
timer = loopingcall.FixedIntervalLoopingCall(_wait)
|
||||||
|
timer.start(interval=interval).wait()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _validate_erase_pattern(self, erase_pattern, node):
|
||||||
|
invalid = False
|
||||||
|
if isinstance(erase_pattern, dict):
|
||||||
|
for device_type, pattern in erase_pattern.items():
|
||||||
|
if device_type == 'hdd' and pattern in (
|
||||||
|
'overwrite', 'crypto', 'zero'):
|
||||||
|
continue
|
||||||
|
elif device_type == 'ssd' and pattern in (
|
||||||
|
'block', 'crypto', 'zero'):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
invalid = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
invalid = True
|
||||||
|
|
||||||
|
if invalid:
|
||||||
|
msg = (_("Erase pattern '%(value)s' is invalid. Clean step "
|
||||||
|
"'erase_devices' is not executed for %(node)s. Supported "
|
||||||
|
"patterns are, for "
|
||||||
|
"'hdd': ('overwrite', 'crypto', 'zero') and for "
|
||||||
|
"'ssd': ('block', 'crypto', 'zero'). "
|
||||||
|
"Ex. {'hdd': 'overwrite', 'ssd': 'block'}")
|
||||||
|
% {'value': erase_pattern, 'node': node.uuid})
|
||||||
|
LOG.error(msg)
|
||||||
|
raise exception.InvalidParameterValue(msg)
|
||||||
|
|
||||||
|
@METRICS.timer('Ilo5Management.erase_devices')
|
||||||
|
@base.clean_step(priority=0, abortable=False, argsinfo={
|
||||||
|
'erase_pattern': {
|
||||||
|
'description': (
|
||||||
|
'Dictionary of disk type and corresponding erase pattern '
|
||||||
|
'to be used to perform specific out-of-band sanitize disk '
|
||||||
|
'erase. Supported values are, '
|
||||||
|
'for "hdd": ("overwrite", "crypto", "zero"), '
|
||||||
|
'for "ssd": ("block", "crypto", "zero"). Default pattern is: '
|
||||||
|
'{"hdd": "overwrite", "ssd": "block"}.'
|
||||||
|
),
|
||||||
|
'required': False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
def erase_devices(self, task, **kwargs):
|
||||||
|
"""Erase all the drives on the node.
|
||||||
|
|
||||||
|
This method performs out-of-band sanitize disk erase on all the
|
||||||
|
supported physical drives in the node. This erase cannot be performed
|
||||||
|
on logical drives.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:raises: InvalidParameterValue, if any of the arguments are invalid.
|
||||||
|
:raises: IloError on an error from iLO.
|
||||||
|
"""
|
||||||
|
erase_pattern = kwargs.get('erase_pattern',
|
||||||
|
{'hdd': 'overwrite', 'ssd': 'block'})
|
||||||
|
node = task.node
|
||||||
|
self._validate_erase_pattern(erase_pattern, node)
|
||||||
|
driver_internal_info = node.driver_internal_info
|
||||||
|
LOG.debug("Calling out-of-band sanitize disk erase for node %(node)s",
|
||||||
|
{'node': node.uuid})
|
||||||
|
try:
|
||||||
|
ilo_object = ilo_common.get_ilo_object(node)
|
||||||
|
disk_types = ilo_object.get_available_disk_types()
|
||||||
|
LOG.info("Disk type detected are: %(disk_types)s. Sanitize disk "
|
||||||
|
"erase are now exercised for one after another disk type "
|
||||||
|
"for node %(node)s.",
|
||||||
|
{'disk_types': disk_types, 'node': node.uuid})
|
||||||
|
|
||||||
|
if disk_types:
|
||||||
|
# First disk-erase will execute for HDD's and after reboot only
|
||||||
|
# try for SSD, since both share same redfish api and would be
|
||||||
|
# overwritten.
|
||||||
|
if not driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check') and ('HDD' in disk_types):
|
||||||
|
ilo_object.do_disk_erase('HDD', erase_pattern.get('hdd'))
|
||||||
|
self._set_driver_internal_value(
|
||||||
|
task, True, 'cleaning_reboot',
|
||||||
|
'ilo_disk_erase_hdd_check')
|
||||||
|
self._set_driver_internal_value(
|
||||||
|
task, False, 'skip_current_clean_step')
|
||||||
|
deploy_opts = deploy_utils.build_agent_options(task.node)
|
||||||
|
task.driver.boot.prepare_ramdisk(task, deploy_opts)
|
||||||
|
manager_utils.node_power_action(task, states.REBOOT)
|
||||||
|
return states.CLEANWAIT
|
||||||
|
|
||||||
|
if not driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_ssd_check') and ('SSD' in disk_types):
|
||||||
|
ilo_object.do_disk_erase('SSD', erase_pattern.get('ssd'))
|
||||||
|
self._set_driver_internal_value(
|
||||||
|
task, True, 'ilo_disk_erase_hdd_check',
|
||||||
|
'ilo_disk_erase_ssd_check', 'cleaning_reboot')
|
||||||
|
self._set_driver_internal_value(
|
||||||
|
task, False, 'skip_current_clean_step')
|
||||||
|
deploy_opts = deploy_utils.build_agent_options(task.node)
|
||||||
|
task.driver.boot.prepare_ramdisk(task, deploy_opts)
|
||||||
|
manager_utils.node_power_action(task, states.REBOOT)
|
||||||
|
return states.CLEANWAIT
|
||||||
|
|
||||||
|
# It will wait until disk erase will complete
|
||||||
|
if self._wait_for_disk_erase_status(task.node):
|
||||||
|
LOG.info("For node %(uuid)s erase_devices clean "
|
||||||
|
"step is done.", {'uuid': task.node.uuid})
|
||||||
|
self._pop_driver_internal_values(
|
||||||
|
task, 'ilo_disk_erase_hdd_check',
|
||||||
|
'ilo_disk_erase_ssd_check')
|
||||||
|
else:
|
||||||
|
LOG.info("No drive found to perform out-of-band sanitize "
|
||||||
|
"disk erase for node %(node)s", {'node': node.uuid})
|
||||||
|
except ilo_error.IloError as ilo_exception:
|
||||||
|
self._pop_driver_internal_values(task,
|
||||||
|
'ilo_disk_erase_hdd_check',
|
||||||
|
'ilo_disk_erase_ssd_check',
|
||||||
|
'cleaning_reboot',
|
||||||
|
'skip_current_clean_step')
|
||||||
|
self._set_clean_failed(task, ilo_exception)
|
||||||
|
@ -22,16 +22,21 @@ from ironic.common import boot_devices
|
|||||||
from ironic.common import exception
|
from ironic.common import exception
|
||||||
from ironic.common import states
|
from ironic.common import states
|
||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
|
from ironic.conductor import utils as manager_utils
|
||||||
from ironic.drivers.modules import deploy_utils
|
from ironic.drivers.modules import deploy_utils
|
||||||
from ironic.drivers.modules.ilo import common as ilo_common
|
from ironic.drivers.modules.ilo import common as ilo_common
|
||||||
from ironic.drivers.modules.ilo import management as ilo_management
|
from ironic.drivers.modules.ilo import management as ilo_management
|
||||||
from ironic.drivers.modules import ipmitool
|
from ironic.drivers.modules import ipmitool
|
||||||
from ironic.drivers import utils as driver_utils
|
from ironic.drivers import utils as driver_utils
|
||||||
|
from ironic.tests.unit.db import base as db_base
|
||||||
|
from ironic.tests.unit.db import utils as db_utils
|
||||||
from ironic.tests.unit.drivers.modules.ilo import test_common
|
from ironic.tests.unit.drivers.modules.ilo import test_common
|
||||||
from ironic.tests.unit.objects import utils as obj_utils
|
from ironic.tests.unit.objects import utils as obj_utils
|
||||||
|
|
||||||
ilo_error = importutils.try_import('proliantutils.exception')
|
ilo_error = importutils.try_import('proliantutils.exception')
|
||||||
|
|
||||||
|
INFO_DICT = db_utils.get_test_ilo_info()
|
||||||
|
|
||||||
|
|
||||||
class IloManagementTestCase(test_common.BaseIloTest):
|
class IloManagementTestCase(test_common.BaseIloTest):
|
||||||
|
|
||||||
@ -897,3 +902,219 @@ class IloManagementTestCase(test_common.BaseIloTest):
|
|||||||
self.assertRaises(exception.IloOperationNotSupported,
|
self.assertRaises(exception.IloOperationNotSupported,
|
||||||
task.driver.management.inject_nmi,
|
task.driver.management.inject_nmi,
|
||||||
task)
|
task)
|
||||||
|
|
||||||
|
|
||||||
|
class Ilo5ManagementTestCase(db_base.DbTestCase):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(Ilo5ManagementTestCase, self).setUp()
|
||||||
|
self.driver = mock.Mock(management=ilo_management.Ilo5Management())
|
||||||
|
self.clean_step = {'step': 'erase_devices',
|
||||||
|
'interface': 'management'}
|
||||||
|
n = {
|
||||||
|
'driver': 'ilo5',
|
||||||
|
'driver_info': INFO_DICT,
|
||||||
|
'clean_step': self.clean_step,
|
||||||
|
}
|
||||||
|
self.config(enabled_hardware_types=['ilo5'],
|
||||||
|
enabled_boot_interfaces=['ilo-virtual-media'],
|
||||||
|
enabled_console_interfaces=['ilo'],
|
||||||
|
enabled_deploy_interfaces=['iscsi'],
|
||||||
|
enabled_inspect_interfaces=['ilo'],
|
||||||
|
enabled_management_interfaces=['ilo5'],
|
||||||
|
enabled_power_interfaces=['ilo'],
|
||||||
|
enabled_raid_interfaces=['ilo5'])
|
||||||
|
self.node = obj_utils.create_test_node(self.context, **n)
|
||||||
|
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||||
|
def test_erase_devices_hdd(self, mock_power, ilo_mock, build_agent_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
|
||||||
|
build_agent_mock.return_value = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
result = task.driver.management.erase_devices(task)
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'cleaning_reboot'))
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'skip_current_clean_step'))
|
||||||
|
ilo_mock_object.do_disk_erase.assert_called_once_with(
|
||||||
|
'HDD', 'overwrite')
|
||||||
|
self.assertEqual(states.CLEANWAIT, result)
|
||||||
|
mock_power.assert_called_once_with(task, states.REBOOT)
|
||||||
|
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||||
|
def test_erase_devices_ssd(self, mock_power, ilo_mock, build_agent_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['SSD']
|
||||||
|
build_agent_mock.return_value = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
result = task.driver.management.erase_devices(task)
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_ssd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'cleaning_reboot'))
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'skip_current_clean_step'))
|
||||||
|
ilo_mock_object.do_disk_erase.assert_called_once_with(
|
||||||
|
'SSD', 'block')
|
||||||
|
self.assertEqual(states.CLEANWAIT, result)
|
||||||
|
mock_power.assert_called_once_with(task, states.REBOOT)
|
||||||
|
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||||
|
def test_erase_devices_ssd_when_hdd_done(self, mock_power, ilo_mock,
|
||||||
|
build_agent_mock):
|
||||||
|
build_agent_mock.return_value = []
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['HDD', 'SSD']
|
||||||
|
self.node.driver_internal_info = {'ilo_disk_erase_hdd_check': True}
|
||||||
|
self.node.save()
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
result = task.driver.management.erase_devices(task)
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_ssd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'cleaning_reboot'))
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'skip_current_clean_step'))
|
||||||
|
ilo_mock_object.do_disk_erase.assert_called_once_with(
|
||||||
|
'SSD', 'block')
|
||||||
|
self.assertEqual(states.CLEANWAIT, result)
|
||||||
|
mock_power.assert_called_once_with(task, states.REBOOT)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_management.LOG, 'info')
|
||||||
|
@mock.patch.object(ilo_management.Ilo5Management,
|
||||||
|
'_wait_for_disk_erase_status', autospec=True)
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
def test_erase_devices_completed(self, ilo_mock, disk_status_mock,
|
||||||
|
log_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['HDD', 'SSD']
|
||||||
|
disk_status_mock.return_value = True
|
||||||
|
self.node.driver_internal_info = {'ilo_disk_erase_hdd_check': True,
|
||||||
|
'ilo_disk_erase_ssd_check': True}
|
||||||
|
self.node.save()
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
task.driver.management.erase_devices(task)
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertTrue(log_mock.called)
|
||||||
|
|
||||||
|
@mock.patch.object(deploy_utils, 'build_agent_options',
|
||||||
|
autospec=True)
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||||
|
def test_erase_devices_hdd_with_erase_pattern_zero(
|
||||||
|
self, mock_power, ilo_mock, build_agent_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
|
||||||
|
build_agent_mock.return_value = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
result = task.driver.management.erase_devices(
|
||||||
|
task, erase_pattern={'hdd': 'zero', 'ssd': 'zero'})
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'ilo_disk_erase_hdd_check'))
|
||||||
|
self.assertTrue(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'cleaning_reboot'))
|
||||||
|
self.assertFalse(
|
||||||
|
task.node.driver_internal_info.get(
|
||||||
|
'skip_current_clean_step'))
|
||||||
|
ilo_mock_object.do_disk_erase.assert_called_once_with(
|
||||||
|
'HDD', 'zero')
|
||||||
|
self.assertEqual(states.CLEANWAIT, result)
|
||||||
|
mock_power.assert_called_once_with(task, states.REBOOT)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_management.LOG, 'info')
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
def test_erase_devices_when_no_drive_available(
|
||||||
|
self, ilo_mock, log_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = []
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
task.driver.management.erase_devices(task)
|
||||||
|
self.assertTrue(log_mock.called)
|
||||||
|
|
||||||
|
def test_erase_devices_hdd_with_invalid_format_erase_pattern(
|
||||||
|
self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
|
task.driver.management.erase_devices,
|
||||||
|
task, erase_pattern=123)
|
||||||
|
|
||||||
|
def test_erase_devices_hdd_with_invalid_device_type_erase_pattern(
|
||||||
|
self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
|
task.driver.management.erase_devices,
|
||||||
|
task, erase_pattern={'xyz': 'block'})
|
||||||
|
|
||||||
|
def test_erase_devices_hdd_with_invalid_erase_pattern(
|
||||||
|
self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
self.assertRaises(exception.InvalidParameterValue,
|
||||||
|
task.driver.management.erase_devices,
|
||||||
|
task, erase_pattern={'ssd': 'xyz'})
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
@mock.patch.object(ilo_management.Ilo5Management, '_set_clean_failed')
|
||||||
|
def test_erase_devices_hdd_ilo_error(self, set_clean_failed_mock,
|
||||||
|
ilo_mock):
|
||||||
|
ilo_mock_object = ilo_mock.return_value
|
||||||
|
ilo_mock_object.get_available_disk_types.return_value = ['HDD']
|
||||||
|
exc = ilo_error.IloError('error')
|
||||||
|
ilo_mock_object.do_disk_erase.side_effect = exc
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=False) as task:
|
||||||
|
task.driver.management.erase_devices(task)
|
||||||
|
ilo_mock_object.do_disk_erase.assert_called_once_with(
|
||||||
|
'HDD', 'overwrite')
|
||||||
|
self.assertNotIn('ilo_disk_erase_hdd_check',
|
||||||
|
task.node.driver_internal_info)
|
||||||
|
self.assertNotIn('ilo_disk_erase_ssd_check',
|
||||||
|
task.node.driver_internal_info)
|
||||||
|
self.assertNotIn('cleaning_reboot',
|
||||||
|
task.node.driver_internal_info)
|
||||||
|
self.assertNotIn('skip_current_clean_step',
|
||||||
|
task.node.driver_internal_info)
|
||||||
|
set_clean_failed_mock.assert_called_once_with(
|
||||||
|
task, exc)
|
||||||
|
@ -57,7 +57,7 @@ class Ilo5RAIDTestCase(db_base.DbTestCase):
|
|||||||
enabled_console_interfaces=['ilo'],
|
enabled_console_interfaces=['ilo'],
|
||||||
enabled_deploy_interfaces=['iscsi'],
|
enabled_deploy_interfaces=['iscsi'],
|
||||||
enabled_inspect_interfaces=['ilo'],
|
enabled_inspect_interfaces=['ilo'],
|
||||||
enabled_management_interfaces=['ilo'],
|
enabled_management_interfaces=['ilo5'],
|
||||||
enabled_power_interfaces=['ilo'],
|
enabled_power_interfaces=['ilo'],
|
||||||
enabled_raid_interfaces=['ilo5'])
|
enabled_raid_interfaces=['ilo5'])
|
||||||
self.node = obj_utils.create_test_node(self.context, **n)
|
self.node = obj_utils.create_test_node(self.context, **n)
|
||||||
|
@ -19,6 +19,7 @@ Test class for iLO Drivers
|
|||||||
from ironic.conductor import task_manager
|
from ironic.conductor import task_manager
|
||||||
from ironic.drivers import ilo
|
from ironic.drivers import ilo
|
||||||
from ironic.drivers.modules import agent
|
from ironic.drivers.modules import agent
|
||||||
|
from ironic.drivers.modules.ilo import management
|
||||||
from ironic.drivers.modules.ilo import raid
|
from ironic.drivers.modules.ilo import raid
|
||||||
from ironic.drivers.modules import inspector
|
from ironic.drivers.modules import inspector
|
||||||
from ironic.drivers.modules import iscsi_deploy
|
from ironic.drivers.modules import iscsi_deploy
|
||||||
@ -177,7 +178,7 @@ class Ilo5HardwareTestCase(db_base.DbTestCase):
|
|||||||
enabled_console_interfaces=['ilo'],
|
enabled_console_interfaces=['ilo'],
|
||||||
enabled_deploy_interfaces=['iscsi', 'direct'],
|
enabled_deploy_interfaces=['iscsi', 'direct'],
|
||||||
enabled_inspect_interfaces=['ilo'],
|
enabled_inspect_interfaces=['ilo'],
|
||||||
enabled_management_interfaces=['ilo'],
|
enabled_management_interfaces=['ilo5'],
|
||||||
enabled_power_interfaces=['ilo'],
|
enabled_power_interfaces=['ilo'],
|
||||||
enabled_raid_interfaces=['ilo5'],
|
enabled_raid_interfaces=['ilo5'],
|
||||||
enabled_rescue_interfaces=['no-rescue', 'agent'],
|
enabled_rescue_interfaces=['no-rescue', 'agent'],
|
||||||
@ -187,6 +188,8 @@ class Ilo5HardwareTestCase(db_base.DbTestCase):
|
|||||||
node = obj_utils.create_test_node(self.context, driver='ilo5')
|
node = obj_utils.create_test_node(self.context, driver='ilo5')
|
||||||
with task_manager.acquire(self.context, node.id) as task:
|
with task_manager.acquire(self.context, node.id) as task:
|
||||||
self.assertIsInstance(task.driver.raid, raid.Ilo5RAID)
|
self.assertIsInstance(task.driver.raid, raid.Ilo5RAID)
|
||||||
|
self.assertIsInstance(task.driver.management,
|
||||||
|
management.Ilo5Management)
|
||||||
|
|
||||||
def test_override_with_no_raid(self):
|
def test_override_with_no_raid(self):
|
||||||
self.config(enabled_raid_interfaces=['no-raid', 'ilo5'])
|
self.config(enabled_raid_interfaces=['no-raid', 'ilo5'])
|
||||||
|
@ -0,0 +1,12 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Adds functionality to perform out-of-band sanitize disk-erase operation for
|
||||||
|
iLO5 based HPE Proliant servers. Management interface ``ilo5`` has been
|
||||||
|
added to ``ilo5`` hardware type. A clean step ``erase_devices`` has been
|
||||||
|
added to management interface ``ilo5`` to support this operation.
|
||||||
|
upgrade:
|
||||||
|
- The ``do_disk_erase``, ``has_disk_erase_completed`` and
|
||||||
|
``get_available_disk_types`` interfaces of 'proliantutils' library has been
|
||||||
|
enhanced to support out-of-band sanitize disk-erase operation for ``ilo5``
|
||||||
|
hardware type. To leverage this feature, the 'proliantutils' library needs
|
||||||
|
to be upgraded to version '2.9.0'.
|
@ -100,6 +100,7 @@ ironic.hardware.interfaces.management =
|
|||||||
ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
|
ibmc = ironic.drivers.modules.ibmc.management:IBMCManagement
|
||||||
idrac = ironic.drivers.modules.drac.management:DracManagement
|
idrac = ironic.drivers.modules.drac.management:DracManagement
|
||||||
ilo = ironic.drivers.modules.ilo.management:IloManagement
|
ilo = ironic.drivers.modules.ilo.management:IloManagement
|
||||||
|
ilo5 = ironic.drivers.modules.ilo.management:Ilo5Management
|
||||||
intel-ipmitool = ironic.drivers.modules.intel_ipmi.management:IntelIPMIManagement
|
intel-ipmitool = ironic.drivers.modules.intel_ipmi.management:IntelIPMIManagement
|
||||||
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
|
ipmitool = ironic.drivers.modules.ipmitool:IPMIManagement
|
||||||
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
|
irmc = ironic.drivers.modules.irmc.management:IRMCManagement
|
||||||
|
Loading…
x
Reference in New Issue
Block a user