iLO BIOS interface implementation
Adds support for manual cleaning steps "apply_configuration" and "factory_reset" which manage BIOS settings on the iLO. This requires to implement 'ilo' BIOS interface for 'ilo' hardware type. Story: #2002899 Task: #22863 Change-Id: Ia014ea3d55504e8e0c815fb4f19bb87b1fc0d6ef
This commit is contained in:
parent
afbe8e7679
commit
66e1ccb7c5
@ -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.5.0
|
proliantutils>=2.6.0
|
||||||
pysnmp>=4.3.0,<5.0.0
|
pysnmp>=4.3.0,<5.0.0
|
||||||
python-ironic-inspector-client>=1.5.0
|
python-ironic-inspector-client>=1.5.0
|
||||||
python-oneviewclient<3.0.0,>=2.5.2
|
python-oneviewclient<3.0.0,>=2.5.2
|
||||||
|
@ -16,6 +16,7 @@ iLO Driver for managing HP Proliant Gen8 and above servers.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from ironic.drivers import generic
|
from ironic.drivers import generic
|
||||||
|
from ironic.drivers.modules.ilo import bios
|
||||||
from ironic.drivers.modules.ilo import boot
|
from ironic.drivers.modules.ilo import boot
|
||||||
from ironic.drivers.modules.ilo import console
|
from ironic.drivers.modules.ilo import console
|
||||||
from ironic.drivers.modules.ilo import inspect
|
from ironic.drivers.modules.ilo import inspect
|
||||||
@ -38,6 +39,11 @@ class IloHardware(generic.GenericHardware):
|
|||||||
"""List of supported boot interfaces."""
|
"""List of supported boot interfaces."""
|
||||||
return [boot.IloVirtualMediaBoot, boot.IloPXEBoot]
|
return [boot.IloVirtualMediaBoot, boot.IloPXEBoot]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def supported_bios_interfaces(self):
|
||||||
|
"""List of supported bios interfaces."""
|
||||||
|
return [bios.IloBIOS, noop.NoBIOS]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def supported_console_interfaces(self):
|
def supported_console_interfaces(self):
|
||||||
"""List of supported console interfaces."""
|
"""List of supported console interfaces."""
|
||||||
|
157
ironic/drivers/modules/ilo/bios.py
Normal file
157
ironic/drivers/modules/ilo/bios.py
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
# Copyright 2018 Hewlett-Packard Development Company, L.P.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
"""
|
||||||
|
iLO BIOS Interface
|
||||||
|
"""
|
||||||
|
|
||||||
|
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.drivers import base
|
||||||
|
from ironic.drivers.modules.ilo import common as ilo_common
|
||||||
|
from ironic import objects
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
METRICS = metrics_utils.get_metrics_logger(__name__)
|
||||||
|
|
||||||
|
ilo_error = importutils.try_import('proliantutils.exception')
|
||||||
|
|
||||||
|
|
||||||
|
class IloBIOS(base.BIOSInterface):
|
||||||
|
|
||||||
|
def get_properties(self):
|
||||||
|
return ilo_common.REQUIRED_PROPERTIES
|
||||||
|
|
||||||
|
@METRICS.timer('IloBIOS.validate')
|
||||||
|
def validate(self, task):
|
||||||
|
"""Check that 'driver_info' contains required ILO credentials.
|
||||||
|
|
||||||
|
Validates whether the 'driver_info' property of the supplied
|
||||||
|
task's node contains the required credentials information.
|
||||||
|
|
||||||
|
:param task: a task from TaskManager.
|
||||||
|
:raises: InvalidParameterValue if required iLO parameters
|
||||||
|
are not valid.
|
||||||
|
:raises: MissingParameterValue if a required parameter is missing.
|
||||||
|
"""
|
||||||
|
ilo_common.parse_driver_info(task.node)
|
||||||
|
|
||||||
|
@METRICS.timer('IloBIOS.apply_configuration')
|
||||||
|
@base.clean_step(priority=0, abortable=False, argsinfo={
|
||||||
|
'settings': {
|
||||||
|
'description': "Dictionary with current BIOS configuration.",
|
||||||
|
'required': True
|
||||||
|
}
|
||||||
|
})
|
||||||
|
def apply_configuration(self, task, settings):
|
||||||
|
"""Applies the provided configuration on the node.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:param settings: Settings intended to be applied on the node.
|
||||||
|
:raises: NodeCleaningFailure when applying the configuration on
|
||||||
|
the node fails.
|
||||||
|
|
||||||
|
"""
|
||||||
|
data = {}
|
||||||
|
for setting in settings:
|
||||||
|
data.update({setting['name']: setting['value']})
|
||||||
|
|
||||||
|
node = task.node
|
||||||
|
|
||||||
|
errmsg = _("Clean step \"apply_configuration\" failed "
|
||||||
|
"on node %(node)s with error: %(err)s")
|
||||||
|
|
||||||
|
try:
|
||||||
|
ilo_object = ilo_common.get_ilo_object(node)
|
||||||
|
ilo_object.set_bios_settings(data)
|
||||||
|
except (exception.MissingParameterValue,
|
||||||
|
exception.InvalidParameterValue,
|
||||||
|
ilo_error.IloError,
|
||||||
|
ilo_error.IloCommandNotSupportedError) as ir_exception:
|
||||||
|
raise exception.NodeCleaningFailure(
|
||||||
|
errmsg % {'node': node.uuid, 'err': ir_exception})
|
||||||
|
|
||||||
|
@METRICS.timer('IloBIOS.factory_reset')
|
||||||
|
@base.clean_step(priority=0, abortable=False)
|
||||||
|
def factory_reset(self, task):
|
||||||
|
"""Reset the BIOS settings to factory configuration.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:raises: NodeCleaningFailure when IloError or any other exception
|
||||||
|
is caught.
|
||||||
|
|
||||||
|
"""
|
||||||
|
node = task.node
|
||||||
|
|
||||||
|
errmsg = _("Clean step \"factory_reset\" failed "
|
||||||
|
"on node %(node)s with error: %(err)s")
|
||||||
|
|
||||||
|
try:
|
||||||
|
ilo_object = ilo_common.get_ilo_object(node)
|
||||||
|
ilo_object.reset_bios_to_default()
|
||||||
|
except (exception.MissingParameterValue,
|
||||||
|
exception.InvalidParameterValue,
|
||||||
|
ilo_error.IloError,
|
||||||
|
ilo_error.IloCommandNotSupportedError) as ir_exception:
|
||||||
|
raise exception.NodeCleaningFailure(
|
||||||
|
errmsg % {'node': node.uuid, 'err': ir_exception})
|
||||||
|
|
||||||
|
@METRICS.timer('IloBIOS.cache_bios_settings')
|
||||||
|
def cache_bios_settings(self, task):
|
||||||
|
"""Store the BIOS settings in the database.
|
||||||
|
|
||||||
|
:param task: a TaskManager instance.
|
||||||
|
:raises: NodeCleaningFailure when IloError or any other exception
|
||||||
|
is caught.
|
||||||
|
|
||||||
|
"""
|
||||||
|
node = task.node
|
||||||
|
nodeid = node.id
|
||||||
|
|
||||||
|
errmsg = _("Caching BIOS settings failed "
|
||||||
|
"on node %(node)s with error: %(err)s")
|
||||||
|
try:
|
||||||
|
ilo_object = ilo_common.get_ilo_object(node)
|
||||||
|
bios_settings = ilo_object.get_pending_bios_settings()
|
||||||
|
|
||||||
|
except (exception.MissingParameterValue,
|
||||||
|
exception.InvalidParameterValue,
|
||||||
|
ilo_error.IloError,
|
||||||
|
ilo_error.IloCommandNotSupportedError) as ir_exception:
|
||||||
|
raise exception.NodeCleaningFailure(
|
||||||
|
errmsg % {'node': node.uuid, 'err': ir_exception})
|
||||||
|
|
||||||
|
fmt_bios_settings = []
|
||||||
|
|
||||||
|
for setting in bios_settings:
|
||||||
|
fmt_bios_settings.append({"name": setting,
|
||||||
|
"value": bios_settings[setting]})
|
||||||
|
|
||||||
|
create_list, update_list, delete_list, nochange_list = (
|
||||||
|
objects.BIOSSettingList.sync_node_setting(task.context,
|
||||||
|
nodeid,
|
||||||
|
fmt_bios_settings))
|
||||||
|
if len(create_list) > 0:
|
||||||
|
objects.BIOSSettingList.create(task.context, nodeid, create_list)
|
||||||
|
if len(update_list) > 0:
|
||||||
|
objects.BIOSSettingList.save(task.context, nodeid, update_list)
|
||||||
|
if len(delete_list) > 0:
|
||||||
|
delete_name_list = [delete_name.get(
|
||||||
|
"name") for delete_name in delete_list]
|
||||||
|
objects.BIOSSettingList.delete(
|
||||||
|
task.context, nodeid, delete_name_list)
|
287
ironic/tests/unit/drivers/modules/ilo/test_bios.py
Normal file
287
ironic/tests/unit/drivers/modules/ilo/test_bios.py
Normal file
@ -0,0 +1,287 @@
|
|||||||
|
# Copyright 2018 Hewlett-Packard Development Company, L.P.
|
||||||
|
# All Rights Reserved.
|
||||||
|
#
|
||||||
|
# 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 IloPower module."""
|
||||||
|
|
||||||
|
import mock
|
||||||
|
from oslo_config import cfg
|
||||||
|
from oslo_utils import importutils
|
||||||
|
|
||||||
|
from ironic.common import exception
|
||||||
|
from ironic.conductor import task_manager
|
||||||
|
from ironic.drivers.modules.ilo import common as ilo_common
|
||||||
|
from ironic import objects
|
||||||
|
from ironic.tests.unit.db import utils as db_utils
|
||||||
|
from ironic.tests.unit.drivers.modules.ilo import test_common
|
||||||
|
|
||||||
|
ilo_error = importutils.try_import('proliantutils.exception')
|
||||||
|
|
||||||
|
INFO_DICT = db_utils.get_test_ilo_info()
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class IloBiosTestCase(test_common.BaseIloTest):
|
||||||
|
|
||||||
|
def test_get_properties(self):
|
||||||
|
expected = ilo_common.REQUIRED_PROPERTIES
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
self.assertEqual(expected, task.driver.bios.get_properties())
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'parse_driver_info', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_validate(self, mock_drvinfo):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
task.driver.bios.validate(task)
|
||||||
|
mock_drvinfo.assert_called_once_with(task.node)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def _test_ilo_error(self, error_type,
|
||||||
|
test_methods_not_called, method_details, ilo_mock):
|
||||||
|
error_dict = {
|
||||||
|
"missing_parameter": exception.MissingParameterValue,
|
||||||
|
"invalid_parameter": exception.InvalidParameterValue
|
||||||
|
}
|
||||||
|
|
||||||
|
exc = error_dict.get(error_type)('error')
|
||||||
|
ilo_mock.side_effect = exc
|
||||||
|
method = method_details.get("name")
|
||||||
|
args = method_details.get("args")
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
method,
|
||||||
|
*args)
|
||||||
|
for test_method in test_methods_not_called:
|
||||||
|
eval("ilo_mock.return_value.%s.assert_not_called()" % (
|
||||||
|
test_method))
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_apply_configuration(self, get_ilo_object_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
data = [
|
||||||
|
{
|
||||||
|
"name": "SET_A", "value": "VAL_A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SET_B", "value": "VAL_B",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SET_C", "value": "VAL_C",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SET_D", "value": "VAL_D",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
task.driver.bios.apply_configuration(task, data)
|
||||||
|
expected = {
|
||||||
|
"SET_A": "VAL_A",
|
||||||
|
"SET_B": "VAL_B",
|
||||||
|
"SET_C": "VAL_C",
|
||||||
|
"SET_D": "VAL_D"
|
||||||
|
}
|
||||||
|
ilo_object_mock.set_bios_settings.assert_called_once_with(expected)
|
||||||
|
|
||||||
|
def test_apply_configuration_missing_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.apply_configuration,
|
||||||
|
"args": (task, [])
|
||||||
|
}
|
||||||
|
self._test_ilo_error("missing_parameter", ["set_bios_settings"],
|
||||||
|
mdobj)
|
||||||
|
|
||||||
|
def test_apply_configuration_invalid_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.apply_configuration,
|
||||||
|
"args": (task, [])
|
||||||
|
}
|
||||||
|
self._test_ilo_error("invalid_parameter", ["set_bios_settings"],
|
||||||
|
mdobj)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_apply_configuration_with_ilo_error(self, get_ilo_object_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
data = [
|
||||||
|
{
|
||||||
|
"name": "SET_A", "value": "VAL_A",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "SET_B", "value": "VAL_B",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
exc = ilo_error.IloError('error')
|
||||||
|
ilo_object_mock.set_bios_settings.side_effect = exc
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
task.driver.bios.apply_configuration,
|
||||||
|
task, data)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_factory_reset(self, get_ilo_object_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
task.driver.bios.factory_reset(task)
|
||||||
|
ilo_object_mock.reset_bios_to_default.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_factory_reset_missing_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.factory_reset,
|
||||||
|
"args": (task,)
|
||||||
|
}
|
||||||
|
self._test_ilo_error("missing_parameter",
|
||||||
|
["reset_bios_to_default"], mdobj)
|
||||||
|
|
||||||
|
def test_factory_reset_invalid_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.factory_reset,
|
||||||
|
"args": (task,)
|
||||||
|
}
|
||||||
|
self._test_ilo_error("invalid_parameter",
|
||||||
|
["reset_bios_to_default"], mdobj)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_factory_reset_with_ilo_error(self, get_ilo_object_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
exc = ilo_error.IloError('error')
|
||||||
|
ilo_object_mock.reset_bios_to_default.side_effect = exc
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
task.driver.bios.factory_reset, task)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', spec_set=True,
|
||||||
|
autospec=True)
|
||||||
|
def test_factory_reset_with_unknown_error(self, get_ilo_object_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
exc = ilo_error.IloCommandNotSupportedError('error')
|
||||||
|
ilo_object_mock.reset_bios_to_default.side_effect = exc
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
task.driver.bios.factory_reset, task)
|
||||||
|
|
||||||
|
@mock.patch.object(objects.BIOSSettingList, 'create')
|
||||||
|
@mock.patch.object(objects.BIOSSettingList, 'save')
|
||||||
|
@mock.patch.object(objects.BIOSSettingList, 'delete')
|
||||||
|
@mock.patch.object(objects.BIOSSettingList, 'sync_node_setting')
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
def test_cache_bios_settings(self, get_ilo_object_mock, sync_node_mock,
|
||||||
|
delete_mock, save_mock, create_mock):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
settings = {
|
||||||
|
"SET_A": True,
|
||||||
|
"SET_B": True,
|
||||||
|
"SET_C": True,
|
||||||
|
"SET_D": True
|
||||||
|
}
|
||||||
|
|
||||||
|
ilo_object_mock.get_pending_bios_settings.return_value = settings
|
||||||
|
expected_bios_settings = [
|
||||||
|
{"name": "SET_A", "value": True},
|
||||||
|
{"name": "SET_B", "value": True},
|
||||||
|
{"name": "SET_C", "value": True},
|
||||||
|
{"name": "SET_D", "value": True}
|
||||||
|
]
|
||||||
|
sync_node_mock.return_value = ([], [], [], [])
|
||||||
|
all_settings = (
|
||||||
|
[
|
||||||
|
{"name": "C_1", "value": "C_1_VAL"},
|
||||||
|
{"name": "C_2", "value": "C_2_VAL"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"name": "U_1", "value": "U_1_VAL"},
|
||||||
|
{"name": "U_2", "value": "U_2_VAL"}
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{"name": "D_1", "value": "D_1_VAL"},
|
||||||
|
{"name": "D_2", "value": "D_2_VAL"}
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
sync_node_mock.return_value = all_settings
|
||||||
|
task.driver.bios.cache_bios_settings(task)
|
||||||
|
ilo_object_mock.get_pending_bios_settings.assert_called_once_with()
|
||||||
|
actual_arg = sorted(sync_node_mock.call_args[0][2],
|
||||||
|
key=lambda x: x.get("name"))
|
||||||
|
expected_arg = sorted(expected_bios_settings,
|
||||||
|
key=lambda x: x.get("name"))
|
||||||
|
self.assertEqual(actual_arg, expected_arg)
|
||||||
|
create_mock.assert_called_once_with(
|
||||||
|
self.context, task.node.id, all_settings[0])
|
||||||
|
save_mock.assert_called_once_with(
|
||||||
|
self.context, task.node.id, all_settings[1])
|
||||||
|
del_names = [setting.get("name") for setting in all_settings[2]]
|
||||||
|
delete_mock.assert_called_once_with(
|
||||||
|
self.context, task.node.id, del_names)
|
||||||
|
|
||||||
|
def test_cache_bios_settings_missing_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.cache_bios_settings,
|
||||||
|
"args": (task,)
|
||||||
|
}
|
||||||
|
self._test_ilo_error("missing_parameter",
|
||||||
|
["get_pending_bios_settings"], mdobj)
|
||||||
|
|
||||||
|
def test_cache_bios_settings_invalid_parameter(self):
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
mdobj = {
|
||||||
|
"name": task.driver.bios.cache_bios_settings,
|
||||||
|
"args": (task,)
|
||||||
|
}
|
||||||
|
self._test_ilo_error("invalid_parameter",
|
||||||
|
["get_pending_bios_settings"], mdobj)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
def test_cache_bios_settings_with_ilo_error(self, get_ilo_object_mock):
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
exc = ilo_error.IloError('error')
|
||||||
|
ilo_object_mock.get_pending_bios_settings.side_effect = exc
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
task.driver.bios.cache_bios_settings, task)
|
||||||
|
|
||||||
|
@mock.patch.object(ilo_common, 'get_ilo_object', autospec=True)
|
||||||
|
def test_cache_bios_settings_with_unknown_error(self, get_ilo_object_mock):
|
||||||
|
|
||||||
|
with task_manager.acquire(self.context, self.node.uuid,
|
||||||
|
shared=True) as task:
|
||||||
|
ilo_object_mock = get_ilo_object_mock.return_value
|
||||||
|
exc = ilo_error.IloCommandNotSupportedError('error')
|
||||||
|
ilo_object_mock.get_pending_bios_settings.side_effect = exc
|
||||||
|
self.assertRaises(exception.NodeCleaningFailure,
|
||||||
|
task.driver.bios.cache_bios_settings, task)
|
@ -62,6 +62,7 @@ class BaseIloTest(db_base.DbTestCase):
|
|||||||
self.config(enabled_hardware_types=['ilo', 'fake-hardware'],
|
self.config(enabled_hardware_types=['ilo', 'fake-hardware'],
|
||||||
enabled_boot_interfaces=['ilo-pxe', 'ilo-virtual-media',
|
enabled_boot_interfaces=['ilo-pxe', 'ilo-virtual-media',
|
||||||
'fake'],
|
'fake'],
|
||||||
|
enabled_bios_interfaces=['ilo', 'no-bios'],
|
||||||
enabled_power_interfaces=['ilo', 'fake'],
|
enabled_power_interfaces=['ilo', 'fake'],
|
||||||
enabled_management_interfaces=['ilo', 'fake'],
|
enabled_management_interfaces=['ilo', 'fake'],
|
||||||
enabled_inspect_interfaces=['ilo', 'fake', 'no-inspect'],
|
enabled_inspect_interfaces=['ilo', 'fake', 'no-inspect'],
|
||||||
@ -71,6 +72,7 @@ class BaseIloTest(db_base.DbTestCase):
|
|||||||
self.node = obj_utils.create_test_node(
|
self.node = obj_utils.create_test_node(
|
||||||
self.context, uuid=uuidutils.generate_uuid(),
|
self.context, uuid=uuidutils.generate_uuid(),
|
||||||
driver='ilo', boot_interface=self.boot_interface,
|
driver='ilo', boot_interface=self.boot_interface,
|
||||||
|
bios_interface='ilo',
|
||||||
driver_info=self.info)
|
driver_info=self.info)
|
||||||
|
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ class IloHardwareTestCase(db_base.DbTestCase):
|
|||||||
super(IloHardwareTestCase, self).setUp()
|
super(IloHardwareTestCase, self).setUp()
|
||||||
self.config(enabled_hardware_types=['ilo'],
|
self.config(enabled_hardware_types=['ilo'],
|
||||||
enabled_boot_interfaces=['ilo-virtual-media', 'ilo-pxe'],
|
enabled_boot_interfaces=['ilo-virtual-media', 'ilo-pxe'],
|
||||||
|
enabled_bios_interfaces=['no-bios', 'ilo'],
|
||||||
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'],
|
||||||
@ -47,6 +48,8 @@ class IloHardwareTestCase(db_base.DbTestCase):
|
|||||||
with task_manager.acquire(self.context, node.id) as task:
|
with task_manager.acquire(self.context, node.id) as task:
|
||||||
self.assertIsInstance(task.driver.boot,
|
self.assertIsInstance(task.driver.boot,
|
||||||
ilo.boot.IloVirtualMediaBoot)
|
ilo.boot.IloVirtualMediaBoot)
|
||||||
|
self.assertIsInstance(task.driver.bios,
|
||||||
|
ilo.bios.IloBIOS)
|
||||||
self.assertIsInstance(task.driver.console,
|
self.assertIsInstance(task.driver.console,
|
||||||
ilo.console.IloConsoleInterface)
|
ilo.console.IloConsoleInterface)
|
||||||
self.assertIsInstance(task.driver.deploy,
|
self.assertIsInstance(task.driver.deploy,
|
||||||
@ -143,3 +146,22 @@ class IloHardwareTestCase(db_base.DbTestCase):
|
|||||||
agent.AgentRescue)
|
agent.AgentRescue)
|
||||||
self.assertIsInstance(task.driver.vendor,
|
self.assertIsInstance(task.driver.vendor,
|
||||||
ilo.vendor.VendorPassthru)
|
ilo.vendor.VendorPassthru)
|
||||||
|
|
||||||
|
def test_override_with_no_bios(self):
|
||||||
|
node = obj_utils.create_test_node(
|
||||||
|
self.context, driver='ilo',
|
||||||
|
boot_interface='ilo-pxe',
|
||||||
|
bios_interface='no-bios',
|
||||||
|
deploy_interface='direct',
|
||||||
|
raid_interface='agent')
|
||||||
|
with task_manager.acquire(self.context, node.id) as task:
|
||||||
|
self.assertIsInstance(task.driver.boot,
|
||||||
|
ilo.boot.IloPXEBoot)
|
||||||
|
self.assertIsInstance(task.driver.bios,
|
||||||
|
noop.NoBIOS)
|
||||||
|
self.assertIsInstance(task.driver.console,
|
||||||
|
ilo.console.IloConsoleInterface)
|
||||||
|
self.assertIsInstance(task.driver.deploy,
|
||||||
|
agent.AgentDeploy)
|
||||||
|
self.assertIsInstance(task.driver.raid,
|
||||||
|
agent.AgentRAID)
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Implements ``bios`` interface for ``ilo`` hardware type.
|
||||||
|
Adds the list of supported bios interfaces for the `ilo` hardware type.
|
||||||
|
Adds manual cleaning steps ``apply_configuration`` and ``factory_reset``
|
||||||
|
which support managing the BIOS settings for the iLO servers using `ilo`
|
||||||
|
hardware type.
|
@ -54,6 +54,7 @@ ironic.dhcp =
|
|||||||
|
|
||||||
ironic.hardware.interfaces.bios =
|
ironic.hardware.interfaces.bios =
|
||||||
fake = ironic.drivers.modules.fake:FakeBIOS
|
fake = ironic.drivers.modules.fake:FakeBIOS
|
||||||
|
ilo = ironic.drivers.modules.ilo.bios:IloBIOS
|
||||||
irmc = ironic.drivers.modules.irmc.bios:IRMCBIOS
|
irmc = ironic.drivers.modules.irmc.bios:IRMCBIOS
|
||||||
no-bios = ironic.drivers.modules.noop:NoBIOS
|
no-bios = ironic.drivers.modules.noop:NoBIOS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user