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)
downloadhorizon-2013.2.b1.tar.gz
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 7ebbbc51d..026af423f 100644
--- a/horizon/templates/horizon/common/_quota_summary.html
+++ b/horizon/templates/horizon/common/_quota_summary.html
@@ -31,6 +31,12 @@
</strong>
</div>
<div class="d3_quota_bar">
+ <div class="d3_pie_chart" data-used="{% widthratio usage.quotas.snapshots.used usage.quotas.snapshots.quota 100 %}"></div>
+ <strong>{% trans "Available Snapshots" %} <br />
+ {% blocktrans with used=usage.quotas.snapshots.used|intcomma available=usage.quotas.snapshots.quota|intcomma %} Used <span> {{ used }} </span> of <span> {{ available }} </span>{% endblocktrans %}
+ </strong>
+ </div>
+ <div class="d3_quota_bar">
<div class="d3_pie_chart" data-used="{% widthratio usage.quotas.gigabytes.used usage.quotas.gigabytes.quota 100 %}"></div>
<strong>{% trans "Available Volume Storage" %} <br />
{% 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 ae974d2c6..6180bb5a4 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):
api.nova.default_quota_get(IsA(http.HttpRequest),
self.tenant.id).AndReturn(self.quotas.nova)
api.cinder.default_quota_get(IsA(http.HttpRequest), self.tenant.id) \
- .AndReturn(self.quotas.nova)
+ .AndReturn(self.cinder_quotas.first())
self.mox.ReplayAll()
@@ -60,6 +60,7 @@ class ServicesViewTests(test.BaseAdminViewTests):
'<Quota: (floating_ips, 1)>',
'<Quota: (fixed_ips, 10)>',
'<Quota: (instances, 10)>',
+ '<Quota: (snapshots, 1)>',
'<Quota: (volumes, 1)>',
'<Quota: (cores, 10)>',
'<Quota: (security_groups, 10)>',
diff --git a/openstack_dashboard/dashboards/admin/projects/tests.py b/openstack_dashboard/dashboards/admin/projects/tests.py
index a8ec8cab1..5baf03d44 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):
return project_info
def _get_quota_info(self, quota):
+ cinder_quota = self.cinder_quotas.first()
quota_data = {}
- for field in quotas.QUOTA_FIELDS:
+ for field in quotas.NOVA_QUOTA_FIELDS:
quota_data[field] = int(quota.get(field).limit)
+ for field in quotas.CINDER_QUOTA_FIELDS:
+ quota_data[field] = int(cinder_quota.get(field).limit)
return quota_data
def _get_workflow_data(self, project, quota):
@@ -403,9 +406,12 @@ class CreateProjectWorkflowTests(test.BaseAdminViewTests):
class UpdateProjectWorkflowTests(test.BaseAdminViewTests):
def _get_quota_info(self, quota):
+ cinder_quota = self.cinder_quotas.first()
quota_data = {}
- for field in quotas.QUOTA_FIELDS:
+ for field in quotas.NOVA_QUOTA_FIELDS:
quota_data[field] = int(quota.get(field).limit)
+ for field in quotas.CINDER_QUOTA_FIELDS:
+ quota_data[field] = int(cinder_quota.get(field).limit)
return quota_data
@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 2337da57c..b9b39812c 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):
injected_file_content_bytes = forms.IntegerField(min_value=-1,
label=ifcb_label)
volumes = forms.IntegerField(min_value=-1, label=_("Volumes"))
+ snapshots = forms.IntegerField(min_value=-1, label=_("Snapshots"))
gigabytes = forms.IntegerField(min_value=-1, label=_("Gigabytes"))
ram = forms.IntegerField(min_value=-1, label=_("RAM (MB)"))
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 27800b43d..16e4d4e20 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
from openstack_dashboard import api
from openstack_dashboard.api import cinder
from openstack_dashboard.test import helpers as test
+from openstack_dashboard.usage import quotas
INDEX_URL = reverse('horizon:project:images_and_snapshots:index')
class VolumeSnapshotsViewTests(test.TestCase):
+ @test.create_stubs({quotas: ('tenant_quota_usages',)})
def test_create_snapshot_get(self):
volume = self.volumes.first()
+ usage = {'gigabytes': {'available': 250},
+ 'snapshots': {'available': 6}}
+ quotas.tenant_quota_usages(IsA(http.HttpRequest)).AndReturn(usage)
+ self.mox.ReplayAll()
+
url = reverse('horizon:project:volumes:create_snapshot',
args=[volume.id])
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 fc64394bd..b4670e6ba 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 @@
{% extends "horizon/common/_modal_form.html" %}
-{% load i18n horizon humanize %}
+{% load i18n %}
{% load url from future %}
{% block form_id %}{% endblock %}
@@ -16,38 +16,8 @@
</div>
<div class="right quota-dynamic">
- <h3>{% trans "Description" %}:</h3>
-
- <p>{% trans "Volumes are block devices that can be attached to instances." %}</p>
-
- <h3>{% trans "Volume Quotas" %}</h3>
-
- <div class="quota_title clearfix">
- <strong>{% trans "Total Gigabytes" %} <span>({{ usages.gigabytes.used|intcomma }} {% trans "GB" %})</span></strong>
- <p>{{ usages.gigabytes.available|quota:_("GB")|intcomma }}</p>
- </div>
-
- <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">
- </div>
-
- <div class="quota_title clearfix">
- <strong>{% trans "Number of Volumes" %} <span>({{ usages.volumes.used|intcomma }})</span></strong>
- <p>{{ usages.volumes.available|quota|intcomma }}</p>
- </div>
-
- <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">
- </div>
+ {% include "project/volumes/_quota.html" with usages=usages %}
</div>
-
- <script type="text/javascript" charset="utf-8">
- if(typeof horizon.Quota !== 'undefined') {
- horizon.Quota.init();
- } else {
- addHorizonLoadEvent(function() {
- horizon.Quota.init();
- });
- }
- </script>
{% endblock %}
{% 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 446a0d0b8..97c97bff1 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 @@
{% block modal-header %}{% trans "Create Volume Snapshot" %}{% endblock %}
{% block modal-body %}
-<div class="left">
- <fieldset>
- {% include "horizon/common/_form_fields.html" %}
- </fieldset>
-</div>
-<div class="right">
- <h3>{% trans "Description" %}:</h3>
- <p>{% trans "Volumes are block devices that can be attached to instances." %}</p>
-</div>
+ <div class="left">
+ <fieldset>
+ {% include "horizon/common/_form_fields.html" %}
+ </fieldset>
+ </div>
+ <div class="right quota-dynamic">
+ {% include "project/volumes/_quota.html" with usages=usages snapshot_quota=True %}
+ </div>
{% endblock %}
{% 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 000000000..f14538522
--- /dev/null
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/_quota.html
@@ -0,0 +1,43 @@
+{% load i18n horizon humanize %}
+
+<h3>{% trans "Description" %}:</h3>
+
+<p>{% trans "Volumes are block devices that can be attached to instances." %}</p>
+
+<h3>{% trans "Volume Quotas" %}</h3>
+
+<div class="quota_title clearfix">
+ <strong>{% trans "Total Gigabytes" %} <span>({{ usages.gigabytes.used|intcomma }} {% trans "GB" %})</span></strong>
+ <p>{{ usages.gigabytes.available|quota:_("GB")|intcomma }}</p>
+</div>
+
+<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">
+</div>
+
+{% if snapshot_quota %}
+ <div class="quota_title clearfix">
+ <strong>{% trans "Number of Snapshots" %} <span>({{ usages.snapshots.used|intcomma }})</span></strong>
+ <p>{{ usages.snapshots.available|quota|intcomma }}</p>
+ </div>
+
+ <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">
+ </div>
+{% else %}
+ <div class="quota_title clearfix">
+ <strong>{% trans "Number of Volumes" %} <span>({{ usages.volumes.used|intcomma }})</span></strong>
+ <p>{{ usages.volumes.available|quota|intcomma }}</p>
+ </div>
+
+ <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">
+ </div>
+{% endif %}
+
+<script type="text/javascript" charset="utf-8">
+ if(typeof horizon.Quota !== 'undefined') {
+ horizon.Quota.init();
+ } else {
+ addHorizonLoadEvent(function() {
+ horizon.Quota.init();
+ });
+ }
+</script>
diff --git a/openstack_dashboard/dashboards/project/volumes/views.py b/openstack_dashboard/dashboards/project/volumes/views.py
index fedaeea37..c423488bc 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):
def get_context_data(self, **kwargs):
context = super(CreateSnapshotView, self).get_context_data(**kwargs)
context['volume_id'] = self.kwargs['volume_id']
+ try:
+ context['usages'] = quotas.tenant_quota_usages(self.request)
+ except:
+ exceptions.handle(self.request)
return context
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 000000000..7ae08cb79
--- /dev/null
+++ b/openstack_dashboard/test/test_data/cinder_data.py
@@ -0,0 +1,45 @@
+# Copyright 2012 Nebula, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from cinderclient.v1 import quotas
+from openstack_dashboard.api.base import Quota, QuotaSet as QuotaSetWrapper
+from openstack_dashboard.usage.quotas import QuotaUsage
+from .utils import TestDataContainer
+
+
+def data(TEST):
+ TEST.cinder_quotas = TestDataContainer()
+ TEST.cinder_quota_usages = TestDataContainer()
+
+ # Quota Sets
+ quota_data = dict(volumes='1',
+ snapshots='1',
+ gigabytes='1000')
+ quota = quotas.QuotaSet(quotas.QuotaSetManager(None), quota_data)
+ #TEST.quotas.cinder = QuotaSetWrapper(quota)
+ TEST.cinder_quotas.add(QuotaSetWrapper(quota))
+
+ # Quota Usages
+ quota_usage_data = {'gigabytes': {'used': 0,
+ 'quota': 1000},
+ 'instances': {'used': 0,
+ 'quota': 10},
+ 'snapshots': {'used': 0,
+ 'quota': 10}}
+ quota_usage = QuotaUsage()
+ for k, v in quota_usage_data.items():
+ quota_usage.add_quota(Quota(k, v['quota']))
+ quota_usage.tally(k, v['used'])
+
+ 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 1a080aa95..ac73408fb 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):
from . import glance_data
from . import keystone_data
from . import nova_data
+ from . import cinder_data
from . import quantum_data
from . import swift_data
from . import heat_data
@@ -27,6 +28,7 @@ def load_test_data(load_onto=None):
keystone_data.data,
glance_data.data,
nova_data.data,
+ cinder_data.data,
quantum_data.data,
swift_data.data,
heat_data.data)
diff --git a/openstack_dashboard/test/tests/quotas.py b/openstack_dashboard/test/tests/quotas.py
index 1c65f40ca..29061a5df 100644
--- a/openstack_dashboard/test/tests/quotas.py
+++ b/openstack_dashboard/test/tests/quotas.py
@@ -45,6 +45,8 @@ class QuotaTests(test.APITestCase):
'cores': {'available': 8, 'used': 2, 'quota': 10}}
if with_volume:
quotas.update({'volumes': {'available': 0, 'used': 3, 'quota': 1},
+ 'snapshots': {'available': 0, 'used': 3,
+ 'quota': 1},
'gigabytes': {'available': 920, 'used': 80,
'quota': 1000}})
return quotas
@@ -54,7 +56,8 @@ class QuotaTests(test.APITestCase):
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',),
- cinder: ('volume_list', 'tenant_quota_get',)})
+ cinder: ('volume_list', 'volume_snapshot_list',
+ 'tenant_quota_get',)})
def test_tenant_quota_usages(self):
quotas.is_service_enabled(IsA(http.HttpRequest),
'volume').AndReturn(True)
@@ -68,8 +71,10 @@ class QuotaTests(test.APITestCase):
.AndReturn([self.servers.list(), False])
cinder.volume_list(IsA(http.HttpRequest)) \
.AndReturn(self.volumes.list())
+ cinder.volume_snapshot_list(IsA(http.HttpRequest)) \
+ .AndReturn(self.snapshots.list())
cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \
- .AndReturn(self.quotas.first())
+ .AndReturn(self.cinder_quotas.first())
self.mox.ReplayAll()
@@ -139,7 +144,8 @@ class QuotaTests(test.APITestCase):
'tenant_quota_get',),
api.network: ('tenant_floating_ip_list',),
quotas: ('is_service_enabled',),
- cinder: ('volume_list', 'tenant_quota_get',)})
+ cinder: ('volume_list', 'volume_snapshot_list',
+ 'tenant_quota_get',)})
def test_tenant_quota_usages_unlimited_quota(self):
inf_quota = self.quotas.first()
inf_quota['ram'] = -1
@@ -156,8 +162,10 @@ class QuotaTests(test.APITestCase):
.AndReturn([self.servers.list(), False])
cinder.volume_list(IsA(http.HttpRequest)) \
.AndReturn(self.volumes.list())
+ cinder.volume_snapshot_list(IsA(http.HttpRequest)) \
+ .AndReturn(self.snapshots.list())
cinder.tenant_quota_get(IsA(http.HttpRequest), '1') \
- .AndReturn(inf_quota)
+ .AndReturn(self.cinder_quotas.first())
self.mox.ReplayAll()
diff --git a/openstack_dashboard/usage/quotas.py b/openstack_dashboard/usage/quotas.py
index 99245097c..68ec9b3b5 100644
--- a/openstack_dashboard/usage/quotas.py
+++ b/openstack_dashboard/usage/quotas.py
@@ -19,6 +19,7 @@ NOVA_QUOTA_FIELDS = ("metadata_items",
"security_group_rules",)
CINDER_QUOTA_FIELDS = ("volumes",
+ "snapshots",
"gigabytes",)
QUOTA_FIELDS = NOVA_QUOTA_FIELDS + CINDER_QUOTA_FIELDS
@@ -136,8 +137,10 @@ def tenant_quota_usages(request):
if 'volumes' not in disabled_quotas:
volumes = cinder.volume_list(request)
+ snapshots = cinder.volume_snapshot_list(request)
usages.tally('gigabytes', sum([int(v.size) for v in volumes]))
usages.tally('volumes', len(volumes))
+ usages.tally('snapshots', len(snapshots))
# Sum our usage based on the flavors of the instances.
for flavor in [flavors[instance.flavor['id']] for instance in instances]: