From a1c44d29e67339a05abde733d24315326c23e685 Mon Sep 17 00:00:00 2001 From: zhengyong Date: Sun, 21 Jan 2018 23:49:40 +0800 Subject: [PATCH] Support IPv6 address when validating interfaces When processing introspection data from IPA, ironic inspector only accept IPv4 address of an interface. In a IPv6 environment, the port will not be collected if processing.add_ports is not set to 'all'. Story: #1744073 Task: #11374 Co-Authored-By: Kaifeng Wang Change-Id: I0e1839df4d0e3b89f182ab98549486199d64c4ad --- ironic_inspector/plugins/standard.py | 13 ++++-- .../test/unit/test_plugins_standard.py | 44 +++++++++++++++++++ ...alidate-ipv6-address-fda29c929754352e.yaml | 9 ++++ 3 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/validate-ipv6-address-fda29c929754352e.yaml diff --git a/ironic_inspector/plugins/standard.py b/ironic_inspector/plugins/standard.py index 123d0622c..cfaeb37e5 100644 --- a/ironic_inspector/plugins/standard.py +++ b/ironic_inspector/plugins/standard.py @@ -13,7 +13,6 @@ """Standard set of plugins.""" - from ironic_lib import utils as il_utils import netaddr from oslo_config import cfg @@ -27,7 +26,6 @@ from ironic_inspector import utils CONF = cfg.CONF - LOG = utils.getProcessingLogger('ironic_inspector.plugins.standard') @@ -162,7 +160,13 @@ class ValidateInterfacesHook(base.ProcessingHook): for iface in inventory['interfaces']: name = iface.get('name') mac = iface.get('mac_address') - ip = iface.get('ipv4_address') + ipv4_address = iface.get('ipv4_address') + ipv6_address = iface.get('ipv6_address') + # NOTE(kaifeng) ipv6 address may in the form of fd00::1%enp2s0, + # which is not supported by netaddr, remove the suffix if exists. + if ipv6_address and '%' in ipv6_address: + ipv6_address = ipv6_address.split('%')[0] + ip = ipv4_address or ipv6_address client_id = iface.get('client_id') if not name: @@ -221,7 +225,8 @@ class ValidateInterfacesHook(base.ProcessingHook): LOG.debug('Skipping interface %s as it was not PXE booting', name, data=data) continue - elif CONF.processing.add_ports != 'all' and not ip: + elif CONF.processing.add_ports != 'all' and ( + not ip or netaddr.IPAddress(ip).is_link_local()): LOG.debug('Skipping interface %s as it did not have ' 'an IP address assigned during the ramdisk run', name, data=data) diff --git a/ironic_inspector/test/unit/test_plugins_standard.py b/ironic_inspector/test/unit/test_plugins_standard.py index b1d4a7836..5a355aad2 100644 --- a/ironic_inspector/test/unit/test_plugins_standard.py +++ b/ironic_inspector/test/unit/test_plugins_standard.py @@ -188,6 +188,50 @@ class TestValidateInterfacesHookBeforeProcessing(test_base.NodeTest): self.assertRaisesRegex(utils.Error, 'No suitable interfaces found', self.hook.before_processing, self.data) + def test_skipped_interfaces_with_local_address(self): + CONF.set_override('add_ports', 'active', 'processing') + self.inventory['interfaces'] = [ + # local interface (by IPv4 address) + {'name': 'em1', 'mac_address': '22:22:22:22:22:22', + 'ipv4_address': '127.0.0.1'}, + # local interface (by IPv6 address) + {'name': 'em2', 'mac_address': '33:33:33:33:33:33', + 'ipv6_address': '::1'}, + # interface only with local-link address + {'name': 'em3', 'mac_address': '44:44:44:44:44:44', + 'ipv6_address': 'fe80::4644:44ff:fe44:4444'}, + # interface only with local-link address with suffix + {'name': 'em4', 'mac_address': '55:55:55:55:55:55', + 'ipv6_address': 'fe80::5755:55ff:fe55:5555%em4'}, + ] + self.assertRaisesRegex(utils.Error, 'No suitable interfaces found', + self.hook.before_processing, self.data) + + def test_interfaces_with_ipv6_addresses_only(self): + CONF.set_override('add_ports', 'all', 'processing') + self.inventory['interfaces'] = [ + # loopback interface (by IPv6 address) + {'name': 'em2', 'mac_address': '33:33:33:33:33:33', + 'ipv6_address': '::1'}, + # interface with local-link address + {'name': 'em3', 'mac_address': '44:44:44:44:44:44', + 'ipv6_address': 'fe80::4644:44ff:fe44:4444'}, + # interface with local-link address with suffix + {'name': 'em4', 'mac_address': '55:55:55:55:55:55', + 'ipv6_address': 'fe80::5755:55ff:fe55:5555%em4'}, + # interface with ULA address + {'name': 'em5', 'mac_address': '66:66:66:66:66:66', + 'ipv6_address': 'fd00::1111:2222:6666'}, + ] + self.hook.before_processing(self.data) + interfaces = self.data['interfaces'] + self.assertEqual(interfaces['em3']['mac'], '44:44:44:44:44:44') + self.assertEqual(interfaces['em3']['ip'], 'fe80::4644:44ff:fe44:4444') + self.assertEqual(interfaces['em4']['mac'], '55:55:55:55:55:55') + self.assertEqual(interfaces['em4']['ip'], 'fe80::5755:55ff:fe55:5555') + self.assertEqual(interfaces['em5']['mac'], '66:66:66:66:66:66') + self.assertEqual(interfaces['em5']['ip'], 'fd00::1111:2222:6666') + @mock.patch.object(node_cache.NodeInfo, 'delete_port', autospec=True) @mock.patch.object(node_cache.NodeInfo, 'create_ports', autospec=True) diff --git a/releasenotes/notes/validate-ipv6-address-fda29c929754352e.yaml b/releasenotes/notes/validate-ipv6-address-fda29c929754352e.yaml new file mode 100644 index 000000000..2d82e8d69 --- /dev/null +++ b/releasenotes/notes/validate-ipv6-address-fda29c929754352e.yaml @@ -0,0 +1,9 @@ +--- +fixes: + - | + Fixes the issue that ports were not collected when there were only IPv6 + addresses (no IPv4), and the configuration option + ``[processing]add_ports`` was not set to ``all``. Inspector will report + "No suitable interfaces found" if no interface is collected. For more + information see + `Story 1744073 `_