diff --git a/horizon/templates/horizon/common/_quota_summary.html b/horizon/templates/horizon/common/_quota_summary.html index 092bdd3725..c0a9ce32d7 100644 --- a/horizon/templates/horizon/common/_quota_summary.html +++ b/horizon/templates/horizon/common/_quota_summary.html @@ -10,4 +10,12 @@ {% trans "Used" %} {{ usage.quotas.ram.used|intcomma }} MB {% trans "of" %} {{ usage.quotas.ram.quota|intcomma }} MB {% trans "Available RAM" %} {% horizon_progress_bar usage.quotas.ram.used usage.quotas.ram.quota %} + + {% if usage.quotas.volumes %} + {% trans "Used" %} {{ usage.quotas.volumes.used|intcomma }} {% trans "of" %} {{ usage.quotas.volumes.quota|intcomma }} {% trans "Available volumes" %} + {% horizon_progress_bar usage.quotas.volumes.used usage.quotas.volumes.quota %} + + {% trans "Used" %} {{ usage.quotas.gigabytes.used|intcomma }} GB {% trans "of" %} {{ usage.quotas.gigabytes.quota|intcomma }} GB {% trans "Available volume storage" %} + {% horizon_progress_bar usage.quotas.gigabytes.used usage.quotas.gigabytes.quota %} + {% endif %} diff --git a/openstack_dashboard/test/tests/quotas.py b/openstack_dashboard/test/tests/quotas.py index 8590eaecc8..fb87c10116 100644 --- a/openstack_dashboard/test/tests/quotas.py +++ b/openstack_dashboard/test/tests/quotas.py @@ -35,8 +35,11 @@ class QuotaTests(test.APITestCase): 'flavor_list', 'tenant_floating_ip_list', 'tenant_quota_get',), + quotas: ('is_service_enabled',), cinder: ('volume_list', 'tenant_quota_get',)}) def test_tenant_quota_usages(self): + quotas.is_service_enabled(IsA(http.HttpRequest), + 'volume').AndReturn(True) api.nova.flavor_list(IsA(http.HttpRequest)) \ .AndReturn(self.flavors.list()) api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ @@ -67,3 +70,36 @@ class QuotaTests(test.APITestCase): # Compare internal structure of usages to expected. self.assertEquals(quota_usages.usages, expected_output) + + @test.create_stubs({api.nova: ('server_list', + 'flavor_list', + 'tenant_floating_ip_list', + 'tenant_quota_get',), + quotas: ('is_service_enabled',)}) + def test_tenant_quota_usages_without_volume(self): + quotas.is_service_enabled(IsA(http.HttpRequest), + 'volume').AndReturn(False) + api.nova.flavor_list(IsA(http.HttpRequest)) \ + .AndReturn(self.flavors.list()) + api.nova.tenant_quota_get(IsA(http.HttpRequest), '1') \ + .AndReturn(self.quotas.first()) + api.nova.tenant_floating_ip_list(IsA(http.HttpRequest)) \ + .AndReturn(self.floating_ips.list()) + api.nova.server_list(IsA(http.HttpRequest)) \ + .AndReturn(self.servers.list()) + + self.mox.ReplayAll() + + quota_usages = quotas.tenant_quota_usages(self.request) + expected_output = { + 'injected_file_content_bytes': {'quota': 1}, + 'metadata_items': {'quota': 1}, + 'injected_files': {'quota': 1}, + 'ram': {'available': 8976, 'used': 1024, 'quota': 10000}, + 'floating_ips': {'available': 0, 'used': 2, 'quota': 1}, + 'instances': {'available': 8, 'used': 2, 'quota': 10}, + 'cores': {'available': 8, 'used': 2, 'quota': 10} + } + + # Compare internal structure of usages to expected. + self.assertEquals(quota_usages.usages, expected_output) diff --git a/openstack_dashboard/usage/quotas.py b/openstack_dashboard/usage/quotas.py index 2e617d76fc..9550026793 100644 --- a/openstack_dashboard/usage/quotas.py +++ b/openstack_dashboard/usage/quotas.py @@ -52,37 +52,41 @@ class QuotaUsage(dict): self.usages[name]['available'] = available -def get_quota_data(request, method_name): +def _get_quota_data(request, method_name, disabled_quotas=[]): quotasets = [] tenant_id = request.user.tenant_id quotasets.append(getattr(nova, method_name)(request, tenant_id)) - if is_service_enabled(request, 'volume'): - quotasets.append(getattr(cinder, method_name)(request, tenant_id)) qs = QuotaSet() + if 'volumes' not in disabled_quotas: + quotasets.append(getattr(cinder, method_name)(request, tenant_id)) for quota in itertools.chain(*quotasets): - qs[quota.name] = quota.limit + if quota.name not in disabled_quotas: + qs[quota.name] = quota.limit return qs -def get_default_quota_data(request): - return get_quota_data(request, "default_quota_get") +def get_default_quota_data(request, disabled_quotas=[]): + return _get_quota_data(request, "default_quota_get", disabled_quotas) -def get_tenant_quota_data(request): - return get_quota_data(request, "tenant_quota_get") +def get_tenant_quota_data(request, disabled_quotas=[]): + return _get_quota_data(request, "tenant_quota_get", disabled_quotas) @memoized def tenant_quota_usages(request): # Get our quotas and construct our usage object. + disabled_quotas = [] + if not is_service_enabled(request, 'volume'): + disabled_quotas.extend(['volumes', 'gigabytes']) + usages = QuotaUsage() - for quota in get_tenant_quota_data(request): + for quota in get_tenant_quota_data(request, disabled_quotas): usages.add_quota(quota) # Get our usages. floating_ips = nova.tenant_floating_ip_list(request) flavors = dict([(f.id, f) for f in nova.flavor_list(request)]) - volumes = cinder.volume_list(request) instances = nova.server_list(request) # Fetch deleted flavors if necessary. missing_flavors = [instance.flavor['id'] for instance in instances @@ -97,8 +101,11 @@ def tenant_quota_usages(request): usages.tally('instances', len(instances)) usages.tally('floating_ips', len(floating_ips)) - usages.tally('volumes', len(volumes)) - usages.tally('gigabytes', sum([int(v.size) for v in volumes])) + + if 'volumes' not in disabled_quotas: + volumes = cinder.volume_list(request) + usages.tally('gigabytes', sum([int(v.size) for v in volumes])) + usages.tally('volumes', len(volumes)) # Sum our usage based on the flavors of the instances. for flavor in [flavors[instance.flavor['id']] for instance in instances]: