From 340bf16be00706235b66309f327611c1bca02f50 Mon Sep 17 00:00:00 2001 From: "Leandro I. Costantino" Date: Fri, 6 Dec 2013 10:52:24 -0500 Subject: [PATCH] CSV Summary not working inside Admin panel. When browsing Project usages from 'Admin->Projects->More->View Usages' an AttributeError exception is thrown due to missing csv_render_class attribute. Also, project_id instead of tenant_id in BaseUsage were expected, so any request to /admin/projects/[id]/usage/ will always return the current tenant from session. This fix reuse logic from project/overview/ into this view. Change-Id: I7d762569a7de176fdb8545a226e563afac34adae Closes-Bug: #1255667 --- .../dashboards/admin/projects/tests.py | 63 +++++++++++++++++++ .../dashboards/admin/projects/urls.py | 2 +- .../dashboards/admin/projects/views.py | 5 +- openstack_dashboard/usage/views.py | 4 +- 4 files changed, 71 insertions(+), 3 deletions(-) diff --git a/openstack_dashboard/dashboards/admin/projects/tests.py b/openstack_dashboard/dashboards/admin/projects/tests.py index 976d221bc5..961af2351c 100644 --- a/openstack_dashboard/dashboards/admin/projects/tests.py +++ b/openstack_dashboard/dashboards/admin/projects/tests.py @@ -15,11 +15,13 @@ # under the License. import copy +import datetime import logging from django.core.urlresolvers import reverse # noqa from django import http from django.test.utils import override_settings # noqa +from django.utils import timezone from mox import IgnoreArg # noqa from mox import IsA # noqa @@ -30,6 +32,7 @@ from horizon.workflows import views from openstack_dashboard import api from openstack_dashboard.dashboards.admin.projects import workflows from openstack_dashboard.test import helpers as test +from openstack_dashboard import usage from openstack_dashboard.usage import quotas from selenium.webdriver import ActionChains # noqa @@ -1446,6 +1449,66 @@ class UpdateProjectWorkflowTests(test.BaseAdminViewTests): logging.disable(logging.NOTSET) +class UsageViewTests(test.BaseAdminViewTests): + def _stub_nova_api_calls(self, nova_stu_enabled=True): + self.mox.StubOutWithMock(api.nova, 'usage_get') + self.mox.StubOutWithMock(api.nova, 'tenant_absolute_limits') + self.mox.StubOutWithMock(api.nova, 'extension_supported') + api.nova.extension_supported( + 'SimpleTenantUsage', IsA(http.HttpRequest)) \ + .AndReturn(nova_stu_enabled) + + def _stub_neutron_api_calls(self, neutron_sg_enabled=True): + self.mox.StubOutWithMock(api.neutron, 'is_extension_supported') + self.mox.StubOutWithMock(api.network, 'tenant_floating_ip_list') + if neutron_sg_enabled: + self.mox.StubOutWithMock(api.network, 'security_group_list') + api.neutron.is_extension_supported( + IsA(http.HttpRequest), + 'security-group').AndReturn(neutron_sg_enabled) + api.network.tenant_floating_ip_list(IsA(http.HttpRequest)) \ + .AndReturn(self.floating_ips.list()) + if neutron_sg_enabled: + api.network.security_group_list(IsA(http.HttpRequest)) \ + .AndReturn(self.q_secgroups.list()) + + def test_usage_csv(self): + self._test_usage_csv(nova_stu_enabled=True) + + def test_usage_csv_disabled(self): + self._test_usage_csv(nova_stu_enabled=False) + + def _test_usage_csv(self, nova_stu_enabled=True): + now = timezone.now() + usage_obj = api.nova.NovaUsage(self.usages.first()) + self._stub_nova_api_calls(nova_stu_enabled) + api.nova.extension_supported( + 'SimpleTenantUsage', IsA(http.HttpRequest)) \ + .AndReturn(nova_stu_enabled) + start = datetime.datetime(now.year, now.month, now.day, 0, 0, 0, 0) + end = datetime.datetime(now.year, now.month, now.day, 23, 59, 59, 0) + + if nova_stu_enabled: + api.nova.usage_get(IsA(http.HttpRequest), + self.tenant.id, + start, end).AndReturn(usage_obj) + api.nova.tenant_absolute_limits(IsA(http.HttpRequest))\ + .AndReturn(self.limits['absolute']) + self._stub_neutron_api_calls() + self.mox.ReplayAll() + + project_id = self.tenants.first().id + csv_url = reverse('horizon:admin:projects:usage', + args=[project_id]) + "?format=csv" + res = self.client.get(csv_url) + self.assertTemplateUsed(res, 'project/overview/usage.csv') + + self.assertTrue(isinstance(res.context['usage'], usage.ProjectUsage)) + hdr = ('Instance Name,VCPUs,Ram (MB),Disk (GB),Usage (Hours),' + 'Uptime(Seconds),State') + self.assertContains(res, '%s\r\n' % hdr) + + class SeleniumTests(test.SeleniumAdminTestCase): @test.create_stubs( {api.keystone: ('tenant_list', 'tenant_get', 'tenant_update')}) diff --git a/openstack_dashboard/dashboards/admin/projects/urls.py b/openstack_dashboard/dashboards/admin/projects/urls.py index ea89f24f0f..c283a443a8 100644 --- a/openstack_dashboard/dashboards/admin/projects/urls.py +++ b/openstack_dashboard/dashboards/admin/projects/urls.py @@ -29,6 +29,6 @@ urlpatterns = patterns('', url(r'^create$', views.CreateProjectView.as_view(), name='create'), url(r'^(?P[^/]+)/update/$', views.UpdateProjectView.as_view(), name='update'), - url(r'^(?P[^/]+)/usage/$', + url(r'^(?P[^/]+)/usage/$', views.ProjectUsageView.as_view(), name='usage'), ) diff --git a/openstack_dashboard/dashboards/admin/projects/views.py b/openstack_dashboard/dashboards/admin/projects/views.py index f9af86976f..5a45d42a97 100644 --- a/openstack_dashboard/dashboards/admin/projects/views.py +++ b/openstack_dashboard/dashboards/admin/projects/views.py @@ -34,7 +34,8 @@ from openstack_dashboard.dashboards.admin.projects \ import tables as project_tables from openstack_dashboard.dashboards.admin.projects \ import workflows as project_workflows - +from openstack_dashboard.dashboards.project.overview \ + import views as project_views PROJECT_INFO_FIELDS = ("domain_id", "domain_name", @@ -94,6 +95,8 @@ class ProjectUsageView(usage.UsageView): table_class = usage.ProjectUsageTable usage_class = usage.ProjectUsage template_name = 'admin/projects/usage.html' + csv_response_class = project_views.ProjectUsageCsvRenderer + csv_template_name = 'project/overview/usage.csv' def get_data(self): super(ProjectUsageView, self).get_data() diff --git a/openstack_dashboard/usage/views.py b/openstack_dashboard/usage/views.py index 40e566f108..6d04753a8c 100644 --- a/openstack_dashboard/usage/views.py +++ b/openstack_dashboard/usage/views.py @@ -18,6 +18,7 @@ from openstack_dashboard.usage import base class UsageView(tables.DataTableView): usage_class = None show_terminated = True + csv_template_name = None def __init__(self, *args, **kwargs): super(UsageView, self).__init__(*args, **kwargs) @@ -27,7 +28,8 @@ class UsageView(tables.DataTableView): def get_template_names(self): if self.request.GET.get('format', 'html') == 'csv': - return ".".join((self.template_name.rsplit('.', 1)[0], 'csv')) + return (self.csv_template_name or + ".".join((self.template_name.rsplit('.', 1)[0], 'csv'))) return self.template_name def get_content_type(self):