diff -r 097063f324c0 -r 4b1def16fe9b components/openstack/horizon/patches/12-launchpad-1265032.patch --- a/components/openstack/horizon/patches/12-launchpad-1265032.patch Thu Apr 16 01:36:32 2015 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,868 +0,0 @@ -Upstream patch to fix launchpad bug 1265032. This fix is available in -Icehouse 2014.1 but not yet available in Havana. - -From f3557786e2a9f026a16d2fd3b8fa9243bc4c70a9 Mon Sep 17 00:00:00 2001 -From: Assaf Muller -Date: Sun, 29 Dec 2013 16:44:46 +0200 -Subject: Get instance networking information from Neutron - -project/instances, admin/instances and the instance details page -all get networking information from Nova. However, with Neutron -enabled, floating IP associations are done direcly with Neutron, -meaning that Nova's DB will fall out of sync and thus the GUI -won't reflect successful floating IP associations until Nova -polls Neutron again and updates its DB. The polling can take -up to several minutes to complete for consecutive floating IP -operations. - -The solution is to update instances' networking information from -Neutron immediately after the call to list Nova instances. - -Conflicts: - openstack_dashboard/dashboards/project/instances/tests.py - openstack_dashboard/dashboards/project/instances/views.py - -Closes-Bug: #1265032 -Change-Id: I0382fa9a4a9fff21e7b4d05cd3b76783f826735f -(cherry picked from commit 715d6b822838009530b7792cd7749164ae3fc663) - -diff --git a/openstack_dashboard/api/network.py b/openstack_dashboard/api/network.py -index 7ab233c..ea76d41 100644 ---- a/openstack_dashboard/api/network.py -+++ b/openstack_dashboard/api/network.py -@@ -132,3 +132,15 @@ def server_update_security_groups(request, instance_id, - - def security_group_backend(request): - return NetworkClient(request).secgroups.backend -+ -+ -+def servers_update_addresses(request, servers): -+ """Retrieve servers networking information from Neutron if enabled. -+ -+ Should be used when up to date networking information is required, -+ and Nova's networking info caching mechanism is not fast enough. -+ -+ """ -+ neutron_enabled = base.is_service_enabled(request, 'network') -+ if neutron_enabled: -+ neutron.servers_update_addresses(request, servers) -diff --git a/openstack_dashboard/api/neutron.py b/openstack_dashboard/api/neutron.py -index 4443c9b..c09a674 100644 ---- a/openstack_dashboard/api/neutron.py -+++ b/openstack_dashboard/api/neutron.py -@@ -21,12 +21,15 @@ - - from __future__ import absolute_import - -+import collections - import logging -+import netaddr - - from django.conf import settings # noqa - from django.utils.datastructures import SortedDict # noqa - from django.utils.translation import ugettext_lazy as _ # noqa - -+from horizon import messages - from horizon.utils.memoized import memoized # noqa - - from openstack_dashboard.api import base -@@ -321,12 +324,12 @@ class FloatingIpManager(network_base.FloatingIpManager): - return [FloatingIpPool(pool) for pool - in self.client.list_networks(**search_opts).get('networks')] - -- def list(self): -+ def list(self, **search_opts): - tenant_id = self.request.user.tenant_id - # In Neutron, list_floatingips returns Floating IPs from all tenants - # when the API is called with admin role, so we need to filter them - # with tenant_id. -- fips = self.client.list_floatingips(tenant_id=tenant_id) -+ fips = self.client.list_floatingips(tenant_id=tenant_id, **search_opts) - fips = fips.get('floatingips') - # Get port list to add instance_id to floating IP list - # instance_id is stored in device_id attribute -@@ -727,6 +730,88 @@ def provider_list(request): - return providers['service_providers'] - - -+def servers_update_addresses(request, servers): -+ """Retrieve servers networking information from Neutron if enabled. -+ -+ Should be used when up to date networking information is required, -+ and Nova's networking info caching mechanism is not fast enough. -+ """ -+ -+ # Get all (filtered for relevant servers) information from Neutron -+ try: -+ ports = port_list(request, -+ device_id=[instance.id for instance in servers]) -+ floating_ips = FloatingIpManager(request).list( -+ port_id=[port.id for port in ports]) -+ networks = network_list(request, -+ id=[port.network_id for port in ports]) -+ except Exception: -+ error_message = _('Unable to connect to Neutron.') -+ LOG.error(error_message) -+ messages.error(request, error_message) -+ return -+ -+ # Map instance to its ports -+ instances_ports = collections.defaultdict(list) -+ for port in ports: -+ instances_ports[port.device_id].append(port) -+ -+ # Map port to its floating ips -+ ports_floating_ips = collections.defaultdict(list) -+ for fip in floating_ips: -+ ports_floating_ips[fip.port_id].append(fip) -+ -+ # Map network id to its name -+ network_names = dict(((network.id, network.name) for network in networks)) -+ -+ for server in servers: -+ try: -+ addresses = _server_get_addresses( -+ request, -+ server, -+ instances_ports, -+ ports_floating_ips, -+ network_names) -+ except Exception as e: -+ LOG.error(e) -+ else: -+ server.addresses = addresses -+ -+ -+def _server_get_addresses(request, server, ports, floating_ips, network_names): -+ def _format_address(mac, ip, type): -+ try: -+ version = netaddr.IPAddress(ip).version -+ except Exception as e: -+ error_message = _('Unable to parse IP address %s.') % ip -+ LOG.error(error_message) -+ messages.error(request, error_message) -+ raise e -+ return {u'OS-EXT-IPS-MAC:mac_addr': mac, -+ u'version': version, -+ u'addr': ip, -+ u'OS-EXT-IPS:type': type} -+ -+ addresses = collections.defaultdict(list) -+ instance_ports = ports.get(server.id, []) -+ for port in instance_ports: -+ network_name = network_names.get(port.network_id) -+ if network_name is not None: -+ for fixed_ip in port.fixed_ips: -+ addresses[network_name].append( -+ _format_address(port.mac_address, -+ fixed_ip['ip_address'], -+ u'fixed')) -+ port_fips = floating_ips.get(port.id, []) -+ for fip in port_fips: -+ addresses[network_name].append( -+ _format_address(port.mac_address, -+ fip.floating_ip_address, -+ u'floating')) -+ -+ return dict(addresses) -+ -+ - @memoized - def list_extensions(request): - extensions_list = neutronclient(request).list_extensions() -diff --git a/openstack_dashboard/dashboards/admin/instances/tests.py b/openstack_dashboard/dashboards/admin/instances/tests.py -index 6beb8fa..9236b4e 100644 ---- a/openstack_dashboard/dashboards/admin/instances/tests.py -+++ b/openstack_dashboard/dashboards/admin/instances/tests.py -@@ -20,6 +20,7 @@ from django.core.urlresolvers import reverse # noqa - from django import http - from django.utils.datastructures import SortedDict # noqa - -+from mox import IgnoreArg # noqa - from mox import IsA # noqa - - from openstack_dashboard import api -@@ -29,7 +30,8 @@ from openstack_dashboard.test import helpers as test - class InstanceViewTest(test.BaseAdminViewTests): - @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'extension_supported',), -- api.keystone: ('tenant_list',)}) -+ api.keystone: ('tenant_list',), -+ api.network: ('servers_update_addresses',)}) - def test_index(self): - servers = self.servers.list() - flavors = self.flavors.list() -@@ -42,6 +44,7 @@ class InstanceViewTest(test.BaseAdminViewTests): - api.nova.server_list(IsA(http.HttpRequest), - all_tenants=True, search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(flavors) - self.mox.ReplayAll() - -@@ -52,7 +55,8 @@ class InstanceViewTest(test.BaseAdminViewTests): - - @test.create_stubs({api.nova: ('flavor_list', 'flavor_get', - 'server_list', 'extension_supported',), -- api.keystone: ('tenant_list',)}) -+ api.keystone: ('tenant_list',), -+ api.network: ('servers_update_addresses',)}) - def test_index_flavor_list_exception(self): - servers = self.servers.list() - tenants = self.tenants.list() -@@ -63,6 +67,7 @@ class InstanceViewTest(test.BaseAdminViewTests): - api.nova.server_list(IsA(http.HttpRequest), - all_tenants=True, search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ - .MultipleTimes().AndReturn(True) - api.nova.flavor_list(IsA(http.HttpRequest)). \ -@@ -82,7 +87,8 @@ class InstanceViewTest(test.BaseAdminViewTests): - - @test.create_stubs({api.nova: ('flavor_list', 'flavor_get', - 'server_list', 'extension_supported', ), -- api.keystone: ('tenant_list',)}) -+ api.keystone: ('tenant_list',), -+ api.network: ('servers_update_addresses',)}) - def test_index_flavor_get_exception(self): - servers = self.servers.list() - flavors = self.flavors.list() -@@ -96,6 +102,7 @@ class InstanceViewTest(test.BaseAdminViewTests): - api.nova.server_list(IsA(http.HttpRequest), - all_tenants=True, search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ - .MultipleTimes().AndReturn(True) - api.nova.flavor_list(IsA(http.HttpRequest)). \ -@@ -162,14 +169,17 @@ class InstanceViewTest(test.BaseAdminViewTests): - - @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'extension_supported', ), -- api.keystone: ('tenant_list',)}) -+ api.keystone: ('tenant_list',), -+ api.network: ('servers_update_addresses',)}) - def test_index_options_before_migrate(self): -+ servers = self.servers.list() - api.keystone.tenant_list(IsA(http.HttpRequest)).\ - AndReturn([self.tenants.list(), False]) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), - all_tenants=True, search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ - .MultipleTimes().AndReturn(True) - api.nova.flavor_list(IsA(http.HttpRequest)).\ -@@ -183,7 +193,8 @@ class InstanceViewTest(test.BaseAdminViewTests): - - @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'extension_supported', ), -- api.keystone: ('tenant_list',)}) -+ api.keystone: ('tenant_list',), -+ api.network: ('servers_update_addresses',)}) - def test_index_options_after_migrate(self): - servers = self.servers.list() - server1 = servers[0] -@@ -197,7 +208,8 @@ class InstanceViewTest(test.BaseAdminViewTests): - .MultipleTimes().AndReturn(True) - api.nova.server_list(IsA(http.HttpRequest), - all_tenants=True, search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IsA(http.HttpRequest)).\ - AndReturn(self.flavors.list()) - self.mox.ReplayAll() -diff --git a/openstack_dashboard/dashboards/admin/instances/views.py b/openstack_dashboard/dashboards/admin/instances/views.py -index 3397f25..4bc6bee 100644 ---- a/openstack_dashboard/dashboards/admin/instances/views.py -+++ b/openstack_dashboard/dashboards/admin/instances/views.py -@@ -74,6 +74,14 @@ class AdminIndexView(tables.DataTableView): - exceptions.handle(self.request, - _('Unable to retrieve instance list.')) - if instances: -+ try: -+ api.network.servers_update_addresses(self.request, instances) -+ except Exception: -+ exceptions.handle( -+ self.request, -+ message=_('Unable to retrieve IP addresses from Neutron.'), -+ ignore=True) -+ - # Gather our flavors to correlate against IDs - try: - flavors = api.nova.flavor_list(self.request) -diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py -index 8d56455..b2b066f 100644 ---- a/openstack_dashboard/dashboards/project/instances/tests.py -+++ b/openstack_dashboard/dashboards/project/instances/tests.py -@@ -52,9 +52,11 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_index(self): -+ servers = self.servers.list() - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ - .MultipleTimes().AndReturn(True) -@@ -64,7 +66,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \ - .MultipleTimes().AndReturn(self.limits['absolute']) - api.network.floating_ip_simple_associate_supported( -@@ -104,7 +107,8 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_index_flavor_list_exception(self): - servers = self.servers.list() -@@ -116,6 +120,7 @@ class InstanceTests(test.TestCase): - .MultipleTimes().AndReturn(True) - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IsA(http.HttpRequest)) \ - .AndRaise(self.exceptions.nova) - api.glance.image_list_detailed(IgnoreArg()) \ -@@ -144,7 +149,8 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_index_flavor_get_exception(self): - servers = self.servers.list() -@@ -160,6 +166,7 @@ class InstanceTests(test.TestCase): - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IsA(http.HttpRequest)).AndReturn(flavors) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) -@@ -187,7 +194,8 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_index_with_instance_booted_from_volume(self): - volume_server = self.servers.first() -@@ -206,6 +214,7 @@ class InstanceTests(test.TestCase): - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ - .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \ - .MultipleTimes().AndReturn(self.limits['absolute']) - api.network.floating_ip_simple_associate_supported( -@@ -223,18 +232,20 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ('server_list', - 'flavor_list', - 'server_delete',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_terminate_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list()) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) - api.nova.server_delete(IsA(http.HttpRequest), server.id) -- - self.mox.ReplayAll() - - formData = {'action': 'instances__terminate__%s' % server.id} -@@ -245,13 +256,16 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ('server_list', - 'flavor_list', - 'server_delete',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_terminate_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list()) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) -@@ -269,9 +283,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_pause_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ -@@ -282,7 +298,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_pause(IsA(http.HttpRequest), server.id) - - self.mox.ReplayAll() -@@ -296,9 +313,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_pause_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ -@@ -309,7 +328,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_pause(IsA(http.HttpRequest), server.id) \ - .AndRaise(self.exceptions.nova) - -@@ -324,9 +344,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_unpause_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - server.status = "PAUSED" - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ -@@ -337,7 +359,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_unpause(IsA(http.HttpRequest), server.id) - - self.mox.ReplayAll() -@@ -351,9 +374,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_unpause_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - server.status = "PAUSED" - - api.nova.extension_supported('AdminActions', -@@ -365,7 +390,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_unpause(IsA(http.HttpRequest), server.id) \ - .AndRaise(self.exceptions.nova) - -@@ -379,16 +405,19 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ('server_reboot', - 'server_list', - 'flavor_list',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_reboot_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - api.nova.flavor_list(IsA(http.HttpRequest)) \ - .AndReturn(self.flavors.list()) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_reboot(IsA(http.HttpRequest), server.id, - soft_reboot=False) - -@@ -402,9 +431,11 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ('server_reboot', - 'server_list', - 'flavor_list',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_reboot_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.flavor_list(IsA(http.HttpRequest)) \ - .AndReturn(self.flavors.list()) -@@ -412,7 +443,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_reboot(IsA(http.HttpRequest), server.id, - soft_reboot=False) \ - .AndRaise(self.exceptions.nova) -@@ -427,9 +459,11 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ('server_reboot', - 'server_list', - 'flavor_list',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_soft_reboot_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.flavor_list(IsA(http.HttpRequest)) \ - .AndReturn(self.flavors.list()) -@@ -437,7 +471,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_reboot(IsA(http.HttpRequest), server.id, - soft_reboot=True) - -@@ -452,9 +487,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_suspend_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ -@@ -465,7 +502,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_suspend(IsA(http.HttpRequest), unicode(server.id)) - - self.mox.ReplayAll() -@@ -479,9 +517,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_suspend_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - - api.nova.extension_supported('AdminActions', - IsA(http.HttpRequest)) \ -@@ -492,7 +532,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_suspend(IsA(http.HttpRequest), unicode(server.id)) \ - .AndRaise(self.exceptions.nova) - -@@ -507,9 +548,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_resume_instance(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - server.status = "SUSPENDED" - - api.nova.extension_supported('AdminActions', -@@ -521,7 +564,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_resume(IsA(http.HttpRequest), unicode(server.id)) - - self.mox.ReplayAll() -@@ -535,9 +579,11 @@ class InstanceTests(test.TestCase): - 'server_list', - 'flavor_list', - 'extension_supported',), -- api.glance: ('image_list_detailed',)}) -+ api.glance: ('image_list_detailed',), -+ api.network: ('servers_update_addresses',)}) - def test_resume_instance_exception(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - server.status = "SUSPENDED" - - api.nova.extension_supported('AdminActions', -@@ -549,7 +595,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.server_resume(IsA(http.HttpRequest), - unicode(server.id)) \ - .AndRaise(self.exceptions.nova) -@@ -564,12 +611,15 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ("server_get", - "instance_volumes_list", - "flavor_get"), -- api.network: ("server_security_groups",)}) -+ api.network: ("server_security_groups", -+ "servers_update_addresses")}) - def test_instance_details_volumes(self): - server = self.servers.first() - volumes = [self.volumes.list()[1]] - - api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), -+ IgnoreArg()) - api.nova.instance_volumes_list(IsA(http.HttpRequest), - server.id).AndReturn(volumes) - api.nova.flavor_get(IsA(http.HttpRequest), server.flavor['id']) \ -@@ -588,12 +638,15 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ("server_get", - "instance_volumes_list", - "flavor_get"), -- api.network: ("server_security_groups",)}) -+ api.network: ("server_security_groups", -+ "servers_update_addresses")}) - def test_instance_details_volume_sorting(self): - server = self.servers.first() - volumes = self.volumes.list()[1:3] - - api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), -+ IgnoreArg()) - api.nova.instance_volumes_list(IsA(http.HttpRequest), - server.id).AndReturn(volumes) - api.nova.flavor_get(IsA(http.HttpRequest), server.flavor['id']) \ -@@ -616,11 +669,14 @@ class InstanceTests(test.TestCase): - @test.create_stubs({api.nova: ("server_get", - "instance_volumes_list", - "flavor_get"), -- api.network: ("server_security_groups",)}) -+ api.network: ("server_security_groups", -+ "servers_update_addresses")}) - def test_instance_details_metadata(self): - server = self.servers.first() - - api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), -+ IgnoreArg()) - api.nova.instance_volumes_list(IsA(http.HttpRequest), - server.id).AndReturn([]) - api.nova.flavor_get(IsA(http.HttpRequest), server.flavor['id']) \ -@@ -1668,9 +1724,11 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_launch_button_disabled_when_quota_exceeded(self): -+ servers = self.servers.list() - limits = self.limits['absolute'] - limits['totalInstancesUsed'] = limits['maxTotalInstances'] - -@@ -1683,7 +1741,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \ - .MultipleTimes().AndReturn(limits) - api.network.floating_ip_simple_associate_supported( -@@ -1709,9 +1768,11 @@ class InstanceTests(test.TestCase): - 'extension_supported',), - api.glance: ('image_list_detailed',), - api.network: -- ('floating_ip_simple_associate_supported',), -+ ('floating_ip_simple_associate_supported', -+ 'servers_update_addresses',), - }) - def test_index_options_after_migrate(self): -+ servers = self.servers.list() - server = self.servers.first() - server.status = "VERIFY_RESIZE" - api.nova.extension_supported('AdminActions', -@@ -1723,7 +1784,8 @@ class InstanceTests(test.TestCase): - .AndReturn((self.images.list(), False)) - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.tenant_absolute_limits(IsA(http.HttpRequest), reserved=True) \ - .MultipleTimes().AndReturn(self.limits['absolute']) - api.network.floating_ip_simple_associate_supported( -@@ -1802,17 +1864,20 @@ class InstanceTests(test.TestCase): - - @test.create_stubs({api.network: ('floating_ip_target_get_by_instance', - 'tenant_floating_ip_allocate', -- 'floating_ip_associate'), -+ 'floating_ip_associate', -+ 'servers_update_addresses',), - api.glance: ('image_list_detailed',), - api.nova: ('server_list', - 'flavor_list')}) - def test_associate_floating_ip(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - fip = self.q_floating_ips.first() - - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list()) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) -@@ -1839,13 +1905,15 @@ class InstanceTests(test.TestCase): - - api.nova: ('server_list', - 'flavor_list')}) - def test_disassociate_floating_ip(self): -- server = self.servers.first() -+ servers = self.servers.list() -+ server = servers[0] - fip = self.q_floating_ips.first() - fip.port_id = server.id - - search_opts = {'marker': None, 'paginate': True} - api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ -- .AndReturn([self.servers.list(), False]) -+ .AndReturn([servers, False]) -+ api.network.servers_update_addresses(IsA(http.HttpRequest), servers) - api.nova.flavor_list(IgnoreArg()).AndReturn(self.flavors.list()) - api.glance.image_list_detailed(IgnoreArg()) \ - .AndReturn((self.images.list(), False)) -diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py -index 4826d8a..cebc5c0 100644 ---- a/openstack_dashboard/dashboards/project/instances/views.py -+++ b/openstack_dashboard/dashboards/project/instances/views.py -@@ -66,9 +66,18 @@ class IndexView(tables.DataTableView): - instances = [] - exceptions.handle(self.request, - _('Unable to retrieve instances.')) -- # Gather our flavors and images and correlate our instances to them -+ - if instances: - try: -+ api.network.servers_update_addresses(self.request, instances) -+ except Exception: -+ exceptions.handle( -+ self.request, -+ message=_('Unable to retrieve IP addresses from Neutron.'), -+ ignore=True) -+ -+ # Gather our flavors and images and correlate our instances to them -+ try: - flavors = api.nova.flavor_list(self.request) - except Exception: - flavors = [] -@@ -233,6 +242,15 @@ class DetailView(tabs.TabView): - 'instance "%s".') % instance_id, - redirect=redirect) - self._instance = instance -+ -+ try: -+ api.network.servers_update_addresses(self.request, [instance]) -+ except Exception: -+ exceptions.handle( -+ self.request, -+ _('Unable to retrieve IP addresses from Neutron for ' -+ 'instance "%s".') % instance_id, ignore=True) -+ - return self._instance - - def get_tabs(self, request, *args, **kwargs): --- -cgit v0.10.1 -