Create node get_interface method

A node's interface can be temporarily overriden in instance_info.
However, some parts of the Ironic code still used a node's interface
attribute directly. This change adds a node get_interface method
and updates various parts of the Ironic code to use it.

Change-Id: Ifdaa21383f71b501bccb6cf8fe80e5b34661b6ae
This commit is contained in:
Tzu-Mainn Chen 2021-11-08 20:30:52 +00:00
parent b1d08ae805
commit 16aad76a6f
11 changed files with 36 additions and 13 deletions

View File

@ -69,9 +69,7 @@ def _attach_interfaces_to_driver(bare_driver, node, hw_type):
the requested implementation is not compatible with it.
"""
for iface in _INTERFACE_LOADERS:
iface_name = '%s_interface' % iface
impl_name = node.instance_info.get(iface_name,
getattr(node, iface_name))
impl_name = node.get_interface(iface)
impl = get_interface(hw_type, iface, impl_name)
setattr(bare_driver, iface, impl)

View File

@ -712,7 +712,7 @@ def validate_port_info(node, port):
# Subnet Manager.
if port.extra.get('client-id'):
return True
if (node.network_interface == 'neutron'
if (node.get_interface('network') == 'neutron'
and not port.local_link_connection):
LOG.warning("The local_link_connection is required for "
"'neutron' network interface and is not present "

View File

@ -309,7 +309,7 @@ def configure_secure_boot_if_needed(task):
'management interface %(driver)s does not support it. '
'This warning will become an error in a future release.',
{'node': task.node.uuid,
'driver': task.node.management_interface})
'driver': task.node.get_interface('management')})
except Exception as exc:
with excutils.save_and_reraise_exception():
LOG.error('Failed to configure secure boot for node %(node)s: '
@ -335,7 +335,7 @@ def deconfigure_secure_boot_if_needed(task):
LOG.debug('Secure boot was requested for node %(node)s but its '
'management interface %(driver)s does not support it.',
{'node': task.node.uuid,
'driver': task.node.management_interface})
'driver': task.node.get_interface('management')})
except Exception as exc:
with excutils.save_and_reraise_exception():
LOG.error('Failed to deconfigure secure boot for node %(node)s: '

View File

@ -628,7 +628,7 @@ def get_boot_option(node):
# option it supports.
def is_ramdisk_deploy(node):
return node.deploy_interface == 'ramdisk'
return node.get_interface('deploy') == 'ramdisk'
def is_anaconda_deploy(node):
@ -638,7 +638,7 @@ def is_anaconda_deploy(node):
:returns: A boolean value of True when Anaconda deploy interface is in use
otherwise False
"""
if node.deploy_interface == 'anaconda':
if node.get_interface('deploy') == 'anaconda':
return True
return False

View File

@ -153,7 +153,7 @@ def _ironic_manages_boot(task, raise_exc=False):
'not support managed boot for in-band inspection or '
'the required options are not populated: %(exc)s',
{'node': task.node.uuid,
'iface': task.node.boot_interface,
'iface': task.node.get_interface('boot'),
'exc': e})
if raise_exc:
raise
@ -166,7 +166,7 @@ def _ironic_manages_boot(task, raise_exc=False):
'not support managed boot for in-band inspection or '
'the required options are not populated: %(exc)s',
{'node': task.node.uuid,
'iface': task.node.network_interface,
'iface': task.node.get_interface('network'),
'exc': e})
if raise_exc:
raise

View File

@ -60,7 +60,8 @@ class RamdiskDeploy(agent_base.AgentBaseMixin, agent_base.HeartbeatMixin,
'deployment request of node %(node)s with boot '
'interface %(drv)s. The configuration drive will be '
'ignored for this deployment.',
{'node': task.node, 'drv': task.node.boot_interface})
{'node': task.node,
'drv': task.node.get_interface('boot')})
manager_utils.node_power_action(task, states.POWER_OFF)
# Tenant neworks must enable connectivity to the boot
# location, as reboot() can otherwise be very problematic.

View File

@ -417,7 +417,7 @@ class RedfishVirtualMediaBoot(base.BootInterface):
_("The %(iface)s boot interface is not suitable for node "
"%(node)s with vendor %(vendor)s, use "
"idrac-redfish-virtual-media instead")
% {'iface': task.node.boot_interface,
% {'iface': task.node.get_interface('boot'),
'node': task.node.uuid, 'vendor': vendor})
def validate(self, task):

View File

@ -709,7 +709,7 @@ class RedfishRAID(base.RAIDInterface):
raise exception.InvalidParameterValue(
_("The %(iface)s raid interface is not suitable for node "
"%(node)s with vendor %(vendor)s, use idrac-redfish instead")
% {'iface': task.node.raid_interface,
% {'iface': task.node.get_interface('raid'),
'node': task.node.uuid, 'vendor': vendor})
def validate(self, task):

View File

@ -544,6 +544,12 @@ class Node(base.IronicObject, object_base.VersionedObjectDictCompat):
node = cls._from_db_object(context, cls(), db_node)
return node
def get_interface(self, iface):
iface_name = '%s_interface' % iface
impl_name = self.instance_info.get(iface_name,
getattr(self, iface_name))
return impl_name
def _convert_deploy_step_field(self, target_version,
remove_unavailable_fields=True):
# NOTE(rloo): Typically we set the value to None. However,

View File

@ -559,6 +559,17 @@ class TestNodeObject(db_base.DbTestCase, obj_utils.SchemasTestMixIn):
def test_payload_schemas(self):
self._check_payload_schemas(objects.node, objects.Node.fields)
def test_get_interface(self):
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
node.deploy_interface = 'direct'
self.assertEqual('direct', node.get_interface('deploy'))
def test_get_interface_overriden(self):
node = obj_utils.get_test_node(self.ctxt, **self.fake_node)
node.deploy_interface = 'direct'
node.instance_info = {'deploy_interface': 'ramdisk'}
self.assertEqual('ramdisk', node.get_interface('deploy'))
class TestConvertToVersion(db_base.DbTestCase):

View File

@ -0,0 +1,7 @@
---
fixes:
- |
Fixes issue with a node's instance_info interface override caused when
Ironic uses the interface attribute directly. Does so by adding a
`get_interface` method to a node, and updating the Ironic code to use it
where needed.