Browse Source

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 <kaifeng.w@gmail.com>
Change-Id: I0e1839df4d0e3b89f182ab98549486199d64c4ad
zhengyong 1 year ago
parent
commit
a1c44d29e6

+ 9
- 4
ironic_inspector/plugins/standard.py View File

@@ -13,7 +13,6 @@
13 13
 
14 14
 """Standard set of plugins."""
15 15
 
16
-
17 16
 from ironic_lib import utils as il_utils
18 17
 import netaddr
19 18
 from oslo_config import cfg
@@ -27,7 +26,6 @@ from ironic_inspector import utils
27 26
 
28 27
 CONF = cfg.CONF
29 28
 
30
-
31 29
 LOG = utils.getProcessingLogger('ironic_inspector.plugins.standard')
32 30
 
33 31
 
@@ -162,7 +160,13 @@ class ValidateInterfacesHook(base.ProcessingHook):
162 160
         for iface in inventory['interfaces']:
163 161
             name = iface.get('name')
164 162
             mac = iface.get('mac_address')
165
-            ip = iface.get('ipv4_address')
163
+            ipv4_address = iface.get('ipv4_address')
164
+            ipv6_address = iface.get('ipv6_address')
165
+            # NOTE(kaifeng) ipv6 address may in the form of fd00::1%enp2s0,
166
+            # which is not supported by netaddr, remove the suffix if exists.
167
+            if ipv6_address and '%' in ipv6_address:
168
+                ipv6_address = ipv6_address.split('%')[0]
169
+            ip = ipv4_address or ipv6_address
166 170
             client_id = iface.get('client_id')
167 171
 
168 172
             if not name:
@@ -221,7 +225,8 @@ class ValidateInterfacesHook(base.ProcessingHook):
221 225
                 LOG.debug('Skipping interface %s as it was not PXE booting',
222 226
                           name, data=data)
223 227
                 continue
224
-            elif CONF.processing.add_ports != 'all' and not ip:
228
+            elif CONF.processing.add_ports != 'all' and (
229
+                        not ip or netaddr.IPAddress(ip).is_link_local()):
225 230
                 LOG.debug('Skipping interface %s as it did not have '
226 231
                           'an IP address assigned during the ramdisk run',
227 232
                           name, data=data)

+ 44
- 0
ironic_inspector/test/unit/test_plugins_standard.py View File

@@ -188,6 +188,50 @@ class TestValidateInterfacesHookBeforeProcessing(test_base.NodeTest):
188 188
         self.assertRaisesRegex(utils.Error, 'No suitable interfaces found',
189 189
                                self.hook.before_processing, self.data)
190 190
 
191
+    def test_skipped_interfaces_with_local_address(self):
192
+        CONF.set_override('add_ports', 'active', 'processing')
193
+        self.inventory['interfaces'] = [
194
+            # local interface (by IPv4 address)
195
+            {'name': 'em1', 'mac_address': '22:22:22:22:22:22',
196
+             'ipv4_address': '127.0.0.1'},
197
+            # local interface (by IPv6 address)
198
+            {'name': 'em2', 'mac_address': '33:33:33:33:33:33',
199
+             'ipv6_address': '::1'},
200
+            # interface only with local-link address
201
+            {'name': 'em3', 'mac_address': '44:44:44:44:44:44',
202
+             'ipv6_address': 'fe80::4644:44ff:fe44:4444'},
203
+            # interface only with local-link address with suffix
204
+            {'name': 'em4', 'mac_address': '55:55:55:55:55:55',
205
+             'ipv6_address': 'fe80::5755:55ff:fe55:5555%em4'},
206
+        ]
207
+        self.assertRaisesRegex(utils.Error, 'No suitable interfaces found',
208
+                               self.hook.before_processing, self.data)
209
+
210
+    def test_interfaces_with_ipv6_addresses_only(self):
211
+        CONF.set_override('add_ports', 'all', 'processing')
212
+        self.inventory['interfaces'] = [
213
+            # loopback interface (by IPv6 address)
214
+            {'name': 'em2', 'mac_address': '33:33:33:33:33:33',
215
+             'ipv6_address': '::1'},
216
+            # interface with local-link address
217
+            {'name': 'em3', 'mac_address': '44:44:44:44:44:44',
218
+             'ipv6_address': 'fe80::4644:44ff:fe44:4444'},
219
+            # interface with local-link address with suffix
220
+            {'name': 'em4', 'mac_address': '55:55:55:55:55:55',
221
+             'ipv6_address': 'fe80::5755:55ff:fe55:5555%em4'},
222
+            # interface with ULA address
223
+            {'name': 'em5', 'mac_address': '66:66:66:66:66:66',
224
+             'ipv6_address': 'fd00::1111:2222:6666'},
225
+        ]
226
+        self.hook.before_processing(self.data)
227
+        interfaces = self.data['interfaces']
228
+        self.assertEqual(interfaces['em3']['mac'], '44:44:44:44:44:44')
229
+        self.assertEqual(interfaces['em3']['ip'], 'fe80::4644:44ff:fe44:4444')
230
+        self.assertEqual(interfaces['em4']['mac'], '55:55:55:55:55:55')
231
+        self.assertEqual(interfaces['em4']['ip'], 'fe80::5755:55ff:fe55:5555')
232
+        self.assertEqual(interfaces['em5']['mac'], '66:66:66:66:66:66')
233
+        self.assertEqual(interfaces['em5']['ip'], 'fd00::1111:2222:6666')
234
+
191 235
 
192 236
 @mock.patch.object(node_cache.NodeInfo, 'delete_port', autospec=True)
193 237
 @mock.patch.object(node_cache.NodeInfo, 'create_ports', autospec=True)

+ 9
- 0
releasenotes/notes/validate-ipv6-address-fda29c929754352e.yaml View File

@@ -0,0 +1,9 @@
1
+---
2
+fixes:
3
+  - |
4
+    Fixes the issue that ports were not collected when there were only IPv6
5
+    addresses (no IPv4), and the configuration option
6
+    ``[processing]add_ports`` was not set to ``all``. Inspector will report
7
+    "No suitable interfaces found" if no interface is collected. For more
8
+    information see
9
+    `Story 1744073 <https://storyboard.openstack.org/#!/story/1744073>`_

Loading…
Cancel
Save