From 4906c986b57eea9b53e5b0f6006917c72fb5fcc0 Mon Sep 17 00:00:00 2001 From: Akihiro Motoki Date: Thu, 30 Nov 2017 20:45:07 +0900 Subject: [PATCH] Redirect VM console dynamically Previously when a user accesses the network topology panel horizon resolves VM console URL when returning server data. This requires one API call to nova per VM, and this causes a scaling issue. Actually there is no need to resolves VM console URL when the network topology. A console URL corresponding to a requested VM can be resolved when a user actually accesses a console. This reduces the number of API calls drastically and addresses the scaling issue reported in the bug report. Change-Id: Icc667449e2988e6227012a6e899835a97ce0d738 Closes-Bug: #1723142 (cherry picked from commit 974f0418efdf171132747ded4a556df7b7af03d1) --- .../dashboards/project/instances/tests.py | 6 ++-- .../dashboards/project/instances/urls.py | 1 + .../dashboards/project/instances/views.py | 13 ++++++++ .../project/network_topology/tests.py | 33 ++++++++----------- .../project/network_topology/views.py | 10 ++---- 5 files changed, 33 insertions(+), 30 deletions(-) diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index c169566e21..b05929049b 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -1274,7 +1274,7 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): self.assertContains(res, "Unable to get log for") - def test_instance_vnc(self): + def test_instance_auto_console(self): server = self.servers.first() CONSOLE_OUTPUT = '/vncserver' CONSOLE_TITLE = '&title=%s(%s)' % (server.name, server.id) @@ -1287,12 +1287,12 @@ class InstanceTests(helpers.ResetImageAPIVersionMixin, helpers.TestCase): self.mox.StubOutWithMock(console, 'get_console') api.nova.server_get(IsA(http.HttpRequest), server.id) \ .AndReturn(server) - console.get_console(IgnoreArg(), 'VNC', server) \ + console.get_console(IgnoreArg(), 'AUTO', server) \ .AndReturn(('VNC', CONSOLE_URL)) self.mox.ReplayAll() - url = reverse('horizon:project:instances:vnc', + url = reverse('horizon:project:instances:auto_console', args=[server.id]) res = self.client.get(url) redirect = CONSOLE_URL diff --git a/openstack_dashboard/dashboards/project/instances/urls.py b/openstack_dashboard/dashboards/project/instances/urls.py index b07f7e3e1f..efbe9e85ac 100644 --- a/openstack_dashboard/dashboards/project/instances/urls.py +++ b/openstack_dashboard/dashboards/project/instances/urls.py @@ -34,6 +34,7 @@ urlpatterns = [ url(INSTANCES % 'serial', views.SerialConsoleView.as_view(), name='serial'), url(INSTANCES % 'console', views.console, name='console'), + url(INSTANCES % 'auto_console', views.auto_console, name='auto_console'), url(INSTANCES % 'vnc', views.vnc, name='vnc'), url(INSTANCES % 'spice', views.spice, name='spice'), url(INSTANCES % 'rdp', views.rdp, name='rdp'), diff --git a/openstack_dashboard/dashboards/project/instances/views.py b/openstack_dashboard/dashboards/project/instances/views.py index eea4379ffd..6a5ecf33fd 100644 --- a/openstack_dashboard/dashboards/project/instances/views.py +++ b/openstack_dashboard/dashboards/project/instances/views.py @@ -198,6 +198,19 @@ def console(request, instance_id): return http.HttpResponse(data.encode('utf-8'), content_type='text/plain') +def auto_console(request, instance_id): + console_type = getattr(settings, 'CONSOLE_TYPE', 'AUTO') + try: + instance = api.nova.server_get(request, instance_id) + console_url = project_console.get_console(request, console_type, + instance)[1] + return shortcuts.redirect(console_url) + except Exception: + redirect = reverse("horizon:project:instances:index") + msg = _('Unable to get console for instance "%s".') % instance_id + exceptions.handle(request, msg, redirect=redirect) + + def vnc(request, instance_id): try: instance = api.nova.server_get(request, instance_id) diff --git a/openstack_dashboard/dashboards/project/network_topology/tests.py b/openstack_dashboard/dashboards/project/network_topology/tests.py index c2f68366f1..1049be2d2d 100644 --- a/openstack_dashboard/dashboards/project/network_topology/tests.py +++ b/openstack_dashboard/dashboards/project/network_topology/tests.py @@ -20,7 +20,6 @@ from mox3.mox import IsA from oslo_serialization import jsonutils from openstack_dashboard import api -from openstack_dashboard.dashboards.project.instances import console from openstack_dashboard.dashboards.project.network_topology.views import \ TranslationHelper from openstack_dashboard.test import helpers as test @@ -37,8 +36,7 @@ class NetworkTopologyTests(test.TestCase): api.neutron: ('network_list_for_tenant', 'network_list', 'router_list', - 'port_list',), - console: ('get_console',)}) + 'port_list')}) def test_json_view(self): self._test_json_view() @@ -46,12 +44,20 @@ class NetworkTopologyTests(test.TestCase): OPENSTACK_NEUTRON_NETWORK={'enable_router': False}) @test.create_stubs({api.nova: ('server_list',), api.neutron: ('network_list_for_tenant', - 'port_list'), - console: ('get_console',)}) + 'port_list')}) def test_json_view_router_disabled(self): self._test_json_view(router_enable=False) - def _test_json_view(self, router_enable=True): + @django.test.utils.override_settings(CONSOLE_TYPE=None) + @test.create_stubs({api.nova: ('server_list',), + api.neutron: ('network_list_for_tenant', + 'network_list', + 'router_list', + 'port_list')}) + def test_json_view_console_disabled(self): + self._test_json_view(with_console=False) + + def _test_json_view(self, router_enable=True, with_console=True): api.nova.server_list( IsA(http.HttpRequest)).AndReturn([self.servers.list(), False]) @@ -63,17 +69,6 @@ class NetworkTopologyTests(test.TestCase): IsA(http.HttpRequest), self.tenant.id).AndReturn(tenant_networks) - for server in self.servers.list(): - if server.status != u'BUILD': - CONSOLE_OUTPUT = '/vncserver' - CONSOLE_TITLE = '&title=%s' % server.id - CONSOLE_URL = CONSOLE_OUTPUT + CONSOLE_TITLE - - console_mock = self.mox.CreateMock(api.nova.VNCConsole) - console_mock.url = CONSOLE_OUTPUT - console.get_console(IsA(http.HttpRequest), 'AUTO', server) \ - .AndReturn(('VNC', CONSOLE_URL)) - # router1 : gateway port not in the port list # router2 : no gateway port # router3 : gateway port included in port list @@ -109,8 +104,8 @@ class NetworkTopologyTests(test.TestCase): 'task': None, 'url': '/project/instances/%s/' % server.id } - if server.status != 'BUILD': - expect_server['console'] = 'vnc' + if server.status != 'BUILD' and with_console: + expect_server['console'] = 'auto_console' expect_server_urls.append(expect_server) self.assertEqual(expect_server_urls, data['servers']) diff --git a/openstack_dashboard/dashboards/project/network_topology/views.py b/openstack_dashboard/dashboards/project/network_topology/views.py index ad86de2124..c0a1320725 100644 --- a/openstack_dashboard/dashboards/project/network_topology/views.py +++ b/openstack_dashboard/dashboards/project/network_topology/views.py @@ -45,8 +45,6 @@ from openstack_dashboard.dashboards.project.network_topology \ import tabs as topology_tabs from openstack_dashboard.dashboards.project.network_topology import utils -from openstack_dashboard.dashboards.project.instances import\ - console as i_console from openstack_dashboard.dashboards.project.instances.tables import \ STATUS_DISPLAY_CHOICES as instance_choices from openstack_dashboard.dashboards.project.instances import\ @@ -251,12 +249,8 @@ class JSONView(View): # Avoid doing extra calls for console if the server is in # a invalid status for console connection if server.status.lower() not in console_invalid_status: - try: - console = i_console.get_console( - request, console_type, server)[0].lower() - server_data['console'] = console - except exceptions.NotAvailable: - pass + if console_type: + server_data['console'] = 'auto_console' data.append(server_data) self.add_resource_url('horizon:project:instances:detail', data)