summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-05-29 07:11:43 +0000
committerGerrit Code Review <review@openstack.org>2013-05-29 07:11:43 +0000
commit144fda877fb1a757626fe074f0f80d7ee7e44e34 (patch)
tree0055928b6f8d729ae1739e2473be84d79766f29b
parent1a6ca7bfc65e86e48cb0422310f36baee6a695b3 (diff)
parentea1edcb027fea9d609326847be3cafb380534a56 (diff)
Merge "Enable snapshot quota setting"2013.2.b1
-rw-r--r--horizon/templates/horizon/common/_quota_summary.html6
-rw-r--r--openstack_dashboard/dashboards/admin/info/tests.py3
-rw-r--r--openstack_dashboard/dashboards/admin/projects/tests.py10
-rw-r--r--openstack_dashboard/dashboards/admin/projects/workflows.py1
-rw-r--r--openstack_dashboard/dashboards/project/images_and_snapshots/volume_snapshots/tests.py7
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/_create.html34
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/_create_snapshot.html17
-rw-r--r--openstack_dashboard/dashboards/project/volumes/templates/volumes/_quota.html43
-rw-r--r--openstack_dashboard/dashboards/project/volumes/views.py4
-rw-r--r--openstack_dashboard/test/test_data/cinder_data.py45
-rw-r--r--openstack_dashboard/test/test_data/utils.py2
-rw-r--r--openstack_dashboard/test/tests/quotas.py16
-rw-r--r--openstack_dashboard/usage/quotas.py3
13 files changed, 143 insertions, 48 deletions
diff --git a/horizon/templates/horizon/common/_quota_summary.html b/horizon/templates/horizon/common/_quota_summary.html
index 7ebbbc5..026af42 100644
--- a/horizon/templates/horizon/common/_quota_summary.html
+++ b/horizon/templates/horizon/common/_quota_summary.html
@@ -31,6 +31,12 @@
31 </strong> 31 </strong>
32 </div> 32 </div>
33 <div class="d3_quota_bar"> 33 <div class="d3_quota_bar">
34 <div class="d3_pie_chart" data-used="{% widthratio usage.quotas.snapshots.used usage.quotas.snapshots.quota 100 %}"></div>
35 <strong>{% trans "Available Snapshots" %} <br />
36 {% blocktrans with used=usage.quotas.snapshots.used|intcomma available=usage.quotas.snapshots.quota|intcomma %} Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
37 </strong>
38 </div>
39 <div class="d3_quota_bar">
34 <div class="d3_pie_chart" data-used="{% widthratio usage.quotas.gigabytes.used usage.quotas.gigabytes.quota 100 %}"></div> 40 <div class="d3_pie_chart" data-used="{% widthratio usage.quotas.gigabytes.used usage.quotas.gigabytes.quota 100 %}"></div>
35 <strong>{% trans "Available Volume Storage" %} <br /> 41 <strong>{% trans "Available Volume Storage" %} <br />
36 {% blocktrans with used=usage.quotas.gigabytes.used|intcomma available=usage.quotas.gigabytes.quota|intcomma%}Used <span> {{ used }} GB </span> of <span> {{ available }} GB</span>{% endblocktrans %} 42 {% blocktrans with used=usage.quotas.gigabytes.used|intcomma available=usage.quotas.gigabytes.quota|intcomma%}Used <span> {{ used }} GB </span> of <span> {{ available }} GB</span>{% endblocktrans %}
diff --git a/openstack_dashboard/dashboards/admin/info/tests.py b/openstack_dashboard/dashboards/admin/info/tests.py
index ae974d2..6180bb5 100644
--- a/openstack_dashboard/dashboards/admin/info/tests.py
+++ b/openstack_dashboard/dashboards/admin/info/tests.py
@@ -31,7 +31,7 @@ class ServicesViewTests(test.BaseAdminViewTests):
31 api.nova.default_quota_get(IsA(http.HttpRequest), 31 api.nova.default_quota_get(IsA(http.HttpRequest),
32 self.tenant.id).AndReturn(self.quotas.nova) 32 self.tenant.id).AndReturn(self.quotas.nova)
33 api.cinder.default_quota_get(IsA(http.HttpRequest), self.tenant.id) \ 33 api.cinder.default_quota_get(IsA(http.HttpRequest), self.tenant.id) \
34 .AndReturn(self.quotas.nova) 34 .AndReturn(self.cinder_quotas.first())
35 35
36 self.mox.ReplayAll() 36 self.mox.ReplayAll()
37 37
@@ -60,6 +60,7 @@ class ServicesViewTests(test.BaseAdminViewTests):
60 '<Quota: (floating_ips, 1)>', 60 '<Quota: (floating_ips, 1)>',
61 '<Quota: (fixed_ips, 10)>', 61 '<Quota: (fixed_ips, 10)>',
62 '<Quota: (instances, 10)>', 62 '<Quota: (instances, 10)>',
63 '<Quota: (snapshots, 1)>',
63 '<Quota: (volumes, 1)>', 64 '<Quota: (volumes, 1)>',
64 '<Quota: (cores, 10)>', 65 '<Quota: (cores, 10)>',
65 '<Quota: (security_groups, 10)>', 66 '<Quota: (security_groups, 10)>',
diff --git a/openstack_dashboard/dashboards/admin/projects/tests.py b/openstack_dashboard/dashboards/admin/projects/tests.py
index a8ec8ca..5baf03d 100644
--- a/openstack_dashboard/dashboards/admin/projects/tests.py
+++ b/openstack_dashboard/dashboards/admin/projects/tests.py
@@ -58,9 +58,12 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
58 return project_info 58 return project_info
59 59
60 def _get_quota_info(self, quota): 60 def _get_quota_info(self, quota):
61 cinder_quota = self.cinder_quotas.first()
61 quota_data = {} 62 quota_data = {}
62 for field in quotas.QUOTA_FIELDS: 63 for field in quotas.NOVA_QUOTA_FIELDS:
63 quota_data[field] = int(quota.get(field).limit) 64 quota_data[field] = int(quota.get(field).limit)
65 for field in quotas.CINDER_QUOTA_FIELDS:
66 quota_data[field] = int(cinder_quota.get(field).limit)
64 return quota_data 67 return quota_data
65 68
66 def _get_workflow_data(self, project, quota): 69 def _get_workflow_data(self, project, quota):
@@ -403,9 +406,12 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
403 406
404class UpdateProjectWorkflowTests(test.BaseAdminViewTests): 407class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
405 def _get_quota_info(self, quota): 408 def _get_quota_info(self, quota):
409 cinder_quota = self.cinder_quotas.first()
406 quota_data = {} 410 quota_data = {}
407 for field in quotas.QUOTA_FIELDS: 411 for field in quotas.NOVA_QUOTA_FIELDS:
408 quota_data[field] = int(quota.get(field).limit) 412 quota_data[field] = int(quota.get(field).limit)
413 for field in quotas.CINDER_QUOTA_FIELDS:
414 quota_data[field] = int(cinder_quota.get(field).limit)
409 return quota_data 415 return quota_data
410 416
411 @test.create_stubs({api.keystone: ('get_default_role', 417 @test.create_stubs({api.keystone: ('get_default_role',
diff --git a/openstack_dashboard/dashboards/admin/projects/workflows.py b/openstack_dashboard/dashboards/admin/projects/workflows.py
index 2337da5..b9b3981 100644
--- a/openstack_dashboard/dashboards/admin/projects/workflows.py
+++ b/openstack_dashboard/dashboards/admin/projects/workflows.py
@@ -51,6 +51,7 @@ class UpdateProjectQuotaAction(workflows.Action):
51 injected_file_content_bytes = forms.IntegerField(min_value=-1, 51 injected_file_content_bytes = forms.IntegerField(min_value=-1,
52 label=ifcb_label) 52 label=ifcb_label)
53 volumes = forms.IntegerField(min_value=-1, label=_("Volumes")) 53 volumes = forms.IntegerField(min_value=-1, label=_("Volumes"))
54 snapshots = forms.IntegerField(min_value=-1, label=_("Snapshots"))
54 gigabytes = forms.IntegerField(min_value=-1, label=_("Gigabytes")) 55 gigabytes = forms.IntegerField(min_value=-1, label=_("Gigabytes"))
55 ram = forms.IntegerField(min_value=-1, label=_("RAM (MB)")) 56 ram = forms.IntegerField(min_value=-1, label=_("RAM (MB)"))
56 floating_ips = forms.IntegerField(min_value=-1, label=_("Floating IPs")) 57 floating_ips = forms.IntegerField(min_value=-1, label=_("Floating IPs"))
diff --git a/openstack_dashboard/dashboards/project/images_and_snapshots/volume_snapshots/tests.py b/openstack_dashboard/dashboards/project/images_and_snapshots/volume_snapshots/tests.py
index 27800b4..16e4d4e 100644
--- a/openstack_dashboard/dashboards/project/images_and_snapshots/volume_snapshots/tests.py
+++ b/openstack_dashboard/dashboards/project/images_and_snapshots/volume_snapshots/tests.py
@@ -25,14 +25,21 @@ from mox import IsA
25from openstack_dashboard import api 25from openstack_dashboard import api
26from openstack_dashboard.api import cinder 26from openstack_dashboard.api import cinder
27from openstack_dashboard.test import helpers as test 27from openstack_dashboard.test import helpers as test
28from openstack_dashboard.usage import quotas
28 29
29 30
30INDEX_URL = reverse('horizon:project:images_and_snapshots:index') 31INDEX_URL = reverse('horizon:project:images_and_snapshots:index')
31 32
32 33
33class VolumeSnapshotsViewTests(test.TestCase): 34class VolumeSnapshotsViewTests(test.TestCase):
35 @test.create_stubs({quotas: ('tenant_quota_usages',)})
34 def test_create_snapshot_get(self): 36 def test_create_snapshot_get(self):
35 volume = self.volumes.first() 37 volume = self.volumes.first()
38 usage = {'gigabytes': {'available': 250},
39 'snapshots': {'available': 6}}
40 quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage)
41 self.mox.ReplayAll()
42
36 url = reverse('horizon:project:volumes:create_snapshot', 43 url = reverse('horizon:project:volumes:create_snapshot',
37 args=[volume.id]) 44 args=[volume.id])
38 res = self.client.get(url) 45 res = self.client.get(url)
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create.html
index fc64394..b4670e6 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create.html
@@ -1,5 +1,5 @@
1{% extends "horizon/common/_modal_form.html" %} 1{% extends "horizon/common/_modal_form.html" %}
2{% load i18n horizon humanize %} 2{% load i18n %}
3{% load url from future %} 3{% load url from future %}
4 4
5{% block form_id %}{% endblock %} 5{% block form_id %}{% endblock %}
@@ -16,38 +16,8 @@
16 </div> 16 </div>
17 17
18 <div class="right quota-dynamic"> 18 <div class="right quota-dynamic">
19 <h3>{% trans "Description" %}:</h3> 19 {% include "project/volumes/_quota.html" with usages=usages %}
20
21 <p>{% trans "Volumes are block devices that can be attached to instances." %}</p>
22
23 <h3>{% trans "Volume Quotas" %}</h3>
24
25 <div class="quota_title clearfix">
26 <strong>{% trans "Total Gigabytes" %} <span>({{ usages.gigabytes.used|intcomma }} {% trans "GB" %})</span></strong>
27 <p>{{ usages.gigabytes.available|quota:_("GB")|intcomma }}</p>
28 </div>
29
30 <div id="quota_size" data-progress-indicator-for="id_size" data-quota-limit="{{ usages.gigabytes.quota }}" data-quota-used="{{ usages.gigabytes.used }}" class="quota_bar">
31 </div>
32
33 <div class="quota_title clearfix">
34 <strong>{% trans "Number of Volumes" %} <span>({{ usages.volumes.used|intcomma }})</span></strong>
35 <p>{{ usages.volumes.available|quota|intcomma }}</p>
36 </div>
37
38 <div id="quota_volumes" data-progress-indicator-step-by="1" data-quota-limit="{{ usages.volumes.quota }}" data-quota-used="{{ usages.volumes.used }}" class="quota_bar">
39 </div>
40 </div> 20 </div>
41
42 <script type="text/javascript" charset="utf-8">
43 if(typeof horizon.Quota !== 'undefined') {
44 horizon.Quota.init();
45 } else {
46 addHorizonLoadEvent(function() {
47 horizon.Quota.init();
48 });
49 }
50 </script>
51{% endblock %} 21{% endblock %}
52 22
53{% block modal-footer %} 23{% block modal-footer %}
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create_snapshot.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create_snapshot.html
index 446a0d0..97c97bf 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create_snapshot.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_create_snapshot.html
@@ -9,15 +9,14 @@
9{% block modal-header %}{% trans "Create Volume Snapshot" %}{% endblock %} 9{% block modal-header %}{% trans "Create Volume Snapshot" %}{% endblock %}
10 10
11{% block modal-body %} 11{% block modal-body %}
12<div class="left"> 12 <div class="left">
13 <fieldset> 13 <fieldset>
14 {% include "horizon/common/_form_fields.html" %} 14 {% include "horizon/common/_form_fields.html" %}
15 </fieldset> 15 </fieldset>
16</div> 16 </div>
17<div class="right"> 17 <div class="right quota-dynamic">
18 <h3>{% trans "Description" %}:</h3> 18 {% include "project/volumes/_quota.html" with usages=usages snapshot_quota=True %}
19 <p>{% trans "Volumes are block devices that can be attached to instances." %}</p> 19 </div>
20</div>
21{% endblock %} 20{% endblock %}
22 21
23{% block modal-footer %} 22{% block modal-footer %}
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/_quota.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_quota.html
new file mode 100644
index 0000000..f145385
--- /dev/null
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_quota.html
@@ -0,0 +1,43 @@
1{% load i18n horizon humanize %}
2
3<h3>{% trans "Description" %}:</h3>
4
5<p>{% trans "Volumes are block devices that can be attached to instances." %}</p>
6
7<h3>{% trans "Volume Quotas" %}</h3>
8
9<div class="quota_title clearfix">
10 <strong>{% trans "Total Gigabytes" %} <span>({{ usages.gigabytes.used|intcomma }} {% trans "GB" %})</span></strong>
11 <p>{{ usages.gigabytes.available|quota:_("GB")|intcomma }}</p>
12</div>
13
14<div id="quota_size" data-progress-indicator-for="id_size" data-quota-limit="{{ usages.gigabytes.quota }}" data-quota-used="{{ usages.gigabytes.used }}" class="quota_bar">
15</div>
16
17{% if snapshot_quota %}
18 <div class="quota_title clearfix">
19 <strong>{% trans "Number of Snapshots" %} <span>({{ usages.snapshots.used|intcomma }})</span></strong>
20 <p>{{ usages.snapshots.available|quota|intcomma }}</p>
21 </div>
22
23 <div id="quota_snapshots" data-progress-indicator-step-by="1" data-quota-limit="{{ usages.snapshots.quota }}" data-quota-used="{{ usages.snapshots.used }}" class="quota_bar">
24 </div>
25{% else %}
26 <div class="quota_title clearfix">
27 <strong>{% trans "Number of Volumes" %} <span>({{ usages.volumes.used|intcomma }})</span></strong>
28 <p>{{ usages.volumes.available|quota|intcomma }}</p>
29 </div>
30
31 <div id="quota_volumes" data-progress-indicator-step-by="1" data-quota-limit="{{ usages.volumes.quota }}" data-quota-used="{{ usages.volumes.used }}" class="quota_bar">
32 </div>
33{% endif %}
34
35<script type="text/javascript" charset="utf-8">
36 if(typeof horizon.Quota !== 'undefined') {
37 horizon.Quota.init();
38 } else {
39 addHorizonLoadEvent(function() {
40 horizon.Quota.init();
41 });
42 }
43</script>
diff --git a/openstack_dashboard/dashboards/project/volumes/views.py b/openstack_dashboard/dashboards/project/volumes/views.py
index fedaeea..c423488 100644
--- a/openstack_dashboard/dashboards/project/volumes/views.py
+++ b/openstack_dashboard/dashboards/project/volumes/views.py
@@ -113,6 +113,10 @@ class CreateSnapshotView(forms.ModalFormView):
113 def get_context_data(self, **kwargs): 113 def get_context_data(self, **kwargs):
114 context = super(CreateSnapshotView, self).get_context_data(**kwargs) 114 context = super(CreateSnapshotView, self).get_context_data(**kwargs)
115 context['volume_id'] = self.kwargs['volume_id'] 115 context['volume_id'] = self.kwargs['volume_id']
116 try:
117 context['usages'] = quotas.tenant_quota_usages(self.request)
118 except:
119 exceptions.handle(self.request)
116 return context 120 return context
117 121
118 def get_initial(self): 122 def get_initial(self):
diff --git a/openstack_dashboard/test/test_data/cinder_data.py b/openstack_dashboard/test/test_data/cinder_data.py
new file mode 100644
index 0000000..7ae08cb
--- /dev/null
+++ b/openstack_dashboard/test/test_data/cinder_data.py
@@ -0,0 +1,45 @@
1# Copyright 2012 Nebula, Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License"); you may
4# not use this file except in compliance with the License. You may obtain
5# a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12# License for the specific language governing permissions and limitations
13# under the License.
14
15from cinderclient.v1 import quotas
16from openstack_dashboard.api.base import Quota, QuotaSet as QuotaSetWrapper
17from openstack_dashboard.usage.quotas import QuotaUsage
18from .utils import TestDataContainer
19
20
21def data(TEST):
22 TEST.cinder_quotas = TestDataContainer()
23 TEST.cinder_quota_usages = TestDataContainer()
24
25 # Quota Sets
26 quota_data = dict(volumes='1',
27 snapshots='1',
28 gigabytes='1000')
29 quota = quotas.QuotaSet(quotas.QuotaSetManager(None), quota_data)
30 #TEST.quotas.cinder = QuotaSetWrapper(quota)
31 TEST.cinder_quotas.add(QuotaSetWrapper(quota))
32
33 # Quota Usages
34 quota_usage_data = {'gigabytes': {'used': 0,
35 'quota': 1000},
36 'instances': {'used': 0,
37 'quota': 10},
38 'snapshots': {'used': 0,
39 'quota': 10}}
40 quota_usage = QuotaUsage()
41 for k, v in quota_usage_data.items():
42 quota_usage.add_quota(Quota(k, v['quota']))
43 quota_usage.tally(k, v['used'])
44
45 TEST.cinder_quota_usages.add(quota_usage)
diff --git a/openstack_dashboard/test/test_data/utils.py b/openstack_dashboard/test/test_data/utils.py
index 1a080aa..ac73408 100644
--- a/openstack_dashboard/test/test_data/utils.py
+++ b/openstack_dashboard/test/test_data/utils.py
@@ -18,6 +18,7 @@ def load_test_data(load_onto=None):
18 from . import glance_data 18 from . import glance_data
19 from . import keystone_data 19 from . import keystone_data
20 from . import nova_data 20 from . import nova_data
21 from . import cinder_data
21 from . import quantum_data 22 from . import quantum_data
22 from . import swift_data 23 from . import swift_data
23 from . import heat_data 24 from . import heat_data
@@ -27,6 +28,7 @@ def load_test_data(load_onto=None):
27 keystone_data.data, 28 keystone_data.data,
28 glance_data.data, 29 glance_data.data,
29 nova_data.data, 30 nova_data.data,
31 cinder_data.data,
30 quantum_data.data, 32 quantum_data.data,
31 swift_data.data, 33 swift_data.data,
32 heat_data.data) 34 heat_data.data)
diff --git a/openstack_dashboard/test/tests/quotas.py b/openstack_dashboard/test/tests/quotas.py
index 1c65f40..29061a5 100644
--- a/openstack_dashboard/test/tests/quotas.py
+++ b/openstack_dashboard/test/tests/quotas.py
@@ -45,6 +45,8 @@ class QuotaTests(test.APITestCase):
45 'cores': {'available': 8, 'used': 2, 'quota': 10}} 45 'cores': {'available': 8, 'used': 2, 'quota': 10}}
46 if with_volume: 46 if with_volume:
47 quotas.update({'volumes': {'available': 0, 'used': 3, 'quota': 1}, 47 quotas.update({'volumes': {'available': 0, 'used': 3, 'quota': 1},
48 'snapshots': {'available': 0, 'used': 3,
49 'quota': 1},
48 'gigabytes': {'available': 920, 'used': 80, 50 'gigabytes': {'available': 920, 'used': 80,
49 'quota': 1000}}) 51 'quota': 1000}})
50 return quotas 52 return quotas
@@ -54,7 +56,8 @@ class QuotaTests(test.APITestCase):
54 'tenant_quota_get',), 56 'tenant_quota_get',),
55 api.network: ('tenant_floating_ip_list',), 57 api.network: ('tenant_floating_ip_list',),
56 quotas: ('is_service_enabled',), 58 quotas: ('is_service_enabled',),
57 cinder: ('volume_list', 'tenant_quota_get',)}) 59 cinder: ('volume_list', 'volume_snapshot_list',
60 'tenant_quota_get',)})
58 def test_tenant_quota_usages(self): 61 def test_tenant_quota_usages(self):
59 quotas.is_service_enabled(IsA(http.HttpRequest), 62 quotas.is_service_enabled(IsA(http.HttpRequest),
60 'volume').AndReturn(True) 63 'volume').AndReturn(True)
@@ -68,8 +71,10 @@ class QuotaTests(test.APITestCase):
68 .AndReturn([self.servers.list(), False]) 71 .AndReturn([self.servers.list(), False])
69 cinder.volume_list(IsA(http.HttpRequest)) \ 72 cinder.volume_list(IsA(http.HttpRequest)) \
70 .AndReturn(self.volumes.list()) 73 .AndReturn(self.volumes.list())
74 cinder.volume_snapshot_list(IsA(http.HttpRequest)) \
75 .AndReturn(self.snapshots.list())
71 cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \ 76 cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \
72 .AndReturn(self.quotas.first()) 77 .AndReturn(self.cinder_quotas.first())
73 78
74 self.mox.ReplayAll() 79 self.mox.ReplayAll()
75 80
@@ -139,7 +144,8 @@ class QuotaTests(test.APITestCase):
139 'tenant_quota_get',), 144 'tenant_quota_get',),
140 api.network: ('tenant_floating_ip_list',), 145 api.network: ('tenant_floating_ip_list',),
141 quotas: ('is_service_enabled',), 146 quotas: ('is_service_enabled',),
142 cinder: ('volume_list', 'tenant_quota_get',)}) 147 cinder: ('volume_list', 'volume_snapshot_list',
148 'tenant_quota_get',)})
143 def test_tenant_quota_usages_unlimited_quota(self): 149 def test_tenant_quota_usages_unlimited_quota(self):
144 inf_quota = self.quotas.first() 150 inf_quota = self.quotas.first()
145 inf_quota['ram'] = -1 151 inf_quota['ram'] = -1
@@ -156,8 +162,10 @@ class QuotaTests(test.APITestCase):
156 .AndReturn([self.servers.list(), False]) 162 .AndReturn([self.servers.list(), False])
157 cinder.volume_list(IsA(http.HttpRequest)) \ 163 cinder.volume_list(IsA(http.HttpRequest)) \
158 .AndReturn(self.volumes.list()) 164 .AndReturn(self.volumes.list())
165 cinder.volume_snapshot_list(IsA(http.HttpRequest)) \
166 .AndReturn(self.snapshots.list())
159 cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \ 167 cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \
160 .AndReturn(inf_quota) 168 .AndReturn(self.cinder_quotas.first())
161 169
162 self.mox.ReplayAll() 170 self.mox.ReplayAll()
163 171
diff --git a/openstack_dashboard/usage/quotas.py b/openstack_dashboard/usage/quotas.py
index 9924509..68ec9b3 100644
--- a/openstack_dashboard/usage/quotas.py
+++ b/openstack_dashboard/usage/quotas.py
@@ -19,6 +19,7 @@ NOVA_QUOTA_FIELDS = ("metadata_items",
19 "security_group_rules",) 19 "security_group_rules",)
20 20
21CINDER_QUOTA_FIELDS = ("volumes", 21CINDER_QUOTA_FIELDS = ("volumes",
22 "snapshots",
22 "gigabytes",) 23 "gigabytes",)
23 24
24QUOTA_FIELDS = NOVA_QUOTA_FIELDS + CINDER_QUOTA_FIELDS 25QUOTA_FIELDS = NOVA_QUOTA_FIELDS + CINDER_QUOTA_FIELDS
@@ -136,8 +137,10 @@ def tenant_quota_usages(request):
136 137
137 if 'volumes' not in disabled_quotas: 138 if 'volumes' not in disabled_quotas:
138 volumes = cinder.volume_list(request) 139 volumes = cinder.volume_list(request)
140 snapshots = cinder.volume_snapshot_list(request)
139 usages.tally('gigabytes', sum([int(v.size) for v in volumes])) 141 usages.tally('gigabytes', sum([int(v.size) for v in volumes]))
140 usages.tally('volumes', len(volumes)) 142 usages.tally('volumes', len(volumes))
143 usages.tally('snapshots', len(snapshots))
141 144
142 # Sum our usage based on the flavors of the instances. 145 # Sum our usage based on the flavors of the instances.
143 for flavor in [flavors[instance.flavor['id']] for instance in instances]: 146 for flavor in [flavors[instance.flavor['id']] for instance in instances]: