OOB RAID implementation for ilo5 based HPE Proliant servers.
This commit adds functionality to perform out-of-band RAID operations for ilo5 based HPE Proliant servers. Using this a user can perform create and delete the RAID configuration from the server. Co-Authored-By: Paresh Sao <paresh.sao@hpe.com> Change-Id: Iad0c609e59dca56729967133c6bbcff73b50a51e Story: 2003349 Task: 24391
This commit is contained in:
parent
565cd192fc
commit
58a395bf83
@ -4,7 +4,7 @@
|
||||
# python projects they should package as optional dependencies for Ironic.
|
||||
|
||||
# These are available on pypi
|
||||
proliantutils>=2.6.0
|
||||
proliantutils>=2.7.0
|
||||
pysnmp>=4.3.0,<5.0.0
|
||||
python-ironic-inspector-client>=1.5.0
|
||||
python-scciclient>=0.8.0
|
||||
|
@ -126,3 +126,51 @@ def update_raid_info(node, raid_config):
|
||||
node.properties = properties
|
||||
|
||||
node.save()
|
||||
|
||||
|
||||
def filter_target_raid_config(
|
||||
node, create_root_volume=True, create_nonroot_volumes=True):
|
||||
"""Filter the target raid config based on root volume creation
|
||||
|
||||
This method can be used by any raid interface which wants to filter
|
||||
out target raid config based on condition whether the root volume
|
||||
will be created or not.
|
||||
|
||||
:param node: a node object
|
||||
:param create_root_volume: A boolean default value True governing
|
||||
if the root volume is returned else root volumes will be filtered
|
||||
out.
|
||||
:param create_nonroot_volumes: A boolean default value True governing
|
||||
if the non root volume is returned else non-root volumes will be
|
||||
filtered out.
|
||||
:raises: MissingParameterValue, if node.target_raid_config is missing
|
||||
or was found to be empty after skipping root volume and/or non-root
|
||||
volumes.
|
||||
:returns: It will return filtered target_raid_config
|
||||
"""
|
||||
if not node.target_raid_config:
|
||||
raise exception.MissingParameterValue(
|
||||
_("Node %s has no target RAID configuration.") % node.uuid)
|
||||
|
||||
target_raid_config = node.target_raid_config.copy()
|
||||
|
||||
error_msg_list = []
|
||||
if not create_root_volume:
|
||||
target_raid_config['logical_disks'] = [
|
||||
x for x in target_raid_config['logical_disks']
|
||||
if not x.get('is_root_volume')]
|
||||
error_msg_list.append(_("skipping root volume"))
|
||||
|
||||
if not create_nonroot_volumes:
|
||||
target_raid_config['logical_disks'] = [
|
||||
x for x in target_raid_config['logical_disks']
|
||||
if x.get('is_root_volume')]
|
||||
error_msg_list.append(_("skipping non-root volumes"))
|
||||
|
||||
if not target_raid_config['logical_disks']:
|
||||
error_msg = _(' and ').join(error_msg_list)
|
||||
raise exception.MissingParameterValue(
|
||||
_("Node %(node)s has empty target RAID configuration "
|
||||
"after %(msg)s.") % {'node': node.uuid, 'msg': error_msg})
|
||||
|
||||
return target_raid_config
|
||||
|
@ -22,6 +22,7 @@ from ironic.drivers.modules.ilo import console
|
||||
from ironic.drivers.modules.ilo import inspect
|
||||
from ironic.drivers.modules.ilo import management
|
||||
from ironic.drivers.modules.ilo import power
|
||||
from ironic.drivers.modules.ilo import raid
|
||||
from ironic.drivers.modules.ilo import vendor
|
||||
from ironic.drivers.modules import inspector
|
||||
from ironic.drivers.modules import noop
|
||||
@ -69,3 +70,15 @@ class IloHardware(generic.GenericHardware):
|
||||
def supported_vendor_interfaces(self):
|
||||
"""List of supported power interfaces."""
|
||||
return [vendor.VendorPassthru, noop.NoVendor]
|
||||
|
||||
|
||||
class Ilo5Hardware(IloHardware):
|
||||
"""iLO5 hardware type.
|
||||
|
||||
iLO5 hardware type is targeted for iLO5 based Proliant Gen10 servers.
|
||||
"""
|
||||
|
||||
@property
|
||||
def supported_raid_interfaces(self):
|
||||
"""List of supported raid interfaces."""
|
||||
return [raid.Ilo5RAID, noop.NoRAID]
|
||||
|
@ -698,32 +698,10 @@ class AgentRAID(base.RAIDInterface):
|
||||
'create_nonroot_volumes': create_nonroot_volumes,
|
||||
'target_raid_config': node.target_raid_config})
|
||||
|
||||
if not node.target_raid_config:
|
||||
raise exception.MissingParameterValue(
|
||||
_("Node %s has no target RAID configuration.") % node.uuid)
|
||||
|
||||
target_raid_config = node.target_raid_config.copy()
|
||||
|
||||
error_msg_list = []
|
||||
if not create_root_volume:
|
||||
target_raid_config['logical_disks'] = [
|
||||
x for x in target_raid_config['logical_disks']
|
||||
if not x.get('is_root_volume')]
|
||||
error_msg_list.append(_("skipping root volume"))
|
||||
|
||||
if not create_nonroot_volumes:
|
||||
error_msg_list.append(_("skipping non-root volumes"))
|
||||
|
||||
target_raid_config['logical_disks'] = [
|
||||
x for x in target_raid_config['logical_disks']
|
||||
if x.get('is_root_volume')]
|
||||
|
||||
if not target_raid_config['logical_disks']:
|
||||
error_msg = _(' and ').join(error_msg_list)
|
||||
raise exception.MissingParameterValue(
|
||||
_("Node %(node)s has empty target RAID configuration "
|
||||
"after %(msg)s.") % {'node': node.uuid, 'msg': error_msg})
|
||||
|
||||
target_raid_config = raid.filter_target_raid_config(
|
||||
node,
|
||||
create_root_volume=create_root_volume,
|
||||
create_nonroot_volumes=create_nonroot_volumes)
|
||||
# Rewrite it back to the node object, but no need to save it as
|
||||
# we need to just send this to the agent ramdisk.
|
||||
node.driver_internal_info['target_raid_config'] = target_raid_config
|
||||
|
235
ironic/drivers/modules/ilo/raid.py
Normal file
235
ironic/drivers/modules/ilo/raid.py
Normal file
@ -0,0 +1,235 @@
|
||||
# Copyright 2018 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
iLO5 RAID specific methods
|
||||
"""
|
||||
|
||||
from ironic_lib import metrics_utils
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import importutils
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import raid
|
||||
from ironic.common import states
|
||||
from ironic.conductor import utils as manager_utils
|
||||
from ironic import conf
|
||||
from ironic.drivers import base
|
||||
from ironic.drivers.modules import deploy_utils
|
||||
from ironic.drivers.modules.ilo import common as ilo_common
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
CONF = conf.CONF
|
||||
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||
|
||||
ilo_error = importutils.try_import('proliantutils.exception')
|
||||
|
||||
|
||||
class Ilo5RAID(base.RAIDInterface):
|
||||
"""Implementation of OOB RAIDInterface for iLO5."""
|
||||
|
||||
def get_properties(self):
|
||||
"""Return the properties of the interface."""
|
||||
return ilo_common.REQUIRED_PROPERTIES
|
||||
|
||||
def _set_clean_failed(self, task, msg, exc):
|
||||
LOG.error("RAID configuration 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 _set_driver_internal_true_value(self, task, *keys):
|
||||
driver_internal_info = task.node.driver_internal_info
|
||||
for key in keys:
|
||||
driver_internal_info[key] = True
|
||||
task.node.driver_internal_info = driver_internal_info
|
||||
task.node.save()
|
||||
|
||||
def _set_driver_internal_false_value(self, task, *keys):
|
||||
driver_internal_info = task.node.driver_internal_info
|
||||
for key in keys:
|
||||
driver_internal_info[key] = False
|
||||
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 _prepare_for_read_raid(self, task, raid_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)
|
||||
if raid_step == 'create_raid':
|
||||
self._set_driver_internal_true_value(
|
||||
task, 'ilo_raid_create_in_progress')
|
||||
else:
|
||||
self._set_driver_internal_true_value(
|
||||
task, 'ilo_raid_delete_in_progress')
|
||||
self._set_driver_internal_true_value(task, 'cleaning_reboot')
|
||||
self._set_driver_internal_false_value(task, 'skip_current_clean_step')
|
||||
|
||||
@METRICS.timer('Ilo5RAID.create_configuration')
|
||||
@base.clean_step(priority=0, abortable=False, argsinfo={
|
||||
'create_root_volume': {
|
||||
'description': (
|
||||
'This specifies whether to create the root volume. '
|
||||
'Defaults to `True`.'
|
||||
),
|
||||
'required': False
|
||||
},
|
||||
'create_nonroot_volumes': {
|
||||
'description': (
|
||||
'This specifies whether to create the non-root volumes. '
|
||||
'Defaults to `True`.'
|
||||
),
|
||||
'required': False
|
||||
}
|
||||
})
|
||||
def create_configuration(self, task, create_root_volume=True,
|
||||
create_nonroot_volumes=True):
|
||||
"""Create a RAID configuration on a bare metal using agent ramdisk.
|
||||
|
||||
This method creates a RAID configuration on the given node.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:param create_root_volume: If True, a root volume is created
|
||||
during RAID configuration. Otherwise, no root volume is
|
||||
created. Default is True.
|
||||
:param create_nonroot_volumes: If True, non-root volumes are
|
||||
created. If False, no non-root volumes are created. Default
|
||||
is True.
|
||||
:raises: MissingParameterValue, if node.target_raid_config is missing
|
||||
or was found to be empty after skipping root volume and/or non-root
|
||||
volumes.
|
||||
:raises: NodeCleaningFailure, on failure to execute step.
|
||||
"""
|
||||
node = task.node
|
||||
target_raid_config = raid.filter_target_raid_config(
|
||||
node, create_root_volume=create_root_volume,
|
||||
create_nonroot_volumes=create_nonroot_volumes)
|
||||
driver_internal_info = node.driver_internal_info
|
||||
driver_internal_info['target_raid_config'] = target_raid_config
|
||||
LOG.debug("Calling OOB RAID create_configuration for node %(node)s "
|
||||
"with the following target RAID configuration: %(target)s",
|
||||
{'node': node.uuid, 'target': target_raid_config})
|
||||
ilo_object = ilo_common.get_ilo_object(node)
|
||||
|
||||
try:
|
||||
# Raid configuration in progress, checking status
|
||||
if not driver_internal_info.get('ilo_raid_create_in_progress'):
|
||||
ilo_object.create_raid_configuration(target_raid_config)
|
||||
self._prepare_for_read_raid(task, 'create_raid')
|
||||
return states.CLEANWAIT
|
||||
else:
|
||||
# Raid configuration is done, updating raid_config
|
||||
raid_conf = (
|
||||
ilo_object.read_raid_configuration(
|
||||
raid_config=target_raid_config))
|
||||
if len(raid_conf['logical_disks']):
|
||||
raid.update_raid_info(node, raid_conf)
|
||||
LOG.debug("Node %(uuid)s raid create clean step is done.",
|
||||
{'uuid': node.uuid})
|
||||
self._pop_driver_internal_values(
|
||||
task, 'ilo_raid_create_in_progress',
|
||||
'cleaning_reboot', 'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
else:
|
||||
# Raid configuration failed
|
||||
msg = "Unable to create raid"
|
||||
self._pop_driver_internal_values(
|
||||
task, 'ilo_raid_create_in_progress',
|
||||
'cleaning_reboot', 'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
raise exception.NodeCleaningFailure(
|
||||
"Clean step create_configuration failed "
|
||||
"on node %(node)s with error: %(err)s" %
|
||||
{'node': node.uuid, 'err': msg})
|
||||
except ilo_error.IloError as ilo_exception:
|
||||
operation = (_("Failed to create raid configuration on node %s")
|
||||
% node.uuid)
|
||||
self._pop_driver_internal_values(task,
|
||||
'ilo_raid_create_in_progress',
|
||||
'cleaning_reboot',
|
||||
'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
self._set_clean_failed(task, operation, ilo_exception)
|
||||
|
||||
@METRICS.timer('Ilo5RAID.delete_configuration')
|
||||
@base.clean_step(priority=0, abortable=False)
|
||||
def delete_configuration(self, task):
|
||||
"""Delete the RAID configuration.
|
||||
|
||||
:param task: a TaskManager instance containing the node to act on.
|
||||
:raises: NodeCleaningFailure, on failure to execute step.
|
||||
"""
|
||||
node = task.node
|
||||
LOG.debug("OOB RAID delete_configuration invoked for node %s.",
|
||||
node.uuid)
|
||||
driver_internal_info = node.driver_internal_info
|
||||
ilo_object = ilo_common.get_ilo_object(node)
|
||||
|
||||
try:
|
||||
# Raid configuration in progress, checking status
|
||||
if not driver_internal_info.get('ilo_raid_delete_in_progress'):
|
||||
ilo_object.delete_raid_configuration()
|
||||
self._prepare_for_read_raid(task, 'delete_raid')
|
||||
return states.CLEANWAIT
|
||||
else:
|
||||
# Raid configuration is done, updating raid_config
|
||||
raid_conf = ilo_object.read_raid_configuration()
|
||||
if not len(raid_conf['logical_disks']):
|
||||
node.raid_config = {}
|
||||
LOG.debug("Node %(uuid)s raid delete clean step is done.",
|
||||
{'uuid': node.uuid})
|
||||
self._pop_driver_internal_values(
|
||||
task, 'ilo_raid_delete_in_progress',
|
||||
'cleaning_reboot', 'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
else:
|
||||
# Raid configuration failed
|
||||
msg = ("Unable to delete this logical disks: %s" %
|
||||
raid_conf['logical_disks'])
|
||||
self._pop_driver_internal_values(
|
||||
task, 'ilo_raid_delete_in_progress',
|
||||
'cleaning_reboot', 'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
raise exception.NodeCleaningFailure(
|
||||
"Clean step delete_configuration failed "
|
||||
"on node %(node)s with error: %(err)s" %
|
||||
{'node': node.uuid, 'err': msg})
|
||||
except ilo_error.IloLogicalDriveNotFoundError:
|
||||
LOG.info("No logical drive found to delete on node %(node)s",
|
||||
{'node': node.uuid})
|
||||
except ilo_error.IloError as ilo_exception:
|
||||
operation = (_("Failed to delete raid configuration on node %s")
|
||||
% node.uuid)
|
||||
self._pop_driver_internal_values(task,
|
||||
'ilo_raid_delete_in_progress',
|
||||
'cleaning_reboot',
|
||||
'skip_current_clean_step')
|
||||
node.driver_internal_info = driver_internal_info
|
||||
node.save()
|
||||
self._set_clean_failed(task, operation, ilo_exception)
|
@ -161,6 +161,21 @@ class ValidateRaidConfigurationTestCase(base.TestCase):
|
||||
|
||||
class RaidPublicMethodsTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(RaidPublicMethodsTestCase, self).setUp()
|
||||
self.target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True},
|
||||
{'size_gb': 200, 'raid_level': 5}
|
||||
]}
|
||||
n = {
|
||||
'boot_interface': 'pxe',
|
||||
'deploy_interface': 'direct',
|
||||
'raid_interface': 'agent',
|
||||
'target_raid_config': self.target_raid_config,
|
||||
}
|
||||
self.node = obj_utils.create_test_node(self.context, **n)
|
||||
|
||||
def test_get_logical_disk_properties(self):
|
||||
with open(drivers_base.RAID_CONFIG_SCHEMA, 'r') as raid_schema_fobj:
|
||||
schema = json.load(raid_schema_fobj)
|
||||
@ -186,7 +201,7 @@ class RaidPublicMethodsTestCase(db_base.DbTestCase):
|
||||
|
||||
def _test_update_raid_info(self, current_config,
|
||||
capabilities=None):
|
||||
node = obj_utils.create_test_node(self.context)
|
||||
node = self.node
|
||||
if capabilities:
|
||||
properties = node.properties
|
||||
properties['capabilities'] = capabilities
|
||||
@ -239,3 +254,37 @@ class RaidPublicMethodsTestCase(db_base.DbTestCase):
|
||||
self.assertRaises(exception.InvalidParameterValue,
|
||||
self._test_update_raid_info,
|
||||
current_config)
|
||||
|
||||
def test_filter_target_raid_config(self):
|
||||
result = raid.filter_target_raid_config(self.node)
|
||||
self.assertEqual(self.node.target_raid_config, result)
|
||||
|
||||
def test_filter_target_raid_config_skip_root(self):
|
||||
result = raid.filter_target_raid_config(
|
||||
self.node, create_root_volume=False)
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [{'size_gb': 200, 'raid_level': 5}]}
|
||||
self.assertEqual(exp_target_raid_config, result)
|
||||
|
||||
def test_filter_target_raid_config_skip_nonroot(self):
|
||||
result = raid.filter_target_raid_config(
|
||||
self.node, create_nonroot_volumes=False)
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [{'size_gb': 200,
|
||||
'raid_level': 0,
|
||||
'is_root_volume': True}]}
|
||||
self.assertEqual(exp_target_raid_config, result)
|
||||
|
||||
def test_filter_target_raid_config_no_target_raid_config_after_skipping(
|
||||
self):
|
||||
self.assertRaises(exception.MissingParameterValue,
|
||||
raid.filter_target_raid_config,
|
||||
self.node, create_root_volume=False,
|
||||
create_nonroot_volumes=False)
|
||||
|
||||
def test_filter_target_raid_config_empty_target_raid_config(self):
|
||||
self.node.target_raid_config = {}
|
||||
self.node.save()
|
||||
self.assertRaises(exception.MissingParameterValue,
|
||||
raid.filter_target_raid_config,
|
||||
self.node)
|
||||
|
342
ironic/tests/unit/drivers/modules/ilo/test_raid.py
Normal file
342
ironic/tests/unit/drivers/modules/ilo/test_raid.py
Normal file
@ -0,0 +1,342 @@
|
||||
# Copyright 2018 Hewlett Packard Enterprise Development LP
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Test class for Raid Interface used by iLO5."""
|
||||
|
||||
import mock
|
||||
from oslo_utils import importutils
|
||||
|
||||
from ironic.common import exception
|
||||
from ironic.common import raid
|
||||
from ironic.common import states
|
||||
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.ilo import common as ilo_common
|
||||
from ironic.drivers.modules.ilo import raid as ilo_raid
|
||||
from ironic.tests.unit.db import base as db_base
|
||||
from ironic.tests.unit.db import utils as db_utils
|
||||
from ironic.tests.unit.objects import utils as obj_utils
|
||||
|
||||
ilo_error = importutils.try_import('proliantutils.exception')
|
||||
|
||||
INFO_DICT = db_utils.get_test_ilo_info()
|
||||
|
||||
|
||||
class Ilo5RAIDTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Ilo5RAIDTestCase, self).setUp()
|
||||
self.driver = mock.Mock(raid=ilo_raid.Ilo5RAID())
|
||||
self.target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True},
|
||||
{'size_gb': 200, 'raid_level': 5}
|
||||
]}
|
||||
self.clean_step = {'step': 'create_configuration',
|
||||
'interface': 'raid'}
|
||||
n = {
|
||||
'driver': 'ilo5',
|
||||
'driver_info': INFO_DICT,
|
||||
'target_raid_config': self.target_raid_config,
|
||||
'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=['ilo'],
|
||||
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(manager_utils, 'node_power_action', autospec=True)
|
||||
def test__prepare_for_read_raid_create_raid(
|
||||
self, mock_reboot, mock_build_opt):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
mock_build_opt.return_value = []
|
||||
task.driver.raid._prepare_for_read_raid(task, 'create_raid')
|
||||
self.assertTrue(
|
||||
task.node.driver_internal_info.get(
|
||||
'ilo_raid_create_in_progress'))
|
||||
self.assertTrue(
|
||||
task.node.driver_internal_info.get(
|
||||
'cleaning_reboot'))
|
||||
self.assertFalse(
|
||||
task.node.driver_internal_info.get(
|
||||
'skip_current_clean_step'))
|
||||
mock_reboot.assert_called_once_with(task, states.REBOOT)
|
||||
|
||||
@mock.patch.object(deploy_utils, 'build_agent_options', autospec=True)
|
||||
@mock.patch.object(manager_utils, 'node_power_action', autospec=True)
|
||||
def test__prepare_for_read_raid_delete_raid(
|
||||
self, mock_reboot, mock_build_opt):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
mock_build_opt.return_value = []
|
||||
task.driver.raid._prepare_for_read_raid(task, 'delete_raid')
|
||||
self.assertTrue(
|
||||
task.node.driver_internal_info.get(
|
||||
'ilo_raid_delete_in_progress'))
|
||||
self.assertTrue(
|
||||
task.node.driver_internal_info.get(
|
||||
'cleaning_reboot'))
|
||||
self.assertEqual(
|
||||
task.node.driver_internal_info.get(
|
||||
'skip_current_clean_step'), False)
|
||||
mock_reboot.assert_called_once_with(task, states.REBOOT)
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid')
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration(
|
||||
self, ilo_mock, filter_target_raid_config_mock, prepare_raid_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
self.target_raid_config)
|
||||
result = task.driver.raid.create_configuration(task)
|
||||
prepare_raid_mock.assert_called_once_with(task, 'create_raid')
|
||||
(ilo_mock_object.create_raid_configuration.
|
||||
assert_called_once_with(self.target_raid_config))
|
||||
self.assertEqual(states.CLEANWAIT, result)
|
||||
|
||||
@mock.patch.object(raid, 'update_raid_info', autospec=True)
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_with_read_raid(
|
||||
self, ilo_mock, filter_target_raid_config_mock, update_raid_mock):
|
||||
raid_conf = {u'logical_disks':
|
||||
[{u'size_gb': 89,
|
||||
u'physical_disks': [u'5I:1:1'],
|
||||
u'raid_level': u'0',
|
||||
u'root_device_hint': {u'wwn': u'0x600508b1001c7e87'},
|
||||
u'controller': u'Smart Array P822 in Slot 1',
|
||||
u'volume_name': u'0006EB7BPDVTF0BRH5L0EAEDDA'}]
|
||||
}
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
self.node.driver_internal_info = {'ilo_raid_create_in_progress': True}
|
||||
self.node.save()
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
self.target_raid_config)
|
||||
ilo_mock_object.read_raid_configuration.return_value = raid_conf
|
||||
task.driver.raid.create_configuration(task)
|
||||
update_raid_mock.assert_called_once_with(task.node, raid_conf)
|
||||
self.assertNotIn('ilo_raid_create_in_progress',
|
||||
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)
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_with_read_raid_failed(
|
||||
self, ilo_mock, filter_target_raid_config_mock):
|
||||
raid_conf = {u'logical_disks': []}
|
||||
self.node.driver_internal_info = {'ilo_raid_create_in_progress': True}
|
||||
self.node.save()
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
self.target_raid_config)
|
||||
ilo_mock_object.read_raid_configuration.return_value = raid_conf
|
||||
self.assertRaises(exception.NodeCleaningFailure,
|
||||
task.driver.raid.create_configuration, task)
|
||||
self.assertNotIn('ilo_raid_create_in_progress',
|
||||
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)
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_empty_target_raid_config(
|
||||
self, ilo_mock, filter_target_raid_config_mock):
|
||||
self.node.target_raid_config = {}
|
||||
self.node.save()
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
msg = "Node %s has no target RAID configuration" % self.node.uuid
|
||||
filter_target_raid_config_mock.side_effect = (
|
||||
exception.MissingParameterValue(msg))
|
||||
self.assertRaises(exception.MissingParameterValue,
|
||||
task.driver.raid.create_configuration, task)
|
||||
self.assertFalse(ilo_mock_object.create_raid_configuration.called)
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid')
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_skip_root(
|
||||
self, ilo_mock, filter_target_raid_config_mock,
|
||||
prepare_raid_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 5}
|
||||
]}
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
exp_target_raid_config)
|
||||
result = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=False)
|
||||
(ilo_mock_object.create_raid_configuration.
|
||||
assert_called_once_with(exp_target_raid_config))
|
||||
self.assertEqual(states.CLEANWAIT, result)
|
||||
prepare_raid_mock.assert_called_once_with(task, 'create_raid')
|
||||
self.assertEqual(
|
||||
exp_target_raid_config,
|
||||
task.node.driver_internal_info['target_raid_config'])
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid')
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_skip_non_root(
|
||||
self, ilo_mock, filter_target_raid_config_mock, prepare_raid_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True}
|
||||
]}
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
exp_target_raid_config)
|
||||
result = task.driver.raid.create_configuration(
|
||||
task, create_nonroot_volumes=False)
|
||||
(ilo_mock_object.create_raid_configuration.
|
||||
assert_called_once_with(exp_target_raid_config))
|
||||
prepare_raid_mock.assert_called_once_with(task, 'create_raid')
|
||||
self.assertEqual(states.CLEANWAIT, result)
|
||||
self.assertEqual(
|
||||
exp_target_raid_config,
|
||||
task.node.driver_internal_info['target_raid_config'])
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_skip_root_skip_non_root(
|
||||
self, ilo_mock, filter_target_raid_config_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
msg = "Node %s has no target RAID configuration" % self.node.uuid
|
||||
filter_target_raid_config_mock.side_effect = (
|
||||
exception.MissingParameterValue(msg))
|
||||
self.assertRaises(
|
||||
exception.MissingParameterValue,
|
||||
task.driver.raid.create_configuration,
|
||||
task, False, False)
|
||||
self.assertFalse(ilo_mock_object.create_raid_configuration.called)
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_set_clean_failed')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_create_configuration_ilo_error(self, ilo_mock,
|
||||
set_clean_failed_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
exc = ilo_error.IloError('error')
|
||||
ilo_mock_object.create_raid_configuration.side_effect = exc
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.raid.create_configuration(
|
||||
task, create_nonroot_volumes=False)
|
||||
set_clean_failed_mock.assert_called_once_with(
|
||||
task,
|
||||
'Failed to create raid configuration '
|
||||
'on node %s' % self.node.uuid, exc)
|
||||
self.assertNotIn('ilo_raid_create_in_progress',
|
||||
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)
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_delete_configuration(self, ilo_mock, prepare_raid_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
result = task.driver.raid.delete_configuration(task)
|
||||
self.assertEqual(states.CLEANWAIT, result)
|
||||
ilo_mock_object.delete_raid_configuration.assert_called_once_with()
|
||||
prepare_raid_mock.assert_called_once_with(task, 'delete_raid')
|
||||
|
||||
@mock.patch.object(ilo_raid.LOG, 'info', spec_set=True,
|
||||
autospec=True)
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_prepare_for_read_raid')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_delete_configuration_no_logical_drive(
|
||||
self, ilo_mock, prepare_raid_mock, log_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
exc = ilo_error.IloLogicalDriveNotFoundError('No logical drive found')
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
ilo_mock_object.delete_raid_configuration.side_effect = exc
|
||||
task.driver.raid.delete_configuration(task)
|
||||
self.assertTrue(log_mock.called)
|
||||
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_delete_configuration_with_read_raid(self, ilo_mock):
|
||||
raid_conf = {u'logical_disks': []}
|
||||
self.node.driver_internal_info = {'ilo_raid_delete_in_progress': True}
|
||||
self.node.save()
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
ilo_mock_object.read_raid_configuration.return_value = raid_conf
|
||||
task.driver.raid.delete_configuration(task)
|
||||
self.assertEqual(self.node.raid_config, {})
|
||||
self.assertNotIn('ilo_raid_delete_in_progress',
|
||||
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)
|
||||
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_delete_configuration_with_read_raid_failed(self, ilo_mock):
|
||||
raid_conf = {u'logical_disks': [{'size_gb': 200,
|
||||
'raid_level': 0,
|
||||
'is_root_volume': True}]}
|
||||
self.node.driver_internal_info = {'ilo_raid_delete_in_progress': True}
|
||||
self.node.save()
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
ilo_mock_object.read_raid_configuration.return_value = raid_conf
|
||||
self.assertRaises(exception.NodeCleaningFailure,
|
||||
task.driver.raid.delete_configuration, task)
|
||||
self.assertNotIn('ilo_raid_delete_in_progress',
|
||||
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)
|
||||
|
||||
@mock.patch.object(ilo_raid.Ilo5RAID, '_set_clean_failed')
|
||||
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||
def test_delete_configuration_ilo_error(self, ilo_mock,
|
||||
set_clean_failed_mock):
|
||||
ilo_mock_object = ilo_mock.return_value
|
||||
exc = ilo_error.IloError('error')
|
||||
ilo_mock_object.delete_raid_configuration.side_effect = exc
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
task.driver.raid.delete_configuration(task)
|
||||
ilo_mock_object.delete_raid_configuration.assert_called_once_with()
|
||||
self.assertNotIn('ilo_raid_delete_in_progress',
|
||||
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,
|
||||
'Failed to delete raid configuration '
|
||||
'on node %s' % self.node.uuid, exc)
|
@ -1406,12 +1406,15 @@ class AgentRAIDTestCase(db_base.DbTestCase):
|
||||
self.assertEqual(0, ret[0]['priority'])
|
||||
self.assertEqual(0, ret[1]['priority'])
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(deploy_utils, 'agent_execute_clean_step',
|
||||
autospec=True)
|
||||
def test_create_configuration(self, execute_mock):
|
||||
def test_create_configuration(self, execute_mock,
|
||||
filter_target_raid_config_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
execute_mock.return_value = states.CLEANWAIT
|
||||
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
self.target_raid_config)
|
||||
return_value = task.driver.raid.create_configuration(task)
|
||||
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
@ -1420,65 +1423,76 @@ class AgentRAIDTestCase(db_base.DbTestCase):
|
||||
task.node.driver_internal_info['target_raid_config'])
|
||||
execute_mock.assert_called_once_with(task, self.clean_step)
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(deploy_utils, 'agent_execute_clean_step',
|
||||
autospec=True)
|
||||
def test_create_configuration_skip_root(self, execute_mock):
|
||||
def test_create_configuration_skip_root(self, execute_mock,
|
||||
filter_target_raid_config_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
execute_mock.return_value = states.CLEANWAIT
|
||||
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=False)
|
||||
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
execute_mock.assert_called_once_with(task, self.clean_step)
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 5}
|
||||
]}
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
exp_target_raid_config)
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_root_volume=False)
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
execute_mock.assert_called_once_with(task, self.clean_step)
|
||||
self.assertEqual(
|
||||
exp_target_raid_config,
|
||||
task.node.driver_internal_info['target_raid_config'])
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(deploy_utils, 'agent_execute_clean_step',
|
||||
autospec=True)
|
||||
def test_create_configuration_skip_nonroot(self, execute_mock):
|
||||
def test_create_configuration_skip_nonroot(self, execute_mock,
|
||||
filter_target_raid_config_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
execute_mock.return_value = states.CLEANWAIT
|
||||
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_nonroot_volumes=False)
|
||||
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
execute_mock.assert_called_once_with(task, self.clean_step)
|
||||
exp_target_raid_config = {
|
||||
"logical_disks": [
|
||||
{'size_gb': 200, 'raid_level': 0, 'is_root_volume': True},
|
||||
]}
|
||||
filter_target_raid_config_mock.return_value = (
|
||||
exp_target_raid_config)
|
||||
return_value = task.driver.raid.create_configuration(
|
||||
task, create_nonroot_volumes=False)
|
||||
self.assertEqual(states.CLEANWAIT, return_value)
|
||||
execute_mock.assert_called_once_with(task, self.clean_step)
|
||||
self.assertEqual(
|
||||
exp_target_raid_config,
|
||||
task.node.driver_internal_info['target_raid_config'])
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(deploy_utils, 'agent_execute_clean_step',
|
||||
autospec=True)
|
||||
def test_create_configuration_no_target_raid_config_after_skipping(
|
||||
self, execute_mock):
|
||||
self, execute_mock, filter_target_raid_config_mock):
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
msg = "Node %s has no target RAID configuration" % self.node.uuid
|
||||
filter_target_raid_config_mock.side_effect = (
|
||||
exception.MissingParameterValue(msg))
|
||||
self.assertRaises(
|
||||
exception.MissingParameterValue,
|
||||
task.driver.raid.create_configuration,
|
||||
task, create_root_volume=False,
|
||||
create_nonroot_volumes=False)
|
||||
|
||||
self.assertFalse(execute_mock.called)
|
||||
|
||||
@mock.patch.object(raid, 'filter_target_raid_config')
|
||||
@mock.patch.object(deploy_utils, 'agent_execute_clean_step',
|
||||
autospec=True)
|
||||
def test_create_configuration_empty_target_raid_config(
|
||||
self, execute_mock):
|
||||
self, execute_mock, filter_target_raid_config_mock):
|
||||
execute_mock.return_value = states.CLEANING
|
||||
self.node.target_raid_config = {}
|
||||
self.node.save()
|
||||
with task_manager.acquire(self.context, self.node.uuid) as task:
|
||||
msg = "Node %s has no target RAID configuration" % self.node.uuid
|
||||
filter_target_raid_config_mock.side_effect = (
|
||||
exception.MissingParameterValue(msg))
|
||||
self.assertRaises(exception.MissingParameterValue,
|
||||
task.driver.raid.create_configuration,
|
||||
task)
|
||||
|
@ -19,6 +19,7 @@ Test class for iLO Drivers
|
||||
from ironic.conductor import task_manager
|
||||
from ironic.drivers import ilo
|
||||
from ironic.drivers.modules import agent
|
||||
from ironic.drivers.modules.ilo import raid
|
||||
from ironic.drivers.modules import inspector
|
||||
from ironic.drivers.modules import iscsi_deploy
|
||||
from ironic.drivers.modules import noop
|
||||
@ -165,3 +166,47 @@ class IloHardwareTestCase(db_base.DbTestCase):
|
||||
agent.AgentDeploy)
|
||||
self.assertIsInstance(task.driver.raid,
|
||||
agent.AgentRAID)
|
||||
|
||||
|
||||
class Ilo5HardwareTestCase(db_base.DbTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Ilo5HardwareTestCase, self).setUp()
|
||||
self.config(enabled_hardware_types=['ilo5'],
|
||||
enabled_boot_interfaces=['ilo-virtual-media', 'ilo-pxe'],
|
||||
enabled_console_interfaces=['ilo'],
|
||||
enabled_deploy_interfaces=['iscsi', 'direct'],
|
||||
enabled_inspect_interfaces=['ilo'],
|
||||
enabled_management_interfaces=['ilo'],
|
||||
enabled_power_interfaces=['ilo'],
|
||||
enabled_raid_interfaces=['ilo5'],
|
||||
enabled_rescue_interfaces=['no-rescue', 'agent'],
|
||||
enabled_vendor_interfaces=['ilo', 'no-vendor'])
|
||||
|
||||
def test_default_interfaces(self):
|
||||
node = obj_utils.create_test_node(self.context, driver='ilo5')
|
||||
with task_manager.acquire(self.context, node.id) as task:
|
||||
self.assertIsInstance(task.driver.raid, raid.Ilo5RAID)
|
||||
|
||||
def test_override_with_no_raid(self):
|
||||
self.config(enabled_raid_interfaces=['no-raid', 'ilo5'])
|
||||
node = obj_utils.create_test_node(self.context, driver='ilo5',
|
||||
raid_interface='no-raid')
|
||||
with task_manager.acquire(self.context, node.id) as task:
|
||||
self.assertIsInstance(task.driver.raid, noop.NoRAID)
|
||||
self.assertIsInstance(task.driver.boot,
|
||||
ilo.boot.IloVirtualMediaBoot)
|
||||
self.assertIsInstance(task.driver.console,
|
||||
ilo.console.IloConsoleInterface)
|
||||
self.assertIsInstance(task.driver.deploy,
|
||||
iscsi_deploy.ISCSIDeploy)
|
||||
self.assertIsInstance(task.driver.inspect,
|
||||
ilo.inspect.IloInspect)
|
||||
self.assertIsInstance(task.driver.management,
|
||||
ilo.management.IloManagement)
|
||||
self.assertIsInstance(task.driver.power,
|
||||
ilo.power.IloPower)
|
||||
self.assertIsInstance(task.driver.rescue,
|
||||
noop.NoRescue)
|
||||
self.assertIsInstance(task.driver.vendor,
|
||||
ilo.vendor.VendorPassthru)
|
||||
|
@ -56,6 +56,8 @@ if not proliantutils:
|
||||
sys.modules['proliantutils.utils'] = proliantutils.utils
|
||||
proliantutils.utils.process_firmware_image = mock.MagicMock()
|
||||
proliantutils.exception.IloError = type('IloError', (Exception,), {})
|
||||
proliantutils.exception.IloLogicalDriveNotFoundError = (
|
||||
type('IloLogicalDriveNotFoundError', (Exception,), {}))
|
||||
command_exception = type('IloCommandNotSupportedError', (Exception,), {})
|
||||
proliantutils.exception.IloCommandNotSupportedError = command_exception
|
||||
proliantutils.exception.IloCommandNotSupportedInBiosError = type(
|
||||
|
12
releasenotes/notes/ilo5-oob-raid-a0eac60f7d77a4fc.yaml
Normal file
12
releasenotes/notes/ilo5-oob-raid-a0eac60f7d77a4fc.yaml
Normal file
@ -0,0 +1,12 @@
|
||||
---
|
||||
features:
|
||||
- Adds new hardware type ``ilo5``. Including all other hardware interfaces
|
||||
``ilo`` hardware type supports, this has one new RAID interface ``ilo5``.
|
||||
- Adds functionality to perform out-of-band RAID operation for iLO5 based
|
||||
HPE Proliant servers.
|
||||
upgrade:
|
||||
- The ``create_raid_configuration``, ``delete_raid_configuration`` and
|
||||
``read_raid_configuration`` interfaces of 'proliantutils' library has been
|
||||
enhanced to support out-of-band RAID operation for ``ilo5`` hardware type.
|
||||
To leverage this feature, the 'proliantutils' library needs to be upgraded
|
||||
to version '2.7.0'.
|
@ -125,6 +125,7 @@ ironic.hardware.interfaces.raid =
|
||||
agent = ironic.drivers.modules.agent:AgentRAID
|
||||
fake = ironic.drivers.modules.fake:FakeRAID
|
||||
idrac = ironic.drivers.modules.drac.raid:DracRAID
|
||||
ilo5 = ironic.drivers.modules.ilo.raid:Ilo5RAID
|
||||
irmc = ironic.drivers.modules.irmc.raid:IRMCRAID
|
||||
no-raid = ironic.drivers.modules.noop:NoRAID
|
||||
|
||||
@ -152,6 +153,7 @@ ironic.hardware.types =
|
||||
fake-hardware = ironic.drivers.fake_hardware:FakeHardware
|
||||
idrac = ironic.drivers.drac:IDRACHardware
|
||||
ilo = ironic.drivers.ilo:IloHardware
|
||||
ilo5 = ironic.drivers.ilo:Ilo5Hardware
|
||||
ipmi = ironic.drivers.ipmi:IPMIHardware
|
||||
irmc = ironic.drivers.irmc:IRMCHardware
|
||||
manual-management = ironic.drivers.generic:ManualManagementHardware
|
||||
|
Loading…
Reference in New Issue
Block a user