Bug fix on neutron's API to return the correct target ID

In the class FloatingIpManager, the function filters the
resulting list of ports with all available floating ips.
The function now returns the target ID of a port with a
floating IP associated to it. Added a new function to get
this to pass. In the next phase is to refactor the
floating ip api to allow a finer granularity. This will
be useful later for managing floating ips.

Change-Id: I02286dbbb60318b0157992622ffdeeae45a71bc1
Closes-Bug: 1265872
This commit is contained in:
George Peristerakis 2014-01-06 17:23:03 -05:00
parent cf252d2252
commit 86f8794490
7 changed files with 50 additions and 12 deletions

View File

@ -81,6 +81,11 @@ def floating_ip_target_get_by_instance(request, instance_id):
instance_id)
def floating_ip_target_list_by_instance(request, instance_id):
floating_ips = NetworkClient(request).floating_ips
return floating_ips.list_target_id_by_instance(instance_id)
def floating_ip_simple_associate_supported(request):
return NetworkClient(request).floating_ips.is_simple_associate_supported()

View File

@ -118,6 +118,13 @@ class FloatingIpManager(object):
"""
pass
@abc.abstractmethod
def list_target_id_by_instance(self, instance_id):
"""Returns a list of instance's target IDs of floating IP association
based on the backend implementation
"""
pass
@abc.abstractmethod
def is_simple_associate_supported(self):
"""Returns True if the default floating IP pool is enabled."""

View File

@ -389,16 +389,25 @@ class FloatingIpManager(network_base.FloatingIpManager):
targets.append(FloatingIpTarget(target))
return targets
def get_target_id_by_instance(self, instance_id):
# In Neutron one port can have multiple ip addresses, so this method
# picks up the first one and generate target id.
def _target_ports_by_instance(self, instance_id):
if not instance_id:
return None
search_opts = {'device_id': instance_id}
ports = port_list(self.request, **search_opts)
return port_list(self.request, **search_opts)
def get_target_id_by_instance(self, instance_id):
# In Neutron one port can have multiple ip addresses, so this method
# picks up the first one and generate target id.
ports = self._target_ports_by_instance(instance_id)
if not ports:
return None
return '%s_%s' % (ports[0].id, ports[0].fixed_ips[0]['ip_address'])
return '{0}_{1}'.format(ports[0].id,
ports[0].fixed_ips[0]['ip_address'])
def list_target_id_by_instance(self, instance_id):
ports = self._target_ports_by_instance(instance_id)
return ['{0}_{1}'.format(p.id, p.fixed_ips[0]['ip_address'])
for p in ports]
def is_simple_associate_supported(self):
# NOTE: There are two reason that simple association support

View File

@ -354,6 +354,9 @@ class FloatingIpManager(network_base.FloatingIpManager):
def get_target_id_by_instance(self, instance_id):
return instance_id
def list_target_id_by_instance(self, instance_id):
return [instance_id, ]
def is_simple_associate_supported(self):
return conf.HORIZON_CONFIG["simple_ip_management"]

View File

@ -522,17 +522,19 @@ class SimpleDisassociateIP(tables.Action):
try:
# target_id is port_id for Neutron and instance_id for Nova Network
# (Neutron API wrapper returns a 'portid_fixedip' string)
target_id = api.network.floating_ip_target_get_by_instance(
request, instance_id).split('_')[0]
targets = api.network.floating_ip_target_list_by_instance(
request, instance_id)
target_ids = [t.split('_')[0] for t in targets]
fips = [fip for fip in api.network.tenant_floating_ip_list(request)
if fip.port_id == target_id]
if fip.port_id in target_ids]
# Removing multiple floating IPs at once doesn't work, so this pops
# off the first one.
if fips:
fip = fips.pop()
api.network.floating_ip_disassociate(request,
fip.id, target_id)
fip.id, fip.port_id)
messages.success(request,
_("Successfully disassociated "
"floating IP: %s") % fip.ip)

View File

@ -2056,7 +2056,7 @@ class InstanceTests(test.TestCase):
self.assertRedirectsNoFollow(res, INDEX_URL)
@test.create_stubs({api.network: ('floating_ip_target_get_by_instance',
@test.create_stubs({api.network: ('floating_ip_target_list_by_instance',
'tenant_floating_ip_list',
'floating_ip_disassociate',),
api.glance: ('image_list_detailed',),
@ -2073,9 +2073,9 @@ class InstanceTests(test.TestCase):
api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list())
api.glance.image_list_detailed(IgnoreArg()) \
.AndReturn((self.images.list(), False))
api.network.floating_ip_target_get_by_instance(
api.network.floating_ip_target_list_by_instance(
IsA(http.HttpRequest),
server.id).AndReturn(server.id)
server.id).AndReturn([server.id, ])
api.network.tenant_floating_ip_list(
IsA(http.HttpRequest)).AndReturn([fip])
api.network.floating_ip_disassociate(

View File

@ -542,3 +542,15 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
ret = api.network.floating_ip_target_get_by_instance(self.request, '1')
self.assertEqual(ret, self._get_target_id(candidates[0]))
def test_target_floating_ip_port_by_instance(self):
ports = self.api_ports.list()
candidates = [p for p in ports if p['device_id'] == '1']
search_opts = {'device_id': '1'}
self.qclient.list_ports(**search_opts).AndReturn({'ports': candidates})
self.mox.ReplayAll()
ret = api.network.floating_ip_target_list_by_instance(self.request,
'1')
self.assertEqual(ret[0], self._get_target_id(candidates[0]))
self.assertEqual(len(ret), len(candidates))