diff --git a/releasenotes/notes/use-interface-ip-c5cb3e7c91150096.yaml b/releasenotes/notes/use-interface-ip-c5cb3e7c91150096.yaml new file mode 100644 index 000000000..14a4fd4a1 --- /dev/null +++ b/releasenotes/notes/use-interface-ip-c5cb3e7c91150096.yaml @@ -0,0 +1,13 @@ +--- +fixes: + - shade now correctly does not try to attach a floating ip with auto_ip + if the cloud has given a public IPv6 address and the calling context + supports IPv6 routing. shade has always used this logic to determine + the server 'interface_ip', but the auto floating ip was incorrectly only + looking at the 'public_v4' value to determine whether the server needed + additional networking. +upgrade: + - If your cloud presents a default split IPv4/IPv6 stack with a public + v6 and a private v4 address and you have the expectation that auto_ip + should procure a v4 floating ip, you need to set 'force_ipv4' to True in + your clouds.yaml entry for the cloud. diff --git a/shade/openstackcloud.py b/shade/openstackcloud.py index a26498550..cf115e893 100644 --- a/shade/openstackcloud.py +++ b/shade/openstackcloud.py @@ -4028,7 +4028,7 @@ class OpenStackCloud(object): """ server = self._add_auto_ip( server, wait=wait, timeout=timeout, reuse=reuse) - return self.get_server_public_ip(server) + return server['interface_ip'] or None def _add_auto_ip(self, server, wait=False, timeout=60, reuse=True): skip_attach = False @@ -4091,7 +4091,7 @@ class OpenStackCloud(object): server, ips, wait=wait, timeout=timeout, fixed_address=fixed_address) elif auto_ip: - if not self.get_server_public_ip(server): + if not server['interface_ip']: server = self._add_auto_ip( server, wait=wait, timeout=timeout, reuse=reuse) return server diff --git a/shade/tests/unit/test_floating_ip_common.py b/shade/tests/unit/test_floating_ip_common.py index e6e60ca5b..df91bea17 100644 --- a/shade/tests/unit/test_floating_ip_common.py +++ b/shade/tests/unit/test_floating_ip_common.py @@ -80,6 +80,118 @@ class TestFloatingIP(base.TestCase): server_dict, pool, reuse=True, wait=False, timeout=60, fixed_address=None, nat_destination=None) + @patch.object(OpenStackCloud, 'has_service') + @patch.object(OpenStackCloud, 'get_floating_ip') + @patch.object(OpenStackCloud, '_add_auto_ip') + def test_add_ips_to_server_ipv6_only( + self, mock_add_auto_ip, + mock_get_floating_ip, + mock_has_service): + self.cloud._floating_ip_source = None + self.cloud.force_ipv4 = False + self.cloud._local_ipv6 = True + mock_has_service.return_value = False + server = FakeServer( + id='server-id', name='test-server', status="ACTIVE", + addresses={ + 'private': [{ + 'addr': "10.223.160.141", + 'version': 4 + }], + 'public': [{ + u'OS-EXT-IPS-MAC:mac_addr': u'fa:16:3e:ae:7d:42', + u'OS-EXT-IPS:type': u'fixed', + 'addr': "2001:4800:7819:103:be76:4eff:fe05:8525", + 'version': 6 + }] + } + ) + server_dict = meta.add_server_interfaces( + self.cloud, meta.obj_to_dict(server)) + + new_server = self.client.add_ips_to_server(server=server_dict) + mock_get_floating_ip.assert_not_called() + mock_add_auto_ip.assert_not_called() + self.assertEqual( + new_server['interface_ip'], + '2001:4800:7819:103:be76:4eff:fe05:8525') + self.assertEqual(new_server['private_v4'], '10.223.160.141') + self.assertEqual(new_server['public_v4'], '') + self.assertEqual( + new_server['public_v6'], '2001:4800:7819:103:be76:4eff:fe05:8525') + + @patch.object(OpenStackCloud, 'has_service') + @patch.object(OpenStackCloud, 'get_floating_ip') + @patch.object(OpenStackCloud, '_add_auto_ip') + def test_add_ips_to_server_rackspace( + self, mock_add_auto_ip, + mock_get_floating_ip, + mock_has_service): + self.cloud._floating_ip_source = None + self.cloud.force_ipv4 = False + self.cloud._local_ipv6 = True + mock_has_service.return_value = False + server = FakeServer( + id='server-id', name='test-server', status="ACTIVE", + addresses={ + 'private': [{ + 'addr': "10.223.160.141", + 'version': 4 + }], + 'public': [{ + 'addr': "104.130.246.91", + 'version': 4 + }, { + 'addr': "2001:4800:7819:103:be76:4eff:fe05:8525", + 'version': 6 + }] + } + ) + server_dict = meta.add_server_interfaces( + self.cloud, meta.obj_to_dict(server)) + + new_server = self.client.add_ips_to_server(server=server_dict) + mock_get_floating_ip.assert_not_called() + mock_add_auto_ip.assert_not_called() + self.assertEqual( + new_server['interface_ip'], + '2001:4800:7819:103:be76:4eff:fe05:8525') + + @patch.object(OpenStackCloud, 'has_service') + @patch.object(OpenStackCloud, 'get_floating_ip') + @patch.object(OpenStackCloud, '_add_auto_ip') + def test_add_ips_to_server_rackspace_local_ipv4( + self, mock_add_auto_ip, + mock_get_floating_ip, + mock_has_service): + self.cloud._floating_ip_source = None + self.cloud.force_ipv4 = False + self.cloud._local_ipv6 = False + mock_has_service.return_value = False + server = FakeServer( + id='server-id', name='test-server', status="ACTIVE", + addresses={ + 'private': [{ + 'addr': "10.223.160.141", + 'version': 4 + }], + 'public': [{ + 'addr': "104.130.246.91", + 'version': 4 + }, { + 'addr': "2001:4800:7819:103:be76:4eff:fe05:8525", + 'version': 6 + }] + } + ) + server_dict = meta.add_server_interfaces( + self.cloud, meta.obj_to_dict(server)) + + new_server = self.client.add_ips_to_server(server=server_dict) + mock_get_floating_ip.assert_not_called() + mock_add_auto_ip.assert_not_called() + self.assertEqual(new_server['interface_ip'], '104.130.246.91') + @patch.object(OpenStackCloud, 'nova_client') @patch.object(OpenStackCloud, 'add_ip_list') def test_add_ips_to_server_ip_list(