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]: