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.

Closes-Bug: #1265032
Change-Id: I0382fa9a4a9fff21e7b4d05cd3b76783f826735f
This commit is contained in:
Assaf Muller
2013-12-29 16:44:46 +02:00
parent 6fd1a1522a
commit 715d6b8228
6 changed files with 273 additions and 69 deletions

View File

@@ -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)

View File

@@ -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
@@ -732,6 +735,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()

View File

@@ -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
@@ -32,7 +33,8 @@ INDEX_URL = reverse('horizon:admin:instances:index')
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()
@@ -45,6 +47,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()
@@ -55,7 +58,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()
@@ -66,6 +70,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)). \
@@ -85,7 +90,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()
@@ -99,6 +105,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)). \
@@ -165,14 +172,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)).\
@@ -186,7 +196,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]
@@ -200,7 +211,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()

View File

@@ -80,6 +80,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)

View File

@@ -54,9 +54,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)
@@ -66,7 +68,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(
@@ -106,7 +109,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()
@@ -118,6 +122,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()) \
@@ -146,7 +151,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()
@@ -162,6 +168,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))
@@ -189,7 +196,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()
@@ -208,6 +216,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(
@@ -225,18 +234,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}
@@ -247,13 +258,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))
@@ -271,9 +285,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)) \
@@ -284,7 +300,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()
@@ -298,9 +315,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)) \
@@ -311,7 +330,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)
@@ -326,9 +346,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)) \
@@ -339,7 +361,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()
@@ -353,9 +376,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',
@@ -367,7 +392,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)
@@ -381,16 +407,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)
@@ -404,9 +433,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())
@@ -414,7 +445,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)
@@ -429,9 +461,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())
@@ -439,7 +473,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)
@@ -454,9 +489,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)) \
@@ -467,7 +504,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()
@@ -481,9 +519,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)) \
@@ -494,7 +534,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)
@@ -509,9 +550,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',
@@ -523,7 +566,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()
@@ -537,9 +581,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',
@@ -551,7 +597,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)
@@ -566,12 +613,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']) \
@@ -590,12 +640,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']) \
@@ -618,11 +671,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']) \
@@ -650,7 +706,8 @@ 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_fault(self):
server = self.servers.first()
@@ -666,6 +723,8 @@ class InstanceTests(test.TestCase):
"created": "2013-10-07T00:08:32Z"}
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']) \
@@ -1781,9 +1840,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']
@@ -1796,7 +1857,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(
@@ -1822,9 +1884,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',
@@ -1836,7 +1900,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(
@@ -1915,17 +1980,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))
@@ -1946,18 +2014,21 @@ class InstanceTests(test.TestCase):
@test.create_stubs({api.network: ('floating_ip_target_get_by_instance',
'tenant_floating_ip_list',
'floating_ip_disassociate',),
'floating_ip_disassociate',
'servers_update_addresses',),
api.glance: ('image_list_detailed',),
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))

View File

@@ -67,8 +67,17 @@ 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:
@@ -233,6 +242,13 @@ class DetailView(tabs.TabView):
_('Unable to retrieve details for '
'instance "%s".') % instance_id,
redirect=redirect)
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 instance
def get_tabs(self, request, *args, **kwargs):