BIOS Settings: Add BIOSInterface
* Adds 'bios' interface to 'BaseDriver' * Adds BIOSInterface driver class * Adds fake & no-bios drivers and entries * Implements it for 'fake-hardare' hardware type * Adds configuration parameters: + [DEFAULT]/enabled_bios_interfaces + [DEFAULT]/default_bios_interface * Adds 'bios_interface' field to Node object * Handle 'bios_interface' field in _convert_to_version * Adds bios in CLEANING_INTERFACE_PRIORITY Drivers can implement this interface to do BIOS configuration. Co-Authored-By: Yolanda Robla Mota <yroblamo@redhat.com> Co-Authored-By: Luong Anh Tuan <tuanla@vn.fujitsu.com> Change-Id: I7e57130242b6cab21b54e35dc3c0b7819bdc43c0 Story: #1712032
This commit is contained in:
parent
02aad838a5
commit
1e24ef9dde
@ -596,7 +596,8 @@ def calculate_migration_delta(driver_name, driver_class,
|
||||
None if a migration is not possible.
|
||||
"""
|
||||
# NOTE(dtantsur): provide defaults for optional interfaces
|
||||
defaults = {'console': 'no-console',
|
||||
defaults = {'bios': 'no-bios',
|
||||
'console': 'no-console',
|
||||
'inspect': 'no-inspect',
|
||||
'raid': 'no-raid',
|
||||
'rescue': 'no-rescue',
|
||||
|
@ -103,7 +103,7 @@ RELEASE_MAPPING = {
|
||||
'api': '1.39',
|
||||
'rpc': '1.44',
|
||||
'objects': {
|
||||
'Node': ['1.23'],
|
||||
'Node': ['1.24'],
|
||||
'Conductor': ['1.2'],
|
||||
'Chassis': ['1.3'],
|
||||
'Port': ['1.8'],
|
||||
|
@ -1869,6 +1869,11 @@ class ConductorManager(base_manager.BaseConductorManager):
|
||||
task.node.instance_info)
|
||||
task.node.driver_internal_info['is_whole_disk_image'] = iwdi
|
||||
for iface_name in task.driver.non_vendor_interfaces:
|
||||
# TODO(zshi): Remove this check in 'bios' API patch
|
||||
# Do not have to return the validation result for 'bios'
|
||||
# interface.
|
||||
if iface_name == 'bios':
|
||||
continue
|
||||
iface = getattr(task.driver, iface_name, None)
|
||||
result = reason = None
|
||||
if iface:
|
||||
|
@ -34,9 +34,10 @@ CLEANING_INTERFACE_PRIORITY = {
|
||||
# by which interface is implementing the clean step. The clean step of the
|
||||
# interface with the highest value here, will be executed first in that
|
||||
# case.
|
||||
'power': 4,
|
||||
'management': 3,
|
||||
'deploy': 2,
|
||||
'power': 5,
|
||||
'management': 4,
|
||||
'deploy': 3,
|
||||
'bios': 2,
|
||||
'raid': 1,
|
||||
}
|
||||
|
||||
|
@ -52,6 +52,18 @@ _DEFAULT_IFACE_HELP = _('Default {0} interface to be used for nodes that '
|
||||
'be found by enumerating the '
|
||||
'"ironic.hardware.interfaces.{0}" entrypoint.')
|
||||
|
||||
# TODO(zshi) Remove this in BIOS API patch.
|
||||
_ENABLED_IFACE_HELP_FOR_BIOS = (_ENABLED_IFACE_HELP +
|
||||
_(' This option is part of BIOS feature '
|
||||
'work, which is not currently exposed to '
|
||||
'users.'))
|
||||
|
||||
# TODO(zshi) Remove this in BIOS API patch.
|
||||
_DEFAULT_IFACE_HELP_FOR_BIOS = (_DEFAULT_IFACE_HELP +
|
||||
_(' This option is part of BIOS feature '
|
||||
'work, which is not currently exposed to '
|
||||
'users.'))
|
||||
|
||||
api_opts = [
|
||||
cfg.StrOpt(
|
||||
'auth_strategy',
|
||||
@ -103,6 +115,11 @@ driver_opts = [
|
||||
'A complete list of hardware types present on your '
|
||||
'system may be found by enumerating the '
|
||||
'"ironic.hardware.types" entrypoint.')),
|
||||
cfg.ListOpt('enabled_bios_interfaces',
|
||||
default=['no-bios'],
|
||||
help=_ENABLED_IFACE_HELP_FOR_BIOS.format('bios')),
|
||||
cfg.StrOpt('default_bios_interface',
|
||||
help=_DEFAULT_IFACE_HELP_FOR_BIOS.format('bios')),
|
||||
cfg.ListOpt('enabled_boot_interfaces',
|
||||
default=['pxe'],
|
||||
help=_ENABLED_IFACE_HELP.format('boot')),
|
||||
|
@ -176,14 +176,21 @@ class BareDriver(BaseDriver):
|
||||
"""
|
||||
core_interfaces = BaseDriver.core_interfaces + ('network',)
|
||||
|
||||
bios = None
|
||||
"""`Standard` attribute for BIOS related features.
|
||||
|
||||
A reference to an instance of :class:BIOSInterface.
|
||||
May be None, if unsupported by a driver.
|
||||
"""
|
||||
|
||||
storage = None
|
||||
"""`Standard` attribute for (remote) storage interface.
|
||||
|
||||
A reference to an instance of :class:StorageInterface.
|
||||
"""
|
||||
|
||||
standard_interfaces = (BaseDriver.standard_interfaces + ('rescue',
|
||||
'storage',))
|
||||
standard_interfaces = (BaseDriver.standard_interfaces + ('bios',
|
||||
'rescue', 'storage',))
|
||||
|
||||
|
||||
ALL_INTERFACES = set(BareDriver().all_interfaces)
|
||||
@ -917,6 +924,87 @@ class InspectInterface(BaseInterface):
|
||||
"""
|
||||
|
||||
|
||||
class BIOSInterface(BaseInterface):
|
||||
interface_type = 'bios'
|
||||
|
||||
def __new__(cls, *args, **kwargs):
|
||||
# Wrap the apply_configuration and factory_reset into a decorator
|
||||
# which call cache_bios_settings() to update the node's BIOS setting
|
||||
# table after apply_configuration and factory_reset have finished.
|
||||
|
||||
super_new = super(BIOSInterface, cls).__new__
|
||||
instance = super_new(cls, *args, **kwargs)
|
||||
|
||||
def wrapper(func):
|
||||
@six.wraps(func)
|
||||
def wrapped(self, task, *args, **kwargs):
|
||||
func(task, *args, **kwargs)
|
||||
instance.cache_bios_settings(task)
|
||||
return wrapped
|
||||
|
||||
for n, method in inspect.getmembers(instance, inspect.ismethod):
|
||||
if n == "apply_configuration":
|
||||
instance.apply_configuration = wrapper(method)
|
||||
elif n == "factory_reset":
|
||||
instance.factory_reset = wrapper(method)
|
||||
return instance
|
||||
|
||||
@abc.abstractmethod
|
||||
def apply_configuration(self, task, settings):
|
||||
"""Validate & apply BIOS settings on the given node.
|
||||
|
||||
This method takes the BIOS settings from the settings param and
|
||||
applies BIOS settings on the given node. It may also validate the
|
||||
given bios settings before applying any settings and manage
|
||||
failures when setting an invalid BIOS config. In the case of
|
||||
needing password to update the BIOS config, it will be taken from
|
||||
the driver_info properties. After the BIOS configuration is done,
|
||||
cache_bios_settings will be called to update the node's BIOS setting
|
||||
table with the BIOS configuration applied on the node.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:param settings: Dictonary containing the BIOS configuration.
|
||||
:raises: UnsupportedDriverExtension, if the node's driver doesn't
|
||||
support BIOS configuration.
|
||||
:raises: InvalidParameterValue, if validation of settings fails.
|
||||
:raises: MissingParameterValue, if some required parameters are
|
||||
missing.
|
||||
:returns: states.CLEANWAIT if BIOS configuration is in progress
|
||||
asynchronously or None if it is complete.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def factory_reset(self, task):
|
||||
"""Reset BIOS configuration to factory default on the given node.
|
||||
|
||||
This method resets BIOS configuration to factory default on the
|
||||
given node. After the BIOS reset action is done, cache_bios_settings
|
||||
will be called to update the node's BIOS settings table with default
|
||||
bios settings.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:raises: UnsupportedDriverExtension, if the node's driver doesn't
|
||||
support BIOS reset.
|
||||
:returns: states.CLEANWAIT if BIOS configuration is in progress
|
||||
asynchronously or None if it is complete.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def cache_bios_settings(self, task):
|
||||
"""Store or update BIOS properties on the given node.
|
||||
|
||||
This method stores BIOS properties to the bios_settings table during
|
||||
'cleaning' operation and updates bios_settings table when
|
||||
apply_configuration() and factory_reset() are called to set new BIOS
|
||||
configurations. It will also update the timestamp of each bios setting.
|
||||
|
||||
:param task: a TaskManager instance.
|
||||
:raises: UnsupportedDriverExtension, if the node's driver doesn't
|
||||
support getting BIOS properties from bare metal.
|
||||
:returns: None.
|
||||
"""
|
||||
|
||||
|
||||
class RAIDInterface(BaseInterface):
|
||||
interface_type = 'raid'
|
||||
|
||||
|
@ -73,7 +73,7 @@ class FakeDriver(base.BaseDriver):
|
||||
def to_hardware_type(cls):
|
||||
return 'fake-hardware', {
|
||||
iface: 'fake'
|
||||
for iface in ['boot', 'console', 'deploy', 'inspect',
|
||||
for iface in ['bios', 'boot', 'console', 'deploy', 'inspect',
|
||||
'management', 'power', 'raid', 'rescue', 'vendor']
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,10 @@ class FakeHardware(hardware_type.AbstractHardwareType):
|
||||
All fake implementations are still expected to be enabled in the
|
||||
configuration.
|
||||
"""
|
||||
@property
|
||||
def supported_bios_interfaces(self):
|
||||
"""List of classes of supported bios interfaces."""
|
||||
return [fake.FakeBIOS, noop.NoBIOS]
|
||||
|
||||
@property
|
||||
def supported_boot_interfaces(self):
|
||||
|
@ -62,6 +62,10 @@ class AbstractHardwareType(object):
|
||||
"""List of supported power interfaces."""
|
||||
|
||||
# Optional hardware interfaces
|
||||
@property
|
||||
def supported_bios_interfaces(self):
|
||||
"""List of supported bios interfaces."""
|
||||
return [noop.NoBIOS]
|
||||
|
||||
@property
|
||||
def supported_console_interfaces(self):
|
||||
|
@ -29,6 +29,7 @@ from ironic.common import exception
|
||||
from ironic.common.i18n import _
|
||||
from ironic.common import states
|
||||
from ironic.drivers import base
|
||||
from ironic import objects
|
||||
|
||||
|
||||
class FakePower(base.PowerInterface):
|
||||
@ -236,6 +237,33 @@ class FakeRAID(base.RAIDInterface):
|
||||
pass
|
||||
|
||||
|
||||
class FakeBIOS(base.BIOSInterface):
|
||||
"""Example implementation of simple BIOSInterface."""
|
||||
|
||||
def get_properties(self):
|
||||
return {}
|
||||
|
||||
def validate(self, task):
|
||||
pass
|
||||
|
||||
def apply_configuration(self, task, settings):
|
||||
node_id = task.node.id
|
||||
try:
|
||||
objects.BIOSSettingList.create(task.context, node_id, settings)
|
||||
except exception.BIOSSettingAlreadyExists:
|
||||
objects.BIOSSettingList.save(task.context, node_id, settings)
|
||||
|
||||
def factory_reset(self, task):
|
||||
node_id = task.node.id
|
||||
setting_objs = objects.BIOSSettingList.get_by_node_id(
|
||||
task.context, node_id)
|
||||
for setting in setting_objs:
|
||||
objects.BIOSSetting.delete(task.context, node_id, setting.name)
|
||||
|
||||
def cache_bios_settings(self, task):
|
||||
pass
|
||||
|
||||
|
||||
class FakeStorage(base.StorageInterface):
|
||||
"""Example implementation of simple storage Interface."""
|
||||
|
||||
|
@ -68,3 +68,16 @@ class NoRAID(FailMixin, base.RAIDInterface):
|
||||
|
||||
def validate_raid_config(self, task, raid_config):
|
||||
_fail(self, task)
|
||||
|
||||
|
||||
class NoBIOS(FailMixin, base.BIOSInterface):
|
||||
"""BIOS interface implementation that raises errors on all requests."""
|
||||
|
||||
def apply_configuration(self, task, settings):
|
||||
_fail(self, task, settings)
|
||||
|
||||
def factory_reset(self, task):
|
||||
_fail(self, task)
|
||||
|
||||
def cache_bios_settings(self, task):
|
||||
pass
|
||||
|
@ -59,7 +59,8 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
# Version 1.21: Add storage_interface field
|
||||
# Version 1.22: Add rescue_interface field
|
||||
# Version 1.23: Add traits field
|
||||
VERSION = '1.23'
|
||||
# Version 1.24: Add bios_interface field
|
||||
VERSION = '1.24'
|
||||
|
||||
dbapi = db_api.get_instance()
|
||||
|
||||
@ -119,6 +120,7 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
|
||||
'extra': object_fields.FlexibleDictField(nullable=True),
|
||||
|
||||
'bios_interface': object_fields.StringField(nullable=True),
|
||||
'boot_interface': object_fields.StringField(nullable=True),
|
||||
'console_interface': object_fields.StringField(nullable=True),
|
||||
'deploy_interface': object_fields.StringField(nullable=True),
|
||||
@ -130,7 +132,6 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
'rescue_interface': object_fields.StringField(nullable=True),
|
||||
'storage_interface': object_fields.StringField(nullable=True),
|
||||
'vendor_interface': object_fields.StringField(nullable=True),
|
||||
|
||||
'traits': object_fields.ObjectField('TraitList', nullable=True),
|
||||
}
|
||||
|
||||
@ -476,6 +477,9 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
Version 1.23: traits field was added. Its default value is
|
||||
None. For versions prior to this, it should be set to None (or
|
||||
removed).
|
||||
Version 1.24: bios_interface field was added. Its default value is
|
||||
None. For versions prior to this, it should be set to None (or
|
||||
removed).
|
||||
|
||||
:param target_version: the desired version of the object
|
||||
:param remove_unavailable_fields: True to remove fields that are
|
||||
@ -511,6 +515,21 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
|
||||
elif self.traits is not None:
|
||||
self.traits = None
|
||||
|
||||
bios_iface_is_set = self.obj_attr_is_set('bios_interface')
|
||||
if target_version >= (1, 24):
|
||||
# Target version supports bios_interface.
|
||||
if not bios_iface_is_set:
|
||||
# Set it to its default value if it is not set.
|
||||
self.bios_interface = None
|
||||
elif bios_iface_is_set:
|
||||
# Target version does not support bios_interface, and it is set.
|
||||
if remove_unavailable_fields:
|
||||
# (De)serialising: remove unavailable fields.
|
||||
delattr(self, 'bios_interface')
|
||||
elif self.bios_interface is not None:
|
||||
# DB: set unavailable field to the default of None.
|
||||
self.bios_interface = None
|
||||
|
||||
|
||||
@base.IronicObjectRegistry.register
|
||||
class NodePayload(notification.NotificationPayloadBase):
|
||||
@ -558,6 +577,11 @@ class NodePayload(notification.NotificationPayloadBase):
|
||||
'uuid': ('node', 'uuid')
|
||||
}
|
||||
|
||||
# TODO(zshi): At a later point in time, once bios_interface is able
|
||||
# to be leveraged, we need to add the bios_interface field to payload
|
||||
# and increment the object versions for all objects that inherit the
|
||||
# NodePayload object.
|
||||
|
||||
# Version 1.0: Initial version, based off of Node version 1.18.
|
||||
# Version 1.1: Type of network_interface changed to just nullable string
|
||||
# similar to version 1.20 of Node.
|
||||
|
@ -215,9 +215,11 @@ class TestListDrivers(base.BaseApiTest):
|
||||
|
||||
if use_dynamic:
|
||||
for iface in driver_base.ALL_INTERFACES:
|
||||
if latest_if or iface not in ['rescue', 'storage']:
|
||||
self.assertIn('default_%s_interface' % iface, data)
|
||||
self.assertIn('enabled_%s_interfaces' % iface, data)
|
||||
if iface != 'bios':
|
||||
if latest_if or iface not in ['rescue', 'storage']:
|
||||
self.assertIn('default_%s_interface' % iface, data)
|
||||
self.assertIn('enabled_%s_interfaces' % iface, data)
|
||||
|
||||
self.assertIsNotNone(data['default_deploy_interface'])
|
||||
self.assertIsNotNone(data['enabled_deploy_interfaces'])
|
||||
else:
|
||||
|
@ -108,7 +108,7 @@ class DriverLoadTestCase(db_base.DbTestCase):
|
||||
with task_manager.acquire(self.context, node.id) as task:
|
||||
for iface in drivers_base.ALL_INTERFACES:
|
||||
impl = getattr(task.driver, iface)
|
||||
if iface == 'rescue':
|
||||
if iface in ['bios', 'rescue']:
|
||||
self.assertIsNone(impl)
|
||||
else:
|
||||
self.assertIsNotNone(impl)
|
||||
@ -572,6 +572,11 @@ class DefaultInterfaceTestCase(db_base.DbTestCase):
|
||||
|
||||
|
||||
class TestFakeHardware(hardware_type.AbstractHardwareType):
|
||||
@property
|
||||
def supported_bios_interfaces(self):
|
||||
"""List of supported bios interfaces."""
|
||||
return [fake.FakeBIOS]
|
||||
|
||||
@property
|
||||
def supported_boot_interfaces(self):
|
||||
"""List of supported boot interfaces."""
|
||||
@ -796,6 +801,7 @@ class HardwareTypeLoadTestCase(db_base.DbTestCase):
|
||||
def _test_enabled_supported_interfaces(self, enable_storage):
|
||||
ht = fake_hardware.FakeHardware()
|
||||
expected = {
|
||||
'bios': set(['fake', 'no-bios']),
|
||||
'boot': set(['fake']),
|
||||
'console': set(['fake', 'no-console']),
|
||||
'deploy': set(['fake']),
|
||||
@ -850,6 +856,7 @@ class ClassicDriverMigrationTestCase(base.TestCase):
|
||||
delta = driver_factory.calculate_migration_delta(
|
||||
'drv', self.driver_cls, False)
|
||||
self.assertEqual({'driver': 'hw-type',
|
||||
'bios_interface': 'no-bios',
|
||||
'console_interface': 'new-console',
|
||||
'inspect_interface': 'new-inspect',
|
||||
'raid_interface': 'no-raid',
|
||||
@ -881,6 +888,7 @@ class ClassicDriverMigrationTestCase(base.TestCase):
|
||||
delta = driver_factory.calculate_migration_delta(
|
||||
'drv', self.driver_cls, True)
|
||||
self.assertEqual({'driver': 'hw-type',
|
||||
'bios_interface': 'no-bios',
|
||||
'console_interface': 'new-console',
|
||||
'inspect_interface': 'no-inspect',
|
||||
'raid_interface': 'no-raid',
|
||||
|
@ -177,6 +177,7 @@ class ServiceSetUpMixin(object):
|
||||
self.config(enabled_raid_interfaces=['fake', 'no-raid'])
|
||||
self.config(enabled_rescue_interfaces=['fake', 'no-rescue'])
|
||||
self.config(enabled_vendor_interfaces=['fake', 'no-vendor'])
|
||||
self.config(enabled_bios_interfaces=['fake', 'no-bios'])
|
||||
|
||||
self.service = manager.ConductorManager(self.hostname, 'test-topic')
|
||||
mock_the_extension_manager()
|
||||
|
@ -3405,6 +3405,7 @@ class MiscTestCase(mgr_utils.ServiceSetUpMixin, mgr_utils.CommonMixIn,
|
||||
'network': {'result': True},
|
||||
'storage': {'result': True},
|
||||
'rescue': {'reason': reason, 'result': None}}
|
||||
|
||||
self.assertEqual(expected, ret)
|
||||
mock_iwdi.assert_called_once_with(self.context, node.instance_info)
|
||||
|
||||
|
@ -730,6 +730,7 @@ class NodePowerActionTestCase(db_base.DbTestCase):
|
||||
raid_interface='no-raid',
|
||||
rescue_interface='no-rescue',
|
||||
vendor_interface='no-vendor',
|
||||
bios_interface='no-bios',
|
||||
power_state=states.POWER_ON)
|
||||
self.config(enabled_boot_interfaces=['fake'])
|
||||
self.config(enabled_deploy_interfaces=['fake'])
|
||||
|
@ -29,10 +29,18 @@ def hardware_interface_extension_manager(interface):
|
||||
|
||||
|
||||
class NoInterfacesTestCase(base.TestCase):
|
||||
iface_types = ['console', 'inspect', 'raid', 'rescue', 'vendor']
|
||||
iface_types = ['bios', 'console', 'inspect', 'raid', 'rescue', 'vendor']
|
||||
task = mock.Mock(node=mock.Mock(driver='pxe_foobar', spec=['driver']),
|
||||
spec=['node'])
|
||||
|
||||
def test_bios(self):
|
||||
self.assertRaises(exception.UnsupportedDriverExtension,
|
||||
getattr(noop.NoBIOS(), 'apply_configuration'),
|
||||
self, self.task, '')
|
||||
self.assertRaises(exception.UnsupportedDriverExtension,
|
||||
getattr(noop.NoBIOS(), 'factory_reset'),
|
||||
self, self.task)
|
||||
|
||||
def test_console(self):
|
||||
for method in ('start_console', 'stop_console', 'get_console'):
|
||||
self.assertRaises(exception.UnsupportedDriverExtension,
|
||||
|
@ -422,6 +422,43 @@ class TestDeployInterface(base.TestCase):
|
||||
self.assertTrue(mock_log.called)
|
||||
|
||||
|
||||
class MyBIOSInterface(driver_base.BIOSInterface):
|
||||
|
||||
def get_properties(self):
|
||||
pass
|
||||
|
||||
def validate(self, task):
|
||||
pass
|
||||
|
||||
def apply_configuration(self, task, settings):
|
||||
pass
|
||||
|
||||
def factory_reset(self, task):
|
||||
pass
|
||||
|
||||
def cache_bios_settings(self, task):
|
||||
pass
|
||||
|
||||
|
||||
class TestBIOSInterface(base.TestCase):
|
||||
|
||||
@mock.patch.object(MyBIOSInterface, 'cache_bios_settings', autospec=True)
|
||||
def test_apply_configuration_wrapper(self, cache_bios_settings_mock):
|
||||
bios = MyBIOSInterface()
|
||||
task_mock = mock.MagicMock()
|
||||
|
||||
bios.apply_configuration(bios, task_mock, "")
|
||||
cache_bios_settings_mock.assert_called_once_with(bios, task_mock)
|
||||
|
||||
@mock.patch.object(MyBIOSInterface, 'cache_bios_settings', autospec=True)
|
||||
def test_factory_reset_wrapper(self, cache_bios_settings_mock):
|
||||
bios = MyBIOSInterface()
|
||||
task_mock = mock.MagicMock()
|
||||
|
||||
bios.factory_reset(bios, task_mock)
|
||||
cache_bios_settings_mock.assert_called_once_with(bios, task_mock)
|
||||
|
||||
|
||||
class TestBootInterface(base.TestCase):
|
||||
|
||||
def test_validate_rescue_default_impl(self):
|
||||
@ -449,16 +486,20 @@ class TestBaseDriver(base.TestCase):
|
||||
# get modified by a child class
|
||||
self.assertEqual(('deploy', 'power'),
|
||||
driver_base.BaseDriver.core_interfaces)
|
||||
self.assertEqual(('boot', 'console', 'inspect', 'management', 'raid'),
|
||||
driver_base.BaseDriver.standard_interfaces)
|
||||
self.assertEqual(
|
||||
('boot', 'console', 'inspect', 'management', 'raid'),
|
||||
driver_base.BaseDriver.standard_interfaces
|
||||
)
|
||||
# Ensure that instantiating an instance of a derived class does not
|
||||
# change our variables.
|
||||
driver_base.BareDriver()
|
||||
|
||||
self.assertEqual(('deploy', 'power'),
|
||||
driver_base.BaseDriver.core_interfaces)
|
||||
self.assertEqual(('boot', 'console', 'inspect', 'management', 'raid'),
|
||||
driver_base.BaseDriver.standard_interfaces)
|
||||
self.assertEqual(
|
||||
('boot', 'console', 'inspect', 'management', 'raid'),
|
||||
driver_base.BaseDriver.standard_interfaces
|
||||
)
|
||||
|
||||
|
||||
class TestBareDriver(base.TestCase):
|
||||
@ -469,7 +510,7 @@ class TestBareDriver(base.TestCase):
|
||||
self.assertEqual(('deploy', 'power', 'network'),
|
||||
driver_base.BareDriver.core_interfaces)
|
||||
self.assertEqual(
|
||||
('boot', 'console', 'inspect', 'management', 'raid',
|
||||
('boot', 'console', 'inspect', 'management', 'raid', 'bios',
|
||||
'rescue', 'storage'),
|
||||
driver_base.BareDriver.standard_interfaces
|
||||
)
|
||||
|
@ -497,6 +497,69 @@ class TestConvertToVersion(db_base.DbTestCase):
|
||||
self.assertIsNone(node.traits)
|
||||
self.assertEqual({}, node.obj_get_changes())
|
||||
|
||||
def test_bios_supported_missing(self):
|
||||
# bios_interface not set, should be set to default.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
delattr(node, 'bios_interface')
|
||||
node.obj_reset_changes()
|
||||
|
||||
node._convert_to_version("1.24")
|
||||
|
||||
self.assertIsNone(node.bios_interface)
|
||||
self.assertEqual({'bios_interface': None},
|
||||
node.obj_get_changes())
|
||||
|
||||
def test_bios_supported_set(self):
|
||||
# bios_interface set, no change required.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
|
||||
node.bios_interface = 'fake'
|
||||
node.obj_reset_changes()
|
||||
node._convert_to_version("1.24")
|
||||
self.assertEqual('fake', node.bios_interface)
|
||||
self.assertEqual({}, node.obj_get_changes())
|
||||
|
||||
def test_bios_unsupported_missing(self):
|
||||
# bios_interface not set, no change required.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
|
||||
delattr(node, 'bios_interface')
|
||||
node.obj_reset_changes()
|
||||
node._convert_to_version("1.23")
|
||||
self.assertNotIn('bios_interface', node)
|
||||
self.assertEqual({}, node.obj_get_changes())
|
||||
|
||||
def test_bios_unsupported_set_remove(self):
|
||||
# bios_interface set, should be removed.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
|
||||
node.bios_interface = 'fake'
|
||||
node.obj_reset_changes()
|
||||
node._convert_to_version("1.23")
|
||||
self.assertNotIn('bios_interface', node)
|
||||
self.assertEqual({}, node.obj_get_changes())
|
||||
|
||||
def test_bios_unsupported_set_no_remove_non_default(self):
|
||||
# bios_interface set, should be set to default.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
|
||||
node.bios_interface = 'fake'
|
||||
node.obj_reset_changes()
|
||||
node._convert_to_version("1.23", False)
|
||||
self.assertIsNone(node.bios_interface)
|
||||
self.assertEqual({'bios_interface': None},
|
||||
node.obj_get_changes())
|
||||
|
||||
def test_bios_unsupported_set_no_remove_default(self):
|
||||
# bios_interface set, no change required.
|
||||
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
|
||||
|
||||
node.bios_interface = None
|
||||
node.obj_reset_changes()
|
||||
node._convert_to_version("1.23", False)
|
||||
self.assertIsNone(node.bios_interface)
|
||||
self.assertEqual({}, node.obj_get_changes())
|
||||
|
||||
|
||||
class TestNodePayloads(db_base.DbTestCase):
|
||||
|
||||
|
@ -663,7 +663,7 @@ class TestObject(_LocalTest, _TestObject):
|
||||
# version bump. It is an MD5 hash of the object fields and remotable methods.
|
||||
# The fingerprint values should only be changed if there is a version bump.
|
||||
expected_object_fingerprints = {
|
||||
'Node': '1.23-6bebf8dbcd2ce15407c946bd091f80b4',
|
||||
'Node': '1.24-7d3d504e5e0d2535b2390d558b27196a',
|
||||
'MyObj': '1.5-9459d30d6954bffc7a9afd347a807ca6',
|
||||
'Chassis': '1.3-d656e039fd8ae9f34efc232ab3980905',
|
||||
'Port': '1.8-898a47921f4a1f53fcdddd4eeb179e0b',
|
||||
|
@ -87,6 +87,10 @@ ironic.drivers =
|
||||
pxe_iscsi_cimc = ironic.drivers.pxe:PXEAndCIMCDriver
|
||||
pxe_agent_cimc = ironic.drivers.agent:AgentAndCIMCDriver
|
||||
|
||||
ironic.hardware.interfaces.bios =
|
||||
fake = ironic.drivers.modules.fake:FakeBIOS
|
||||
no-bios = ironic.drivers.modules.noop:NoBIOS
|
||||
|
||||
ironic.hardware.interfaces.boot =
|
||||
fake = ironic.drivers.modules.fake:FakeBoot
|
||||
ilo-pxe = ironic.drivers.modules.ilo.boot:IloPXEBoot
|
||||
|
Loading…
Reference in New Issue
Block a user