Show floating IP associated with Load Balancer VIP

Previously the code always tried to show an instance when
a floating IP is associated. This commit chnages the code
to consider a port device_owner associated with a floating IP
so that appropriate information is displayed in the table.

Change-Id: I5d99090b17bf94a80a0d7894ab2084f83e55d59d
Closes-Bug: #1359215
This commit is contained in:
Akihiro Motoki 2014-09-15 17:30:52 +09:00
parent eb1d684068
commit 39229c1844
4 changed files with 83 additions and 27 deletions

View File

@ -302,7 +302,8 @@ class SecurityGroupManager(network_base.SecurityGroupManager):
class FloatingIp(base.APIDictWrapper):
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id', 'pool']
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id',
'instance_type', 'pool']
def __init__(self, fip):
fip['ip'] = fip['floating_ip_address']
@ -320,6 +321,12 @@ class FloatingIpTarget(base.APIDictWrapper):
class FloatingIpManager(network_base.FloatingIpManager):
device_owner_map = {
'compute:': 'compute',
'neutron:LOADBALANCER': 'loadbalancer',
}
def __init__(self, request):
self.request = request
self.client = neutronclient(request)
@ -329,6 +336,23 @@ class FloatingIpManager(network_base.FloatingIpManager):
return [FloatingIpPool(pool) for pool
in self.client.list_networks(**search_opts).get('networks')]
def _get_instance_type_from_device_owner(self, device_owner):
for key, value in self.device_owner_map.items():
if device_owner.startswith(key):
return value
return device_owner
def _set_instance_info(self, fip, port=None):
if fip['port_id']:
if not port:
port = port_get(self.request, fip['port_id'])
fip['instance_id'] = port.device_id
fip['instance_type'] = self._get_instance_type_from_device_owner(
port.device_owner)
else:
fip['instance_id'] = None
fip['instance_type'] = None
def list(self, all_tenants=False, **search_opts):
if not all_tenants:
tenant_id = self.request.user.tenant_id
@ -344,27 +368,20 @@ class FloatingIpManager(network_base.FloatingIpManager):
# Get port list to add instance_id to floating IP list
# instance_id is stored in device_id attribute
ports = port_list(self.request, **port_search_opts)
device_id_dict = SortedDict([(p['id'], p['device_id']) for p in ports])
port_dict = SortedDict([(p['id'], p) for p in ports])
for fip in fips:
if fip['port_id']:
fip['instance_id'] = device_id_dict[fip['port_id']]
else:
fip['instance_id'] = None
self._set_instance_info(fip, port_dict.get(fip['port_id']))
return [FloatingIp(fip) for fip in fips]
def get(self, floating_ip_id):
fip = self.client.show_floatingip(floating_ip_id).get('floatingip')
if fip['port_id']:
fip['instance_id'] = port_get(self.request,
fip['port_id']).device_id
else:
fip['instance_id'] = None
self._set_instance_info(fip)
return FloatingIp(fip)
def allocate(self, pool):
body = {'floatingip': {'floating_network_id': pool}}
fip = self.client.create_floatingip(body).get('floatingip')
fip['instance_id'] = None
self._set_instance_info(fip)
return FloatingIp(fip)
def release(self, floating_ip_id):

View File

@ -342,10 +342,13 @@ class FlavorExtraSpec(object):
class FloatingIp(base.APIResourceWrapper):
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id', 'pool']
_attrs = ['id', 'ip', 'fixed_ip', 'port_id', 'instance_id',
'instance_type', 'pool']
def __init__(self, fip):
fip.__setattr__('port_id', fip.instance_id)
fip.__setattr__('instance_type',
'compute' if fip.instance_id else None)
super(FloatingIp, self).__init__(fip)

View File

