From f9483e5d95653906d6740a9a8ec0b715237f586e Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 15 Apr 2019 14:34:00 +0200 Subject: [PATCH] Skip attaching FloatingIP if it is already attached There are some flows in the cloud layer (reuse, but not found), which try to attach a freshly allocated (and attached) FIP. There is at least one cloud in the crowd, which explicitely forbids FIP attachment when it is already attached, what results in SDK and Ansible failure with auto_ip=True The test test_add_ip_refresh_timeout is being removed, since normally we should never end up this way (with reuse=False we wait for the FIP to be assigned during creation and we leave _add_auto_ip on a short-cut) Change-Id: If9a217981237d6f851ee470717da01fddd1b5ff1 --- openstack/cloud/_floating_ip.py | 11 +++- .../unit/cloud/test_floating_ip_neutron.py | 58 ++----------------- 2 files changed, 15 insertions(+), 54 deletions(-) diff --git a/openstack/cloud/_floating_ip.py b/openstack/cloud/_floating_ip.py index 5235fdffe..98068ad9b 100644 --- a/openstack/cloud/_floating_ip.py +++ b/openstack/cloud/_floating_ip.py @@ -691,6 +691,15 @@ class FloatingIPCloudMixin(_normalize.Normalizer): # Short circuit if we're asking to attach an IP that's already # attached ext_ip = meta.get_server_ip(server, ext_tag='floating', public=True) + if not ext_ip and floating_ip['port_id']: + # When we came here from reuse_fip and created FIP it might be + # already attached, but the server info might be also + # old to check whether it belongs to us now, thus refresh + # the server data and try again. There are some clouds, which + # explicitely forbids FIP assign call if it is already assigned. + server = self.get_server_by_id(server['id']) + ext_ip = meta.get_server_ip(server, ext_tag='floating', + public=True) if ext_ip == floating_ip['floating_ip_address']: return server @@ -719,7 +728,7 @@ class FloatingIPCloudMixin(_normalize.Normalizer): timeout, "Timeout waiting for the floating IP to be attached.", wait=self._SERVER_AGE): - server = self.get_server(server_id) + server = self.get_server_by_id(server_id) ext_ip = meta.get_server_ip( server, ext_tag='floating', public=True) if ext_ip == floating_ip['floating_ip_address']: diff --git a/openstack/tests/unit/cloud/test_floating_ip_neutron.py b/openstack/tests/unit/cloud/test_floating_ip_neutron.py index 94c06bdc0..d2f72f097 100644 --- a/openstack/tests/unit/cloud/test_floating_ip_neutron.py +++ b/openstack/tests/unit/cloud/test_floating_ip_neutron.py @@ -768,7 +768,8 @@ class TestFloatingIP(base.TestCase): self.assert_calls() def test_attach_ip_to_server(self): - fip = self.mock_floating_ip_list_rep['floatingips'][0] + fip = self.mock_floating_ip_list_rep['floatingips'][0].copy() + fip.update({'status': 'DOWN', 'port_id': None, 'router_id': None}) device_id = self.fake_server['id'] self.register_uris([ @@ -782,7 +783,8 @@ class TestFloatingIP(base.TestCase): 'network', 'public', append=['v2.0', 'floatingips/{0}.json'.format( fip['id'])]), - json={'floatingip': fip}, + json={'floatingip': + self.mock_floating_ip_list_rep['floatingips'][0]}, validate=dict( json={'floatingip': { 'port_id': self.mock_search_ports_rep[0]['id'], @@ -792,57 +794,7 @@ class TestFloatingIP(base.TestCase): self.cloud._attach_ip_to_server( server=self.fake_server, - floating_ip=self.floating_ip) - self.assert_calls() - - def test_add_ip_refresh_timeout(self): - device_id = self.fake_server['id'] - - self.register_uris([ - dict(method='GET', - uri=self.get_mock_url( - 'network', 'public', - append=['v2.0', 'networks.json']), - json={'networks': [self.mock_get_network_rep]}), - dict(method='GET', - uri='https://network.example.com/v2.0/subnets.json', - json={'subnets': []}), - dict(method='GET', - uri=self.get_mock_url( - 'network', 'public', append=['v2.0', 'ports.json'], - qs_elements=["device_id={0}".format(device_id)]), - json={'ports': self.mock_search_ports_rep}), - dict(method='POST', - uri='https://network.example.com/v2.0/floatingips.json', - json={'floatingip': self.floating_ip}, - validate=dict( - json={'floatingip': { - 'floating_network_id': 'my-network-id', - 'fixed_ip_address': self.mock_search_ports_rep[0][ - 'fixed_ips'][0]['ip_address'], - 'port_id': self.mock_search_ports_rep[0]['id']}})), - dict(method='GET', - uri=self.get_mock_url( - 'network', 'public', append=['v2.0', 'floatingips.json']), - json={'floatingips': [self.floating_ip]}), - dict(method='DELETE', - uri=self.get_mock_url( - 'network', 'public', - append=['v2.0', 'floatingips/{0}.json'.format( - self.floating_ip['id'])]), - json={}), - dict(method='GET', - uri=self.get_mock_url( - 'network', 'public', append=['v2.0', 'floatingips.json']), - json={'floatingips': []}), - ]) - - self.assertRaises( - exc.OpenStackCloudTimeout, - self.cloud._add_auto_ip, - server=self.fake_server, - wait=True, timeout=0.01, - reuse=False) + floating_ip=self.cloud._normalize_floating_ip(fip)) self.assert_calls() def test_detach_ip_from_server(self):