diff --git a/ironic_python_agent/hardware.py b/ironic_python_agent/hardware.py index dc3cd57ad..45414c6a1 100644 --- a/ironic_python_agent/hardware.py +++ b/ironic_python_agent/hardware.py @@ -260,15 +260,17 @@ class BlockDevice(encoding.SerializableComparable): class NetworkInterface(encoding.SerializableComparable): serializable_fields = ('name', 'mac_address', 'ipv4_address', - 'has_carrier', 'lldp', 'vendor', 'product', - 'client_id', 'biosdevname') + 'ipv6_address', 'has_carrier', 'lldp', + 'vendor', 'product', 'client_id', + 'biosdevname') - def __init__(self, name, mac_addr, ipv4_address=None, has_carrier=True, - lldp=None, vendor=None, product=None, client_id=None, - biosdevname=None): + def __init__(self, name, mac_addr, ipv4_address=None, ipv6_address=None, + has_carrier=True, lldp=None, vendor=None, product=None, + client_id=None, biosdevname=None): self.name = name self.mac_address = mac_addr self.ipv4_address = ipv4_address + self.ipv6_address = ipv6_address self.has_carrier = has_carrier self.lldp = lldp self.vendor = vendor @@ -582,6 +584,7 @@ class GenericHardwareManager(HardwareManager): return NetworkInterface( interface_name, mac_addr, ipv4_address=self.get_ipv4_addr(interface_name), + ipv6_address=self.get_ipv6_addr(interface_name), has_carrier=netutils.interface_has_carrier(interface_name), vendor=_get_device_info(interface_name, 'net', 'vendor'), product=_get_device_info(interface_name, 'net', 'device'), @@ -590,6 +593,14 @@ class GenericHardwareManager(HardwareManager): def get_ipv4_addr(self, interface_id): return netutils.get_ipv4_addr(interface_id) + def get_ipv6_addr(self, interface_id): + """Get the default IPv6 address assigned to the interface. + + With different networking environment, the address could be a + link-local address, ULA or something else. + """ + return netutils.get_ipv6_addr(interface_id) + def get_bios_given_nic_name(self, interface_name): """Collect the BIOS given NICs name. diff --git a/ironic_python_agent/netutils.py b/ironic_python_agent/netutils.py index 9af4e04ba..656e61ace 100644 --- a/ironic_python_agent/netutils.py +++ b/ironic_python_agent/netutils.py @@ -203,15 +203,24 @@ def _get_lldp_info(interfaces): return lldp_info -def get_ipv4_addr(interface_id): +def get_default_ip_addr(type, interface_id): + """Retrieve default IPv4 or IPv6 address.""" try: addrs = netifaces.ifaddresses(interface_id) - return addrs[netifaces.AF_INET][0]['addr'] + return addrs[type][0]['addr'] except (ValueError, IndexError, KeyError): - # No default IPv4 address found + # No default IP address found return None +def get_ipv4_addr(interface_id): + return get_default_ip_addr(netifaces.AF_INET, interface_id) + + +def get_ipv6_addr(interface_id): + return get_default_ip_addr(netifaces.AF_INET6, interface_id) + + def get_mac_addr(interface_id): try: addrs = netifaces.ifaddresses(interface_id) diff --git a/ironic_python_agent/tests/unit/test_hardware.py b/ironic_python_agent/tests/unit/test_hardware.py index af5e52a26..6bdae9987 100644 --- a/ironic_python_agent/tests/unit/test_hardware.py +++ b/ironic_python_agent/tests/unit/test_hardware.py @@ -513,7 +513,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): read_mock = mocked_open.return_value.read read_mock.side_effect = ['1'] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_execute.return_value = ('em0\n', '') mock_get_mac.mock_has_carrier = True @@ -523,6 +524,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) self.assertIsNone(interfaces[0].lldp) self.assertTrue(interfaces[0].has_carrier) self.assertEqual('em0', interfaces[0].biosdevname) @@ -552,7 +554,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): read_mock = mocked_open.return_value.read read_mock.side_effect = ['1'] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_execute.return_value = ('em0\n', '') mock_get_mac.return_value = '00:0c:29:8c:11:b1' @@ -562,6 +565,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) self.assertIsNone(interfaces[0].lldp) self.assertTrue(interfaces[0].has_carrier) self.assertEqual('em0', interfaces[0].biosdevname) @@ -645,7 +649,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): read_mock = mocked_open.return_value.read read_mock.side_effect = ['1'] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_lldp_info.return_value = {'eth0': [ (0, b''), @@ -661,6 +666,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) expected_lldp_info = [ (0, ''), (1, '04885a92ec5459'), @@ -693,7 +699,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): read_mock = mocked_open.return_value.read read_mock.side_effect = ['1'] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_lldp_info.side_effect = Exception('Boom!') mocked_execute.return_value = ('em0\n', '') @@ -704,6 +711,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) self.assertIsNone(interfaces[0].lldp) self.assertTrue(interfaces[0].has_carrier) self.assertEqual('em0', interfaces[0].biosdevname) @@ -734,7 +742,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): read_mock = mocked_open.return_value.read read_mock.side_effect = [OSError('boom')] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_execute.return_value = ('em0\n', '') mock_has_carrier.return_value = False @@ -744,6 +753,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual('00:0c:29:8c:11:b1', interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) self.assertFalse(interfaces[0].has_carrier) self.assertIsNone(interfaces[0].vendor) self.assertEqual('em0', interfaces[0].biosdevname) @@ -774,7 +784,8 @@ class TestGenericHardwareManager(base.IronicAgentTest): mac = '00:0c:29:8c:11:b1' read_mock.side_effect = ['0x15b3\n', '0x1014\n'] mocked_ifaddresses.return_value = { - netifaces.AF_INET: [{'addr': '192.168.1.2'}] + netifaces.AF_INET: [{'addr': '192.168.1.2'}], + netifaces.AF_INET6: [{'addr': 'fd00::101'}] } mocked_execute.return_value = ('em0\n', '') mock_has_carrier.return_value = True @@ -784,6 +795,7 @@ class TestGenericHardwareManager(base.IronicAgentTest): self.assertEqual('eth0', interfaces[0].name) self.assertEqual(mac, interfaces[0].mac_address) self.assertEqual('192.168.1.2', interfaces[0].ipv4_address) + self.assertEqual('fd00::101', interfaces[0].ipv6_address) self.assertTrue(interfaces[0].has_carrier) self.assertEqual('0x15b3', interfaces[0].vendor) self.assertEqual('0x1014', interfaces[0].product) diff --git a/releasenotes/notes/support-collecting-ipv6-address-dd819d543f851a63.yaml b/releasenotes/notes/support-collecting-ipv6-address-dd819d543f851a63.yaml new file mode 100644 index 000000000..2cfc3098b --- /dev/null +++ b/releasenotes/notes/support-collecting-ipv6-address-dd819d543f851a63.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - Adds support to collect the default IPv6 address for interfaces. With + different networking environment, the address could be a link-local + address, ULA or something else.