@ -16,7 +16,7 @@
import logging
from django.conf import settings
from django.core import urlresolvers
from django.core.urlresolvers import reverse
from django import shortcuts
from django.utils.http import urlencode
from django.utils.translation import string_concat # noqa
@ -119,7 +119,7 @@ class AssociateIP(tables.LinkAction):
return not fip.port_id and POLICY_CHECK(policy, request)
def get_link_url(self, datum):
base_url = urlresolvers.reverse(self.url)
base_url = reverse(self.url)
params = urlencode({"ip_id": self.table.get_object_id(datum)})
return "?".join([base_url, params])
@ -153,14 +153,23 @@ class DisassociateIP(tables.Action):
return shortcuts.redirect('horizon:project:access_and_security:index')
def get_instance_info(instance):
return getattr(instance, "instance_name", None)
def get_instance_info(fip):
if fip.instance_type == 'compute':
return (_("%(instance_name)s %(fixed_ip)s")
% {'instance_name': getattr(fip, "instance_name", ''),
'fixed_ip': fip.fixed_ip})
elif fip.instance_type == 'loadbalancer':
return _("Load Balancer VIP %s") % fip.fixed_ip
elif fip.instance_type:
return fip.fixed_ip
else:
return None
def get_instance_link(datum):
view = "horizon:project:instances:detail"
if datum.instance_id:
return urlresolvers.reverse(view, args=(datum.instance_id,))
if datum.instance_type == 'compute':
return reverse("horizon:project:instances:detail",
args=(datum.instance_id,))
else:
return None
@ -169,9 +178,9 @@ class FloatingIPsTable(tables.DataTable):
ip = tables.Column("ip",
verbose_name=_("IP Address"),
attrs={'data-type': "ip"})
instance = tables.Column(get_instance_info,
fixed_ip = tables.Column(get_instance_info,
link=get_instance_link,
verbose_name=_("Instance"),
verbose_name=_("Mapped Fixed IP Address"),
empty_value="-")
pool = tables.Column("pool_name",
verbose_name=_("Floating IP Pool"),

View File

@ -124,6 +124,8 @@ class NetworkApiNovaFloatingIpTests(NetworkApiNovaTestBase):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(getattr(e, attr), getattr(r, attr))
self.assertEqual(e.instance_id, r.port_id)
exp_instance_type = 'compute' if e.instance_id else None
self.assertEqual(exp_instance_type, r.instance_type)
def test_floating_ip_get(self):
fip = self.api_floating_ips.first()
@ -136,10 +138,13 @@ class NetworkApiNovaFloatingIpTests(NetworkApiNovaTestBase):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(getattr(fip, attr), getattr(ret, attr))
self.assertEqual(fip.instance_id, ret.port_id)
self.assertEqual(fip.instance_id, ret.instance_id)
self.assertEqual('compute', ret.instance_type)
def test_floating_ip_allocate(self):
pool_name = 'fip_pool'
fip = self.api_floating_ips.first()
fip = [fip for fip in self.api_floating_ips.list()
if not fip.instance_id][0]
novaclient = self.stub_novaclient()
novaclient.floating_ips = self.mox.CreateMockAnything()
novaclient.floating_ips.create(pool=pool_name).AndReturn(fip)
@ -148,7 +153,8 @@ class NetworkApiNovaFloatingIpTests(NetworkApiNovaTestBase):
ret = api.network.tenant_floating_ip_allocate(self.request, pool_name)
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'instance_id']:
self.assertEqual(getattr(fip, attr), getattr(ret, attr))
self.assertEqual(fip.instance_id, ret.port_id)
self.assertIsNone(ret.port_id)
self.assertIsNone(ret.instance_type)
def test_floating_ip_release(self):
fip = self.api_floating_ips.first()
@ -557,6 +563,10 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
if exp['port_id']:
dev_id = assoc_port['device_id'] if exp['port_id'] else None
self.assertEqual(dev_id, ret.instance_id)
self.assertEqual('compute', ret.instance_type)
else:
self.assertIsNone(ret.instance_id)
self.assertIsNone(ret.instance_type)
def test_floating_ip_list_all_tenants(self):
fips = self.api_q_floating_ips.list()
@ -581,11 +591,14 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
self.assertEqual(getattr(ret, attr), exp[attr])
if exp['port_id']:
dev_id = assoc_port['device_id'] if exp['port_id'] else None
self.assertEqual(ret.instance_id, dev_id)
self.assertEqual(dev_id, ret.instance_id)
self.assertEqual('compute', ret.instance_type)
else:
self.assertIsNone(ret.instance_id)
self.assertIsNone(ret.instance_type)
def test_floating_ip_get_associated(self):
def _test_floating_ip_get_associated(self, assoc_port, exp_instance_type):
fip = self.api_q_floating_ips.list()[1]
assoc_port = self.api_ports.list()[1]
self.qclient.show_floatingip(fip['id']).AndReturn({'floatingip': fip})
self.qclient.show_port(assoc_port['id']) \
.AndReturn({'port': assoc_port})
@ -595,6 +608,18 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(fip[attr], getattr(ret, attr))
self.assertEqual(assoc_port['device_id'], ret.instance_id)
self.assertEqual(exp_instance_type, ret.instance_type)
def test_floating_ip_get_associated(self):
assoc_port = self.api_ports.list()[1]
self._test_floating_ip_get_associated(assoc_port, 'compute')
def test_floating_ip_get_associated_with_loadbalancer_vip(self):
assoc_port = copy.deepcopy(self.api_ports.list()[1])
assoc_port['device_owner'] = 'neutron:LOADBALANCER'
assoc_port['device_id'] = str(uuid.uuid4())
assoc_port['name'] = 'vip-' + str(uuid.uuid4())
self._test_floating_ip_get_associated(assoc_port, 'loadbalancer')
def test_floating_ip_get_unassociated(self):
fip = self.api_q_floating_ips.list()[0]
@ -605,6 +630,7 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(fip[attr], getattr(ret, attr))
self.assertIsNone(ret.instance_id)
self.assertIsNone(ret.instance_type)
def test_floating_ip_allocate(self):
ext_nets = [n for n in self.api_networks.list()
@ -621,6 +647,7 @@ class NetworkApiNeutronFloatingIpTests(NetworkApiNeutronTestBase):
for attr in ['id', 'ip', 'pool', 'fixed_ip', 'port_id']:
self.assertEqual(fip[attr], getattr(ret, attr))
self.assertIsNone(ret.instance_id)
self.assertIsNone(ret.instance_type)
def test_floating_ip_release(self):
fip = self.api_q_floating_ips.first()