From db9c08e1721710d3b8f866a47ec1034bf2cf7d9d Mon Sep 17 00:00:00 2001 From: ericpeterson-l Date: Wed, 17 Jul 2013 16:03:22 -0600 Subject: [PATCH] calling nova extensions api to enable certain nova features Fixes: bug #1202310 Change-Id: I47365b0a89ab572f25cb71bfe17cae547261df9d --- openstack_dashboard/api/nova.py | 20 ++++ .../dashboards/admin/instances/tests.py | 28 ++++-- .../dashboards/project/instances/tables.py | 6 ++ .../dashboards/project/instances/tests.py | 92 ++++++++++++++----- 4 files changed, 118 insertions(+), 28 deletions(-) diff --git a/openstack_dashboard/api/nova.py b/openstack_dashboard/api/nova.py index 5acd6ab702..57bb99ed01 100644 --- a/openstack_dashboard/api/nova.py +++ b/openstack_dashboard/api/nova.py @@ -28,6 +28,7 @@ from django.conf import settings from django.utils.translation import ugettext_lazy as _ from novaclient.v1_1 import client as nova_client +from novaclient.v1_1.contrib.list_extensions import ListExtManager from novaclient.v1_1 import security_group_rules as nova_rules from novaclient.v1_1.security_groups import SecurityGroup as NovaSecurityGroup from novaclient.v1_1.servers import REBOOT_HARD @@ -628,3 +629,22 @@ def aggregate_list(request): result.append(novaclient(request).aggregates.get(aggregate.id)) return result + + +@memoized +def list_extensions(request): + return ListExtManager(novaclient(request)).show_all() + + +@memoized +def extension_supported(extension_name, request): + """ + this method will determine if nova supports a given extension name. + example values for the extension_name include AdminActions, ConsoleOutput, + etc. + """ + extensions = list_extensions(request) + for extension in extensions: + if extension.name == extension_name: + return True + return False diff --git a/openstack_dashboard/dashboards/admin/instances/tests.py b/openstack_dashboard/dashboards/admin/instances/tests.py index 8e379ef601..be2373fabd 100644 --- a/openstack_dashboard/dashboards/admin/instances/tests.py +++ b/openstack_dashboard/dashboards/admin/instances/tests.py @@ -27,12 +27,15 @@ from openstack_dashboard.test import helpers as test class InstanceViewTest(test.BaseAdminViewTests): - @test.create_stubs({api.nova: ('flavor_list', 'server_list',), + @test.create_stubs({api.nova: ('flavor_list', 'server_list', + 'extension_supported',), api.keystone: ('tenant_list',)}) def test_index(self): servers = self.servers.list() flavors = self.flavors.list() tenants = self.tenants.list() + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.keystone.tenant_list(IsA(http.HttpRequest)).\ AndReturn([tenants, False]) search_opts = {'marker': None, 'paginate': True} @@ -48,7 +51,7 @@ class InstanceViewTest(test.BaseAdminViewTests): self.assertItemsEqual(instances, servers) @test.create_stubs({api.nova: ('flavor_list', 'flavor_get', - 'server_list',), + 'server_list', 'extension_supported',), api.keystone: ('tenant_list',)}) def test_index_flavor_list_exception(self): servers = self.servers.list() @@ -60,6 +63,8 @@ class InstanceViewTest(test.BaseAdminViewTests): api.nova.server_list(IsA(http.HttpRequest), all_tenants=True, search_opts=search_opts) \ .AndReturn([servers, False]) + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)). \ AndRaise(self.exceptions.nova) api.keystone.tenant_list(IsA(http.HttpRequest)).\ @@ -76,7 +81,7 @@ class InstanceViewTest(test.BaseAdminViewTests): self.assertItemsEqual(instances, servers) @test.create_stubs({api.nova: ('flavor_list', 'flavor_get', - 'server_list',), + 'server_list', 'extension_supported', ), api.keystone: ('tenant_list',)}) def test_index_flavor_get_exception(self): servers = self.servers.list() @@ -91,6 +96,8 @@ class InstanceViewTest(test.BaseAdminViewTests): api.nova.server_list(IsA(http.HttpRequest), all_tenants=True, search_opts=search_opts) \ .AndReturn([servers, False]) + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)). \ AndReturn(flavors) api.keystone.tenant_list(IsA(http.HttpRequest)).\ @@ -119,7 +126,8 @@ class InstanceViewTest(test.BaseAdminViewTests): self.assertTemplateUsed(res, 'admin/instances/index.html') self.assertEqual(len(res.context['instances_table'].data), 0) - @test.create_stubs({api.nova: ('server_get', 'flavor_get',), + @test.create_stubs({api.nova: ('server_get', 'flavor_get', + 'extension_supported', ), api.keystone: ('tenant_get',)}) def test_ajax_loading_instances(self): server = self.servers.first() @@ -127,6 +135,8 @@ class InstanceViewTest(test.BaseAdminViewTests): tenant = self.tenants.list()[0] api.nova.server_get(IsA(http.HttpRequest), server.id).AndReturn(server) + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_get(IsA(http.HttpRequest), server.flavor['id']).AndReturn(flavor) api.keystone.tenant_get(IsA(http.HttpRequest), @@ -150,7 +160,8 @@ class InstanceViewTest(test.BaseAdminViewTests): self.assertContains(res, "Active", 1, 200) self.assertContains(res, "Running", 1, 200) - @test.create_stubs({api.nova: ('flavor_list', 'server_list',), + @test.create_stubs({api.nova: ('flavor_list', 'server_list', + 'extension_supported', ), api.keystone: ('tenant_list',)}) def test_index_options_before_migrate(self): api.keystone.tenant_list(IsA(http.HttpRequest)).\ @@ -159,6 +170,8 @@ class InstanceViewTest(test.BaseAdminViewTests): api.nova.server_list(IsA(http.HttpRequest), all_tenants=True, search_opts=search_opts) \ .AndReturn([self.servers.list(), False]) + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)).\ AndReturn(self.flavors.list()) self.mox.ReplayAll() @@ -168,7 +181,8 @@ class InstanceViewTest(test.BaseAdminViewTests): self.assertNotContains(res, "instances__confirm") self.assertNotContains(res, "instances__revert") - @test.create_stubs({api.nova: ('flavor_list', 'server_list',), + @test.create_stubs({api.nova: ('flavor_list', 'server_list', + 'extension_supported', ), api.keystone: ('tenant_list',)}) def test_index_options_after_migrate(self): servers = self.servers.list() @@ -179,6 +193,8 @@ class InstanceViewTest(test.BaseAdminViewTests): api.keystone.tenant_list(IsA(http.HttpRequest)) \ .AndReturn([self.tenants.list(), False]) search_opts = {'marker': None, 'paginate': True} + api.nova.extension_supported('AdminActions', IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.server_list(IsA(http.HttpRequest), all_tenants=True, search_opts=search_opts) \ .AndReturn([self.servers.list(), False]) diff --git a/openstack_dashboard/dashboards/project/instances/tables.py b/openstack_dashboard/dashboards/project/instances/tables.py index a953347470..b3e932a6cc 100644 --- a/openstack_dashboard/dashboards/project/instances/tables.py +++ b/openstack_dashboard/dashboards/project/instances/tables.py @@ -127,6 +127,9 @@ class TogglePause(tables.BatchAction): classes = ("btn-pause",) def allowed(self, request, instance=None): + if not api.nova.extension_supported('AdminActions', + request): + return False self.paused = False if not instance: return self.paused @@ -156,6 +159,9 @@ class ToggleSuspend(tables.BatchAction): classes = ("btn-suspend",) def allowed(self, request, instance=None): + if not api.nova.extension_supported('AdminActions', + request): + return False self.suspended = False if not instance: self.suspended diff --git a/openstack_dashboard/dashboards/project/instances/tests.py b/openstack_dashboard/dashboards/project/instances/tests.py index 5e0c045e02..0e51d94a1c 100644 --- a/openstack_dashboard/dashboards/project/instances/tests.py +++ b/openstack_dashboard/dashboards/project/instances/tests.py @@ -49,8 +49,12 @@ INDEX_URL = reverse('horizon:project:instances:index') class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'tenant_absolute_limits')}) + 'tenant_absolute_limits', + 'extension_supported',)}) def test_index(self): + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -61,8 +65,7 @@ class InstanceTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get( - reverse('horizon:project:instances:index')) + res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'project/instances/index.html') @@ -71,7 +74,7 @@ class InstanceTests(test.TestCase): self.assertItemsEqual(instances, self.servers.list()) @test.create_stubs({api.nova: ('server_list', - 'tenant_absolute_limits')}) + 'tenant_absolute_limits',)}) def test_index_server_list_exception(self): search_opts = {'marker': None, 'paginate': True} api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ @@ -81,7 +84,7 @@ class InstanceTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get(reverse('horizon:project:instances:index')) + res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'project/instances/index.html') self.assertEqual(len(res.context['instances_table'].data), 0) @@ -90,12 +93,16 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('flavor_list', 'server_list', 'flavor_get', - 'tenant_absolute_limits')}) + 'tenant_absolute_limits', + 'extension_supported',)}) def test_index_flavor_list_exception(self): servers = self.servers.list() flavors = self.flavors.list() full_flavors = SortedDict([(f.id, f) for f in flavors]) search_opts = {'marker': None, 'paginate': True} + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.server_list(IsA(http.HttpRequest), search_opts=search_opts) \ .AndReturn([servers, False]) api.nova.flavor_list(IsA(http.HttpRequest)) \ @@ -108,7 +115,7 @@ class InstanceTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get(reverse('horizon:project:instances:index')) + res = self.client.get(INDEX_URL) self.assertTemplateUsed(res, 'project/instances/index.html') instances = res.context['instances_table'].data @@ -118,10 +125,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('flavor_list', 'server_list', 'flavor_get', - 'tenant_absolute_limits')}) + 'tenant_absolute_limits', + 'extension_supported',)}) def test_index_flavor_get_exception(self): servers = self.servers.list() flavors = self.flavors.list() + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) # UUIDs generated using indexes are unlikely to match # any of existing flavor ids and are guaranteed to be deterministic. for i, server in enumerate(servers): @@ -139,7 +150,7 @@ class InstanceTests(test.TestCase): self.mox.ReplayAll() - res = self.client.get(reverse('horizon:project:instances:index')) + res = self.client.get(INDEX_URL) instances = res.context['instances_table'].data @@ -188,10 +199,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_pause', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_pause_instance(self): server = self.servers.first() + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -208,10 +223,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_pause', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_pause_instance_exception(self): server = self.servers.first() + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -229,11 +248,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_unpause', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_unpause_instance(self): server = self.servers.first() server.status = "PAUSED" - + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -250,11 +272,15 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_unpause', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_unpause_instance_exception(self): server = self.servers.first() server.status = "PAUSED" + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -275,7 +301,6 @@ class InstanceTests(test.TestCase): 'flavor_list',)}) def test_reboot_instance(self): server = self.servers.first() - api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -336,10 +361,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_suspend', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_suspend_instance(self): server = self.servers.first() + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -356,10 +385,14 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_suspend', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_suspend_instance_exception(self): server = self.servers.first() + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -377,11 +410,15 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_resume', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_resume_instance(self): server = self.servers.first() server.status = "SUSPENDED" + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -398,11 +435,15 @@ class InstanceTests(test.TestCase): @test.create_stubs({api.nova: ('server_resume', 'server_list', - 'flavor_list',)}) + 'flavor_list', + 'extension_supported',)}) def test_resume_instance_exception(self): server = self.servers.first() server.status = "SUSPENDED" + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -1429,11 +1470,15 @@ class InstanceTests(test.TestCase): self.assertContains(res, "greater than or equal to 1") @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'tenant_absolute_limits',)}) + 'tenant_absolute_limits', + 'extension_supported',)}) def test_launch_button_disabled_when_quota_exceeded(self): limits = self.limits['absolute'] limits['totalInstancesUsed'] = limits['maxTotalInstances'] + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True} @@ -1458,11 +1503,14 @@ class InstanceTests(test.TestCase): msg_prefix="The launch button is not disabled") @test.create_stubs({api.nova: ('flavor_list', 'server_list', - 'tenant_absolute_limits')}) + 'tenant_absolute_limits', + 'extension_supported',)}) def test_index_options_after_migrate(self): server = self.servers.first() server.status = "VERIFY_RESIZE" - + api.nova.extension_supported('AdminActions', + IsA(http.HttpRequest)) \ + .MultipleTimes().AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) search_opts = {'marker': None, 'paginate': True}