Merge "Allow to skip API calls to Neutron in instance tables"

This commit is contained in:
Zuul 2017-12-12 21:28:20 +00:00 committed by Gerrit Code Review
commit e23048774b
7 changed files with 72 additions and 26 deletions

View File

@ -2126,6 +2126,39 @@ Setting ``enable_quotas`` to ``False`` will make Horizon treat all Nova
quotas as disabled, thus it won't try to modify them. By default, quotas are
enabled.
OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. versionadded:: 13.0.0(Queens)
Default: ``True``
This settings controls whether IP addresses of servers are retrieved from
neutron in the project instance table. Setting this to ``False`` may mitigate
a performance issue in the project instance table in large deployments.
If your deployment has no support of floating IP like provider network
scenario, you can set this to ``False`` in most cases. If your deployment
supports floating IP, read the detail below and understand the under-the-hood
before setting this to ``False``.
Nova has a mechanism to cache network info but it is not fast enough
in some cases. For example, when a user associates a floating IP or
updates an IP address of an server port, it is not reflected to the nova
network info cache immediately. This means an action which a user makes
from the horizon instance table is not reflected into the table content
just after the action. To avoid this, horizon retrieves IP address info
from neutron when retrieving a list of servers from nova.
On the other hand, this operation requires a full list of neutron ports
and can potentially lead to a performance issue in large deployments
(`bug 1722417 <https://bugs.launchpad.net/horizon/+bug/1722417>`__).
This issue can be avoided by skipping querying IP addresses to neutron
and setting this to ``False`` achieves this.
Note that when disabling the query to neutron it takes some time until
associated floating IPs are visible in the project instance table and
users may reload the table to check them.
OPENSTACK_NOVA_EXTENSIONS_BLACKLIST
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -32,7 +32,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
@test.create_stubs({
api.nova: ('flavor_list', 'server_list', 'extension_supported',),
api.keystone: ('tenant_list',),
api.network: ('servers_update_addresses',),
api.glance: ('image_list_detailed',),
})
def test_index(self):
@ -53,8 +52,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova.server_list(IsA(http.HttpRequest),
search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers,
all_tenants=True)
self.mox.ReplayAll()
res = self.client.get(INDEX_URL)
@ -66,7 +63,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova: ('flavor_list', 'flavor_get', 'server_list',
'extension_supported',),
api.keystone: ('tenant_list',),
api.network: ('servers_update_addresses',),
api.glance: ('image_list_detailed',),
})
def test_index_flavor_list_exception(self):
@ -78,8 +74,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova.server_list(IsA(http.HttpRequest),
search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers,
all_tenants=True)
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
@ -103,7 +97,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova: ('flavor_list', 'flavor_get', 'server_list',
'extension_supported',),
api.keystone: ('tenant_list',),
api.network: ('servers_update_addresses',),
api.glance: ('image_list_detailed',),
})
def test_index_flavor_get_exception(self):
@ -123,8 +116,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova.server_list(IsA(http.HttpRequest),
search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers,
all_tenants=True)
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
@ -207,7 +198,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
@test.create_stubs({
api.nova: ('flavor_list', 'server_list', 'extension_supported', ),
api.keystone: ('tenant_list',),
api.network: ('servers_update_addresses',),
api.glance: ('image_list_detailed',),
})
def test_index_options_before_migrate(self):
@ -223,8 +213,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova.server_list(IsA(http.HttpRequest),
search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers,
all_tenants=True)
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
api.nova.extension_supported('Shelve', IsA(http.HttpRequest)) \
@ -239,7 +227,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
@test.create_stubs({
api.nova: ('flavor_list', 'server_list', 'extension_supported',),
api.keystone: ('tenant_list',),
api.network: ('servers_update_addresses',),
api.glance: ('image_list_detailed',),
})
def test_index_options_after_migrate(self):
@ -263,8 +250,6 @@ class InstanceViewTest(test.BaseAdminViewTests):
api.nova.server_list(IsA(http.HttpRequest),
search_opts=search_opts) \
.AndReturn([servers, False])
api.network.servers_update_addresses(IsA(http.HttpRequest), servers,
all_tenants=True)
self.mox.ReplayAll()
res = self.client.get(INDEX_URL)

View File

@ -158,15 +158,6 @@ class AdminIndexView(tables.DataTableView):
# don't call api.network
return
try:
api.network.servers_update_addresses(self.request, instances,
all_tenants=True)
except Exception:
exceptions.handle(
self.request,
message=_('Unable to retrieve IP addresses from Neutron.'),
ignore=True)
with futurist.ThreadPoolExecutor(max_workers=3) as e:
e.submit(fn=_task_get_tenants)
e.submit(fn=_task_get_images)

View File

@ -132,7 +132,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
'servers_update_addresses',
),
})
def _get_index(self):
def _get_index(self, use_servers_update_address=True):
servers = self.servers.list()
api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \
.MultipleTimes().AndReturn(True)
@ -148,7 +148,9 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.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)
if use_servers_update_address:
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.neutron.floating_ip_supported(IsA(http.HttpRequest)) \
@ -170,6 +172,16 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase):
self.assertItemsEqual(instances, self.servers.list())
self.assertNotContains(res, "Launch Instance (Quota exceeded)")
@override_settings(OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES=False)
def test_index_without_servers_update_addresses(self):
res = self._get_index(use_servers_update_address=False)
self.assertTemplateUsed(res, INDEX_TEMPLATE)
instances = res.context['instances_table'].data
self.assertItemsEqual(instances, self.servers.list())
self.assertNotContains(res, "Launch Instance (Quota exceeded)")
@helpers.create_stubs({
api.nova: ('server_list', 'tenant_absolute_limits', 'flavor_list'),
api.glance: ('image_list_detailed',),

View File

@ -91,6 +91,16 @@ class IndexView(tables.DataTableView):
# don't call api.network
return
# TODO(future): Explore more efficient logic to sync IP address
# and drop the setting OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES.
# The situation servers_update_addresses() is needed # is only
# when IP address of a server is updated via neutron API and
# nova network info cache is not synced. Precisely there is no
# need to check IP addresses of all serves. It is sufficient to
# fetch IP address information for servers recently updated.
if not getattr(settings,
'OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES', True):
return
try:
api.network.servers_update_addresses(self.request, instances)
except Exception:

View File

@ -303,6 +303,11 @@ OPENSTACK_HYPERVISOR_FEATURES = {
'enable_quotas': True
}
# This settings controls whether IP addresses of servers are retrieved from
# neutron in the project instance table. Setting this to ``False`` may mitigate
# a performance issue in the project instance table in large deployments.
#OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES = True
# The OPENSTACK_CINDER_FEATURES settings can be used to enable optional
# services provided by cinder that is not exposed by its extension API.
OPENSTACK_CINDER_FEATURES = {

View File

@ -0,0 +1,10 @@
---
fixes:
- |
A new setting ``OPENSTACK_INSTANCE_RETRIEVE_IP_ADDRESSES`` was introduced
to control whether IP addresses of servers are retrieved from neutron in
the project instance table. This setting was introduces to mitigate a
performance issue in large deployments and setting this to ``False``
skips the query to neutron. Deployments without floating IP support can
set this setting to ``False`` for better performance.
For more detail, see [:bug:`1722417`].