From 39229c1844e739ab6ea8140c0e23f5e1f11223f3 Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Mon, 15 Sep 2014 17:30:52 +0900 Subject: [PATCH] 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 --- openstack_dashboard/api/neutron.py | 41 +++++++++++++------ openstack_dashboard/api/nova.py | 5 ++- .../floating_ips/tables.py | 27 ++++++++---- .../test/api_tests/network_tests.py | 37 ++++++++++++++--- 4 files changed, 83 insertions(+), 27 deletions(-) diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py index fdefb011a1..116b440e13 100644 --- a/openstack_dashboard/api/neutron.py +++ b/openstack_dashboard/api/neutron.py @@ -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): diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index 5a92c961f2..eabc92bb88 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -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) diff --git a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py b/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py index 72b3ae8c7f..31dbb9eed0 100644 --- a/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py +++ b/openstack_dashboard/dashboards/project/access_and_security/floating_ips/tables.py @@ -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"), diff --git a/openstack_dashboard/test/api_tests/network_tests.py b/openstack_dashboard/test/api_tests/network_tests.py index 48f216844c..1060c421c9 100644 --- a/openstack_dashboard/test/api_tests/network_tests.py +++ b/openstack_dashboard/test/api_tests/network_tests.py @@ -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()