diff --git a/horizon/static/horizon/js/horizon.forms.js b/horizon/static/horizon/js/horizon.forms.js
index 78510edd5f..ce73066957 100644
--- a/horizon/static/horizon/js/horizon.forms.js
+++ b/horizon/static/horizon/js/horizon.forms.js
@@ -6,7 +6,7 @@ horizon.forms = {
var $form = $(this).closest('form');
var $volName = $form.find('input#id_name');
if ($volName.val() == "") {
- $volName.val($option.data("display_name"));
+ $volName.val($option.data("name"));
}
var $volSize = $form.find('input#id_size');
var volSize = parseInt($volSize.val(), 10) || -1;
@@ -23,7 +23,7 @@ horizon.forms = {
var $form = $(this).closest('form');
var $volName = $form.find('input#id_name');
if ($volName.val() == "") {
- $volName.val($option.data("display_name"));
+ $volName.val($option.data("name"));
}
var $volSize = $form.find('input#id_size');
var volSize = parseInt($volSize.val(), 10) || -1;
diff --git a/openstack_dashboard/api/cinder.py b/openstack_dashboard/api/cinder.py
index db45d1e28f..7b123c94fd 100644
--- a/openstack_dashboard/api/cinder.py
+++ b/openstack_dashboard/api/cinder.py
@@ -27,7 +27,6 @@ import logging
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
-from cinderclient.v1 import client as cinder_client
from cinderclient.v1.contrib import list_extensions as cinder_list_extensions
from horizon import exceptions
@@ -44,29 +43,100 @@ VOLUME_STATE_AVAILABLE = "available"
DEFAULT_QUOTA_NAME = 'default'
+VERSIONS = base.APIVersionManager("volume", preferred_version=1)
+
+try:
+ from cinderclient.v1 import client as cinder_client_v1
+ VERSIONS.load_supported_version(1, {"client": cinder_client_v1,
+ "version": 1})
+except ImportError:
+ pass
+
+try:
+ from cinderclient.v2 import client as cinder_client_v2
+ VERSIONS.load_supported_version(2, {"client": cinder_client_v2,
+ "version": 2})
+except ImportError:
+ pass
+
+
+class BaseCinderAPIResourceWrapper(base.APIResourceWrapper):
+
+ @property
+ def name(self):
+ # If a volume doesn't have a name, use its id.
+ return (getattr(self._apiresource, 'name', None) or
+ getattr(self._apiresource, 'display_name', None) or
+ getattr(self._apiresource, 'id', None))
+
+ @property
+ def description(self):
+ return (getattr(self._apiresource, 'description', None) or
+ getattr(self._apiresource, 'display_description', None))
+
+
+class Volume(BaseCinderAPIResourceWrapper):
+
+ _attrs = ['id', 'name', 'description', 'size', 'status', 'created_at',
+ 'volume_type', 'availability_zone', 'imageRef', 'bootable'
+ 'snapshot_id', 'source_volid', 'attachments', 'tenant_name',
+ 'os-vol-host-attr:host', 'os-vol-tenant-attr:tenant_id',
+ 'metadata']
+
+
+class VolumeSnapshot(BaseCinderAPIResourceWrapper):
+
+ _attrs = ['id', 'name', 'description', 'size', 'status',
+ 'created_at', 'volume_id',
+ 'os-extended-snapshot-attributes:project_id']
+
+
def cinderclient(request):
+ api_version = VERSIONS.get_active_version()
+
insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False)
cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None)
cinder_url = ""
try:
- cinder_url = base.url_for(request, 'volume')
+ # The cinder client assumes that the v2 endpoint type will be
+ # 'volumev2'. However it also allows 'volume' type as a
+ # fallback if the requested version is 2 and there is no
+ # 'volumev2' endpoint.
+ if api_version['version'] == 2:
+ try:
+ cinder_url = base.url_for(request, 'volumev2')
+ except exceptions.ServiceCatalogException:
+ LOG.warning("Cinder v2 requested but no 'volumev2' service "
+ "type available in Keystone catalog. Falling back "
+ "to 'volume'.")
+ if cinder_url == "":
+ cinder_url = base.url_for(request, 'volume')
except exceptions.ServiceCatalogException:
LOG.debug('no volume service configured.')
return None
LOG.debug('cinderclient connection created using token "%s" and url "%s"' %
(request.user.token.id, cinder_url))
- c = cinder_client.Client(request.user.username,
- request.user.token.id,
- project_id=request.user.tenant_id,
- auth_url=cinder_url,
- insecure=insecure,
- cacert=cacert,
- http_log_debug=settings.DEBUG)
+ c = api_version['client'].Client(request.user.username,
+ request.user.token.id,
+ project_id=request.user.tenant_id,
+ auth_url=cinder_url,
+ insecure=insecure,
+ cacert=cacert,
+ http_log_debug=settings.DEBUG)
c.client.auth_token = request.user.token.id
c.client.management_url = cinder_url
return c
+def _replace_v2_parameters(data):
+ if VERSIONS.active < 2:
+ data['display_name'] = data['name']
+ data['display_description'] = data['description']
+ del data['name']
+ del data['description']
+ return data
+
+
def volume_list(request, search_opts=None):
"""To see all volumes in the cloud as an admin you can pass in a special
search option: {'all_tenants': 1}
@@ -74,7 +144,7 @@ def volume_list(request, search_opts=None):
c_client = cinderclient(request)
if c_client is None:
return []
- return c_client.volumes.list(search_opts=search_opts)
+ return [Volume(v) for v in c_client.volumes.list(search_opts=search_opts)]
def volume_get(request, volume_id):
@@ -89,16 +159,24 @@ def volume_get(request, volume_id):
# the lack a server_id property; to work around that we'll
# give the attached instance a generic name.
attachment['instance_name'] = _("Unknown instance")
- return volume_data
+ return Volume(volume_data)
def volume_create(request, size, name, description, volume_type,
snapshot_id=None, metadata=None, image_id=None,
availability_zone=None, source_volid=None):
- return cinderclient(request).volumes.create(size, display_name=name,
- display_description=description, volume_type=volume_type,
- snapshot_id=snapshot_id, metadata=metadata, imageRef=image_id,
- availability_zone=availability_zone, source_volid=source_volid)
+ data = {'name': name,
+ 'description': description,
+ 'volume_type': volume_type,
+ 'snapshot_id': snapshot_id,
+ 'metadata': metadata,
+ 'imageRef': image_id,
+ 'availability_zone': availability_zone,
+ 'source_volid': source_volid}
+ data = _replace_v2_parameters(data)
+
+ volume = cinderclient(request).volumes.create(size, **data)
+ return Volume(volume)
def volume_extend(request, volume_id, new_size):
@@ -110,28 +188,34 @@ def volume_delete(request, volume_id):
def volume_update(request, volume_id, name, description):
- vol_data = {'display_name': name,
- 'display_description': description}
+ vol_data = {'name': name,
+ 'description': description}
+ vol_data = _replace_v2_parameters(vol_data)
return cinderclient(request).volumes.update(volume_id,
**vol_data)
def volume_snapshot_get(request, snapshot_id):
- return cinderclient(request).volume_snapshots.get(snapshot_id)
+ snapshot = cinderclient(request).volume_snapshots.get(snapshot_id)
+ return VolumeSnapshot(snapshot)
def volume_snapshot_list(request):
c_client = cinderclient(request)
if c_client is None:
return []
- return c_client.volume_snapshots.list()
+ return [VolumeSnapshot(s) for s in c_client.volume_snapshots.list()]
def volume_snapshot_create(request, volume_id, name,
description=None, force=False):
- return cinderclient(request).volume_snapshots.create(
- volume_id, force=force, display_name=name,
- display_description=description)
+ data = {'name': name,
+ 'description': description,
+ 'force': force}
+ data = _replace_v2_parameters(data)
+
+ return VolumeSnapshot(cinderclient(request).volume_snapshots.create(
+ volume_id, **data))
def volume_snapshot_delete(request, snapshot_id):
diff --git a/openstack_dashboard/dashboards/admin/volumes/tables.py b/openstack_dashboard/dashboards/admin/volumes/tables.py
index 9befae86a8..0d704b362a 100644
--- a/openstack_dashboard/dashboards/admin/volumes/tables.py
+++ b/openstack_dashboard/dashboards/admin/volumes/tables.py
@@ -41,11 +41,11 @@ class VolumesFilterAction(tables.FilterAction):
"""Naive case-insensitive search."""
q = filter_string.lower()
return [volume for volume in volumes
- if q in volume.display_name.lower()]
+ if q in volume.name.lower()]
class VolumesTable(project_tables.VolumesTable):
- name = tables.Column("display_name",
+ name = tables.Column("name",
verbose_name=_("Name"),
link="horizon:admin:volumes:detail")
host = tables.Column("os-vol-host-attr:host", verbose_name=_("Host"))
diff --git a/openstack_dashboard/dashboards/admin/volumes/templates/volumes/detail.html b/openstack_dashboard/dashboards/admin/volumes/templates/volumes/detail.html
index 260f9f4379..59dbb7d5a5 100644
--- a/openstack_dashboard/dashboards/admin/volumes/templates/volumes/detail.html
+++ b/openstack_dashboard/dashboards/admin/volumes/templates/volumes/detail.html
@@ -3,7 +3,7 @@
{% block title %}{% trans "Volume Details" %}{% endblock %}
{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Volume Details: ")|add:volume.display_name|default:_("Volume Details:") %}
+ {% include "horizon/common/_page_header.html" with title=_("Volume Details: ")|add:volume.name|default:_("Volume Details:") %}
{% endblock page_header %}
{% block main %}
diff --git a/openstack_dashboard/dashboards/admin/volumes/tests.py b/openstack_dashboard/dashboards/admin/volumes/tests.py
index 67851868eb..5acc7467f1 100644
--- a/openstack_dashboard/dashboards/admin/volumes/tests.py
+++ b/openstack_dashboard/dashboards/admin/volumes/tests.py
@@ -31,7 +31,7 @@ class VolumeTests(test.BaseAdminViewTests):
keystone: ('tenant_list',)})
def test_index(self):
cinder.volume_list(IsA(http.HttpRequest), search_opts={
- 'all_tenants': True}).AndReturn(self.volumes.list())
+ 'all_tenants': True}).AndReturn(self.cinder_volumes.list())
api.nova.server_list(IsA(http.HttpRequest), search_opts={
'all_tenants': True}) \
.AndReturn([self.servers.list(), False])
@@ -47,7 +47,7 @@ class VolumeTests(test.BaseAdminViewTests):
self.assertTemplateUsed(res, 'admin/volumes/index.html')
volumes = res.context['volumes_table'].data
- self.assertItemsEqual(volumes, self.volumes.list())
+ self.assertItemsEqual(volumes, self.cinder_volumes.list())
@test.create_stubs({cinder: ('volume_type_create',)})
def test_create_volume_type(self):
@@ -74,7 +74,7 @@ class VolumeTests(test.BaseAdminViewTests):
formData = {'action': 'volume_types__delete__%s' % volume_type.id}
cinder.volume_list(IsA(http.HttpRequest), search_opts={
- 'all_tenants': True}).AndReturn(self.volumes.list())
+ 'all_tenants': True}).AndReturn(self.cinder_volumes.list())
api.nova.server_list(IsA(http.HttpRequest), search_opts={
'all_tenants': True}) \
.AndReturn([self.servers.list(), False])
diff --git a/openstack_dashboard/dashboards/admin/volumes/views.py b/openstack_dashboard/dashboards/admin/volumes/views.py
index 858befb10d..5667327f44 100644
--- a/openstack_dashboard/dashboards/admin/volumes/views.py
+++ b/openstack_dashboard/dashboards/admin/volumes/views.py
@@ -48,7 +48,6 @@ class IndexView(tables.MultiTableView, project_tabs.VolumeTableMixIn):
def get_volumes_data(self):
volumes = self._get_volumes(search_opts={'all_tenants': True})
instances = self._get_instances(search_opts={'all_tenants': True})
- self._set_id_if_nameless(volumes)
self._set_attachments_string(volumes, instances)
# Gather our tenants to correlate against IDs
diff --git a/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py b/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py
index 5294593e9b..b206c5f681 100644
--- a/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py
+++ b/openstack_dashboard/dashboards/project/instances/workflows/create_instance.py
@@ -342,7 +342,7 @@ class SetInstanceDetailsAction(workflows.Action):
visible_label = _("Volume")
return (("%s:%s" % (volume.id, vol_type)),
(_("%(name)s - %(size)s GB (%(label)s)") %
- {'name': volume.display_name or volume.id,
+ {'name': volume.name,
'size': volume.size,
'label': visible_label}))
diff --git a/openstack_dashboard/dashboards/project/volumes/snapshots/tables.py b/openstack_dashboard/dashboards/project/volumes/snapshots/tables.py
index 1993e1e7ca..5004e1156b 100644
--- a/openstack_dashboard/dashboards/project/volumes/snapshots/tables.py
+++ b/openstack_dashboard/dashboards/project/volumes/snapshots/tables.py
@@ -79,7 +79,7 @@ class SnapshotVolumeNameColumn(tables.Column):
def get_raw_data(self, snapshot):
volume = snapshot._volume
if volume:
- volume_name = volume.display_name or volume.id
+ volume_name = volume.name
volume_name = html.escape(volume_name)
else:
volume_name = _("Unknown")
@@ -93,11 +93,10 @@ class SnapshotVolumeNameColumn(tables.Column):
class VolumeSnapshotsTable(volume_tables.VolumesTableBase):
- name = tables.Column("display_name",
+ name = tables.Column("name",
verbose_name=_("Name"),
link="horizon:project:volumes:detail")
- volume_name = SnapshotVolumeNameColumn(
- "display_name",
+ volume_name = SnapshotVolumeNameColumn("name",
verbose_name=_("Volume Name"),
link="horizon:project:volumes:volumes:detail")
diff --git a/openstack_dashboard/dashboards/project/volumes/snapshots/tests.py b/openstack_dashboard/dashboards/project/volumes/snapshots/tests.py
index 50b9f3e59a..f3b434c211 100644
--- a/openstack_dashboard/dashboards/project/volumes/snapshots/tests.py
+++ b/openstack_dashboard/dashboards/project/volumes/snapshots/tests.py
@@ -35,12 +35,12 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',),
quotas: ('tenant_limit_usages',)})
def test_create_snapshot_get(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
@@ -56,15 +56,15 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',
'volume_snapshot_create',)})
def test_create_snapshot_post(self):
- volume = self.volumes.first()
- snapshot = self.volume_snapshots.first()
+ volume = self.cinder_volumes.first()
+ snapshot = self.cinder_volume_snapshots.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
cinder.volume_snapshot_create(IsA(http.HttpRequest),
volume.id,
- snapshot.display_name,
- snapshot.display_description,
+ snapshot.name,
+ snapshot.description,
force=False) \
.AndReturn(snapshot)
self.mox.ReplayAll()
@@ -72,8 +72,8 @@ class VolumeSnapshotsViewTests(test.TestCase):
formData = {'method': 'CreateSnapshotForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
- 'name': snapshot.display_name,
- 'description': snapshot.display_description}
+ 'name': snapshot.name,
+ 'description': snapshot.description}
url = reverse('horizon:project:volumes:volumes:create_snapshot',
args=[volume.id])
res = self.client.post(url, formData)
@@ -82,15 +82,15 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',
'volume_snapshot_create',)})
def test_force_create_snapshot(self):
- volume = self.volumes.get(name='my_volume')
- snapshot = self.volume_snapshots.first()
+ volume = self.cinder_volumes.get(name='my_volume')
+ snapshot = self.cinder_volume_snapshots.first()
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
cinder.volume_snapshot_create(IsA(http.HttpRequest),
volume.id,
- snapshot.display_name,
- snapshot.display_description,
+ snapshot.name,
+ snapshot.description,
force=True) \
.AndReturn(snapshot)
self.mox.ReplayAll()
@@ -98,8 +98,8 @@ class VolumeSnapshotsViewTests(test.TestCase):
formData = {'method': 'CreateSnapshotForm',
'tenant_id': self.tenant.id,
'volume_id': volume.id,
- 'name': snapshot.display_name,
- 'description': snapshot.display_description}
+ 'name': snapshot.name,
+ 'description': snapshot.description}
url = reverse('horizon:project:volumes:volumes:create_snapshot',
args=[volume.id])
res = self.client.post(url, formData)
@@ -111,9 +111,9 @@ class VolumeSnapshotsViewTests(test.TestCase):
'volume_snapshot_delete'),
quotas: ('tenant_quota_usages',)})
def test_delete_volume_snapshot(self):
- vol_snapshots = self.volume_snapshots.list()
- volumes = self.volumes.list()
- snapshot = self.volume_snapshots.first()
+ vol_snapshots = self.cinder_volume_snapshots.list()
+ volumes = self.cinder_volumes.list()
+ snapshot = self.cinder_volume_snapshots.first()
api.cinder.volume_snapshot_list(IsA(http.HttpRequest)). \
AndReturn(vol_snapshots)
@@ -142,8 +142,8 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({api.cinder: ('volume_snapshot_get', 'volume_get')})
def test_volume_snapshot_detail_get(self):
- volume = self.volumes.first()
- snapshot = self.volume_snapshots.first()
+ volume = self.cinder_volumes.first()
+ snapshot = self.cinder_volume_snapshots.first()
api.cinder.volume_get(IsA(http.HttpRequest), volume.id). \
AndReturn(volume)
@@ -158,19 +158,16 @@ class VolumeSnapshotsViewTests(test.TestCase):
self.assertContains(res,
"
Volume Snapshot Details: %s
" %
- snapshot.display_name,
+ snapshot.name,
1, 200)
self.assertContains(res, "test snapshot", 1, 200)
- self.assertContains(res,
- "40f3fabf-3613-4f5e-90e5-6c9a08333fc3",
- 1,
- 200)
+ self.assertContains(res, "%s" % snapshot.id, 1, 200)
self.assertContains(res, "Available", 1, 200)
@test.create_stubs({api.cinder: ('volume_snapshot_get',)})
def test_volume_snapshot_detail_get_with_exception(self):
# Test to verify redirect if get volume snapshot fails
- snapshot = self.volume_snapshots.first()
+ snapshot = self.cinder_volume_snapshots.first()
api.cinder.volume_snapshot_get(IsA(http.HttpRequest), snapshot.id).\
AndRaise(self.exceptions.cinder)
@@ -185,8 +182,8 @@ class VolumeSnapshotsViewTests(test.TestCase):
@test.create_stubs({api.cinder: ('volume_snapshot_get', 'volume_get')})
def test_volume_snapshot_detail_with_volume_get_exception(self):
# Test to verify redirect if get volume fails
- volume = self.volumes.first()
- snapshot = self.volume_snapshots.first()
+ volume = self.cinder_volumes.first()
+ snapshot = self.cinder_volume_snapshots.first()
api.cinder.volume_get(IsA(http.HttpRequest), volume.id). \
AndRaise(self.exceptions.cinder)
diff --git a/openstack_dashboard/dashboards/project/volumes/tabs.py b/openstack_dashboard/dashboards/project/volumes/tabs.py
index 45c1166d10..2527536d15 100644
--- a/openstack_dashboard/dashboards/project/volumes/tabs.py
+++ b/openstack_dashboard/dashboards/project/volumes/tabs.py
@@ -49,13 +49,6 @@ class VolumeTableMixIn(object):
"attachment information"))
return []
- def _set_id_if_nameless(self, volumes):
- for volume in volumes:
- # It is possible to create a volume with no name through the
- # EC2 API, use the ID in those cases.
- if not volume.display_name:
- volume.display_name = volume.id
-
def _set_attachments_string(self, volumes, instances):
instances = SortedDict([(inst.id, inst) for inst in instances])
for volume in volumes:
@@ -73,7 +66,6 @@ class VolumeTab(tabs.TableTab, VolumeTableMixIn):
def get_volumes_data(self):
volumes = self._get_volumes()
instances = self._get_instances()
- self._set_id_if_nameless(volumes)
self._set_attachments_string(volumes, instances)
return volumes
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/_detail_overview.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/_detail_overview.html
index 11fb958be4..bb2dcbf58f 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/_detail_overview.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/_detail_overview.html
@@ -8,20 +8,20 @@
- {% trans "Name" %}
- - {{ snapshot.display_name }}
+ - {{ snapshot.name }}
- {% trans "ID" %}
- {{ snapshot.id }}
- {% if snapshot.display_description %}
+ {% if snapshot.description %}
- {% trans "Description" %}
- - {{ snapshot.display_description }}
+ - {{ snapshot.description }}
{% endif %}
- {% trans "Status" %}
- {{ snapshot.status|capfirst }}
- {% trans "Volume" %}
-
- {% if volume.display_name %}
- {{ volume.display_name }}
+ {% if volume.name %}
+ {{ volume.name }}
{% else %}
{{ snapshot.volume_id }}
{% endif %}
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/detail.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/detail.html
index 5bca132066..9e19f59a86 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/detail.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/snapshots/detail.html
@@ -3,7 +3,7 @@
{% block title %}{% trans "Volume Snapshot Details" %}{% endblock %}
{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Volume Snapshot Details: ")|add:snapshot.display_name|default:_("Volume Snapshot Details:") %}
+ {% include "horizon/common/_page_header.html" with title=_("Volume Snapshot Details: ")|add:snapshot.name|default:_("Volume Snapshot Details:") %}
{% endblock page_header %}
{% block main %}
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_detail_overview.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_detail_overview.html
index 0aecff68a8..e51f282792 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_detail_overview.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/_detail_overview.html
@@ -8,12 +8,12 @@
- {% trans "Name" %}
- - {{ volume.display_name }}
+ - {{ volume.name }}
- {% trans "ID" %}
- {{ volume.id }}
- {% if volume.display_description %}
+ {% if volume.description %}
- {% trans "Description" %}
- - {{ volume.display_description }}
+ - {{ volume.description }}
{% endif %}
- {% trans "Status" %}
- {{ volume.status|capfirst }}
diff --git a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/detail.html b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/detail.html
index 260f9f4379..59dbb7d5a5 100644
--- a/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/detail.html
+++ b/openstack_dashboard/dashboards/project/volumes/templates/volumes/volumes/detail.html
@@ -3,7 +3,7 @@
{% block title %}{% trans "Volume Details" %}{% endblock %}
{% block page_header %}
- {% include "horizon/common/_page_header.html" with title=_("Volume Details: ")|add:volume.display_name|default:_("Volume Details:") %}
+ {% include "horizon/common/_page_header.html" with title=_("Volume Details: ")|add:volume.name|default:_("Volume Details:") %}
{% endblock page_header %}
{% block main %}
diff --git a/openstack_dashboard/dashboards/project/volumes/test.py b/openstack_dashboard/dashboards/project/volumes/test.py
index a0f05622a7..d0dba6a0d7 100644
--- a/openstack_dashboard/dashboards/project/volumes/test.py
+++ b/openstack_dashboard/dashboards/project/volumes/test.py
@@ -33,8 +33,8 @@ class VolumeAndSnapshotsTests(test.TestCase):
api.nova: ('server_list',),
quotas: ('tenant_quota_usages',)})
def test_index(self):
- vol_snaps = self.volume_snapshots.list()
- volumes = self.volumes.list()
+ vol_snaps = self.cinder_volume_snapshots.list()
+ volumes = self.cinder_volumes.list()
api.cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\
AndReturn(volumes)
@@ -48,4 +48,5 @@ class VolumeAndSnapshotsTests(test.TestCase):
self.mox.ReplayAll()
res = self.client.get(INDEX_URL)
+ self.assertEqual(res.status_code, 200)
self.assertTemplateUsed(res, 'project/volumes/index.html')
diff --git a/openstack_dashboard/dashboards/project/volumes/volumes/forms.py b/openstack_dashboard/dashboards/project/volumes/volumes/forms.py
index 4d80238663..fea238f9ee 100644
--- a/openstack_dashboard/dashboards/project/volumes/volumes/forms.py
+++ b/openstack_dashboard/dashboards/project/volumes/volumes/forms.py
@@ -56,8 +56,8 @@ class CreateForm(forms.SelfHandlingForm):
label=_("Use snapshot as a source"),
widget=fields.SelectWidget(
attrs={'class': 'snapshot-selector'},
- data_attrs=('size', 'display_name'),
- transform=lambda x: "%s (%sGB)" % (x.display_name, x.size)),
+ data_attrs=('size', 'name'),
+ transform=lambda x: "%s (%sGB)" % (x.name, x.size)),
required=False)
image_source = forms.ChoiceField(
label=_("Use image as a source"),
@@ -70,8 +70,8 @@ class CreateForm(forms.SelfHandlingForm):
label=_("Use a volume as source"),
widget=fields.SelectWidget(
attrs={'class': 'image-selector'},
- data_attrs=('size', 'display_name'),
- transform=lambda x: "%s (%s)" % (x.display_name,
+ data_attrs=('size', 'name'),
+ transform=lambda x: "%s (%s)" % (x.name,
filesizeformat(x.size * 1024 * 1024 * 1024))),
required=False)
availability_zone = forms.ChoiceField(
@@ -94,7 +94,7 @@ class CreateForm(forms.SelfHandlingForm):
try:
snapshot = self.get_snapshot(request,
request.GET["snapshot_id"])
- self.fields['name'].initial = snapshot.display_name
+ self.fields['name'].initial = snapshot.name
self.fields['size'].initial = snapshot.size
self.fields['snapshot_source'].choices = ((snapshot.id,
snapshot),)
@@ -153,8 +153,8 @@ class CreateForm(forms.SelfHandlingForm):
exceptions.handle(request, msg % request.GET['volume_id'])
if volume is not None:
- self.fields['name'].initial = volume.display_name
- self.fields['description'].initial = volume.display_description
+ self.fields['name'].initial = volume.name
+ self.fields['description'].initial = volume.description
min_vol_size = volume.size
size_help_text = _('Volume size must be equal to or greater '
'than the origin volume size (%s)') \
@@ -417,12 +417,8 @@ class AttachForm(forms.SelfHandlingForm):
data['instance'],
data.get('device', ''))
volume = cinder.volume_get(request, data['volume_id'])
- if not volume.display_name:
- volume_name = volume.id
- else:
- volume_name = volume.display_name
message = _('Attaching volume %(vol)s to instance '
- '%(inst)s on %(dev)s.') % {"vol": volume_name,
+ '%(inst)s on %(dev)s.') % {"vol": volume.name,
"inst": instance_name,
"dev": attach.device}
messages.info(request, message)
diff --git a/openstack_dashboard/dashboards/project/volumes/volumes/tables.py b/openstack_dashboard/dashboards/project/volumes/volumes/tables.py
index f2969df8de..f7a00af3dd 100644
--- a/openstack_dashboard/dashboards/project/volumes/volumes/tables.py
+++ b/openstack_dashboard/dashboards/project/volumes/volumes/tables.py
@@ -165,8 +165,6 @@ class UpdateRow(tables.Row):
def get_data(self, request, volume_id):
volume = cinder.volume_get(request, volume_id)
- if not volume.display_name:
- volume.display_name = volume_id
return volume
@@ -226,10 +224,10 @@ class VolumesTableBase(tables.DataTable):
("creating", None),
("error", False),
)
- name = tables.Column("display_name",
+ name = tables.Column("name",
verbose_name=_("Name"),
link="horizon:project:volumes:volumes:detail")
- description = tables.Column("display_description",
+ description = tables.Column("description",
verbose_name=_("Description"),
truncate=40)
size = tables.Column(get_size,
@@ -242,7 +240,7 @@ class VolumesTableBase(tables.DataTable):
status_choices=STATUS_CHOICES)
def get_object_display(self, obj):
- return obj.display_name
+ return obj.name
class VolumesFilterAction(tables.FilterAction):
@@ -251,11 +249,11 @@ class VolumesFilterAction(tables.FilterAction):
"""Naive case-insensitive search."""
q = filter_string.lower()
return [volume for volume in volumes
- if q in volume.display_name.lower()]
+ if q in volume.name.lower()]
class VolumesTable(VolumesTableBase):
- name = tables.Column("display_name",
+ name = tables.Column("name",
verbose_name=_("Name"),
link="horizon:project:volumes:volumes:detail")
volume_type = tables.Column(get_volume_type,
diff --git a/openstack_dashboard/dashboards/project/volumes/volumes/tests.py b/openstack_dashboard/dashboards/project/volumes/volumes/tests.py
index 03033f6273..195ae96fdd 100644
--- a/openstack_dashboard/dashboards/project/volumes/volumes/tests.py
+++ b/openstack_dashboard/dashboards/project/volumes/volumes/tests.py
@@ -47,12 +47,12 @@ class VolumeViewTests(test.TestCase):
api.glance: ('image_list_detailed',),
quotas: ('tenant_limit_usages',)})
def test_create_volume(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
volume_type = self.volume_types.first()
az = self.cinder_availability_zones.first().zoneName
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'A Volume I Am Making',
'description': u'This is a volume I am making for a test.',
@@ -67,7 +67,7 @@ class VolumeViewTests(test.TestCase):
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -82,7 +82,7 @@ class VolumeViewTests(test.TestCase):
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
.AndReturn(True)
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
cinder.volume_create(IsA(http.HttpRequest),
formData['size'],
@@ -113,10 +113,10 @@ class VolumeViewTests(test.TestCase):
api.glance: ('image_list_detailed',),
quotas: ('tenant_limit_usages',)})
def test_create_volume_dropdown(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'A Volume I Am Making',
'description': u'This is a volume I am making for a test.',
@@ -124,13 +124,13 @@ class VolumeViewTests(test.TestCase):
'size': 50,
'type': '',
'volume_source_type': 'no_source_type',
- 'snapshot_source': self.volume_snapshots.first().id,
+ 'snapshot_source': self.cinder_volume_snapshots.first().id,
'image_source': self.images.first().id}
cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -140,7 +140,7 @@ class VolumeViewTests(test.TestCase):
'status': 'active'}) \
.AndReturn([[], False])
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
@@ -174,12 +174,12 @@ class VolumeViewTests(test.TestCase):
'volume_type_list'),
quotas: ('tenant_limit_usages',)})
def test_create_volume_from_snapshot(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
- snapshot = self.volume_snapshots.first()
+ snapshot = self.cinder_volume_snapshots.first()
formData = {'name': u'A Volume I Am Making',
'description': u'This is a volume I am making for a test.',
'method': u'CreateForm',
@@ -194,7 +194,7 @@ class VolumeViewTests(test.TestCase):
cinder.volume_snapshot_get(IsA(http.HttpRequest),
str(snapshot.id)).AndReturn(snapshot)
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
- AndReturn(self.volumes.first())
+ AndReturn(self.cinder_volumes.first())
cinder.volume_create(IsA(http.HttpRequest),
formData['size'],
@@ -228,10 +228,10 @@ class VolumeViewTests(test.TestCase):
api.glance: ('image_list_detailed',),
quotas: ('tenant_limit_usages',)})
def test_create_volume_from_volume(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'A copy of a volume',
@@ -243,16 +243,16 @@ class VolumeViewTests(test.TestCase):
'volume_source': volume.id}
cinder.volume_list(IsA(http.HttpRequest)).\
- AndReturn(self.volumes.list())
+ AndReturn(self.cinder_volumes.list())
cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
cinder.volume_get(IsA(http.HttpRequest),
- volume.id).AndReturn(self.volumes.first())
+ volume.id).AndReturn(self.cinder_volumes.first())
cinder.extension_supported(IsA(http.HttpRequest),
'AvailabilityZones').AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
@@ -296,12 +296,12 @@ class VolumeViewTests(test.TestCase):
api.glance: ('image_list_detailed',),
quotas: ('tenant_limit_usages',)})
def test_create_volume_from_snapshot_dropdown(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 250,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
- snapshot = self.volume_snapshots.first()
+ snapshot = self.cinder_volume_snapshots.first()
formData = {'name': u'A Volume I Am Making',
'description': u'This is a volume I am making for a test.',
'method': u'CreateForm',
@@ -313,7 +313,7 @@ class VolumeViewTests(test.TestCase):
cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -323,7 +323,7 @@ class VolumeViewTests(test.TestCase):
'status': 'active'}) \
.AndReturn([[], False])
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
cinder.volume_snapshot_get(IsA(http.HttpRequest),
@@ -362,9 +362,9 @@ class VolumeViewTests(test.TestCase):
def test_create_volume_from_snapshot_invalid_size(self):
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
- snapshot = self.volume_snapshots.first()
+ snapshot = self.cinder_volume_snapshots.first()
formData = {'name': u'A Volume I Am Making',
'description': u'This is a volume I am making for a test.',
'method': u'CreateForm',
@@ -377,7 +377,7 @@ class VolumeViewTests(test.TestCase):
cinder.volume_snapshot_get(IsA(http.HttpRequest),
str(snapshot.id)).AndReturn(snapshot)
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
- AndReturn(self.volumes.first())
+ AndReturn(self.cinder_volumes.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
@@ -400,10 +400,10 @@ class VolumeViewTests(test.TestCase):
api.glance: ('image_get',),
quotas: ('tenant_limit_usages',)})
def test_create_volume_from_image(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 200,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
image = self.images.first()
formData = {'name': u'A Volume I Am Making',
@@ -457,10 +457,10 @@ class VolumeViewTests(test.TestCase):
'image_list_detailed'),
quotas: ('tenant_limit_usages',)})
def test_create_volume_from_image_dropdown(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 200,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
image = self.images.first()
formData = {'name': u'A Volume I Am Making',
@@ -469,13 +469,13 @@ class VolumeViewTests(test.TestCase):
'size': 30,
'type': '',
'volume_source_type': 'image_source',
- 'snapshot_source': self.volume_snapshots.first().id,
+ 'snapshot_source': self.cinder_volume_snapshots.first().id,
'image_source': image.id}
cinder.volume_type_list(IsA(http.HttpRequest)).\
AndReturn(self.volume_types.list())
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -485,7 +485,7 @@ class VolumeViewTests(test.TestCase):
'status': 'active'}) \
.AndReturn([[], False])
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
quotas.tenant_limit_usages(IsA(http.HttpRequest)) \
.AndReturn(usage_limit)
api.glance.image_get(IsA(http.HttpRequest),
@@ -525,7 +525,7 @@ class VolumeViewTests(test.TestCase):
def test_create_volume_from_image_under_image_size(self):
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
image = self.images.first()
formData = {'name': u'A Volume I Am Making',
@@ -574,7 +574,7 @@ class VolumeViewTests(test.TestCase):
def test_create_volume_from_image_under_image_min_disk_size(self):
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
image = self.images.get(name="protected_images")
image.min_disk = 30
@@ -617,7 +617,7 @@ class VolumeViewTests(test.TestCase):
def test_create_volume_gb_used_over_alloted_quota(self):
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 80,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'This Volume Is Huge!',
'description': u'This is a volume that is just too big!',
@@ -629,7 +629,7 @@ class VolumeViewTests(test.TestCase):
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -639,7 +639,7 @@ class VolumeViewTests(test.TestCase):
'status': 'active'}) \
.AndReturn([[], False])
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
.AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
@@ -666,8 +666,8 @@ class VolumeViewTests(test.TestCase):
def test_create_volume_number_over_alloted_quota(self):
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
- 'maxTotalVolumes': len(self.volumes.list())}
+ 'volumesUsed': len(self.cinder_volumes.list()),
+ 'maxTotalVolumes': len(self.cinder_volumes.list())}
formData = {'name': u'Too Many...',
'description': u'We have no volumes left!',
'method': u'CreateForm',
@@ -678,7 +678,7 @@ class VolumeViewTests(test.TestCase):
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
api.glance.image_list_detailed(IsA(http.HttpRequest),
filters={'is_public': True,
'status': 'active'}) \
@@ -688,7 +688,7 @@ class VolumeViewTests(test.TestCase):
'status': 'active'}) \
.AndReturn([[], False])
cinder.volume_list(IsA(
- http.HttpRequest)).AndReturn(self.volumes.list())
+ http.HttpRequest)).AndReturn(self.cinder_volumes.list())
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
.AndReturn(True)
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
@@ -711,25 +711,25 @@ class VolumeViewTests(test.TestCase):
api.nova: ('server_list',),
quotas: ('tenant_quota_usages',)})
def test_delete_volume(self):
- volumes = self.volumes.list()
- volume = self.volumes.first()
+ volumes = self.cinder_volumes.list()
+ volume = self.cinder_volumes.first()
formData = {'action':
'volumes__delete__%s' % volume.id}
cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\
- AndReturn(volumes)
+ AndReturn(volumes)
cinder.volume_delete(IsA(http.HttpRequest), volume.id)
api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\
- AndReturn([self.servers.list(), False])
+ AndReturn([self.servers.list(), False])
cinder.volume_snapshot_list(IsA(http.HttpRequest)).\
- AndReturn(self.volume_snapshots.list())
+ AndReturn(self.cinder_volume_snapshots.list())
cinder.volume_list(IsA(http.HttpRequest), search_opts=None).\
- AndReturn(volumes)
+ AndReturn(volumes)
api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\
- AndReturn([self.servers.list(), False])
+ AndReturn([self.servers.list(), False])
cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes)
quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().\
- AndReturn(self.quota_usages.first())
+ AndReturn(self.quota_usages.first())
self.mox.ReplayAll()
@@ -744,8 +744,8 @@ class VolumeViewTests(test.TestCase):
api.nova: ('server_list',),
quotas: ('tenant_quota_usages',)})
def test_delete_volume_error_existing_snapshot(self):
- volume = self.volumes.first()
- volumes = self.volumes.list()
+ volume = self.cinder_volumes.first()
+ volumes = self.cinder_volumes.list()
formData = {'action':
'volumes__delete__%s' % volume.id}
exc = self.exceptions.cinder.__class__(400,
@@ -762,7 +762,7 @@ class VolumeViewTests(test.TestCase):
api.nova.server_list(IsA(http.HttpRequest), search_opts=None).\
AndReturn([self.servers.list(), False])
cinder.volume_snapshot_list(IsA(http.HttpRequest))\
- .AndReturn(self.volume_snapshots.list())
+ .AndReturn(self.cinder_volume_snapshots.list())
cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes)
quotas.tenant_quota_usages(IsA(http.HttpRequest)).MultipleTimes().\
AndReturn(self.quota_usages.first())
@@ -774,14 +774,14 @@ class VolumeViewTests(test.TestCase):
self.assertEqual(list(res.context['messages'])[0].message,
u'Unable to delete volume "%s". '
u'One or more snapshots depend on it.' %
- volume.display_name)
+ volume.name)
@test.create_stubs({cinder: ('volume_get',), api.nova: ('server_list',)})
def test_edit_attachments(self):
PREV = settings.OPENSTACK_HYPERVISOR_FEATURES['can_set_mount_point']
settings.OPENSTACK_HYPERVISOR_FEATURES['can_set_mount_point'] = True
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
@@ -805,7 +805,7 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',), api.nova: ('server_list',)})
def test_edit_attachments_cannot_set_mount_point(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
@@ -828,7 +828,7 @@ class VolumeViewTests(test.TestCase):
servers = [s for s in self.servers.list()
if s.tenant_id == self.request.user.tenant_id]
server = servers[0]
- volume = self.volumes.list()[0]
+ volume = self.cinder_volumes.list()[0]
cinder.volume_get(IsA(http.HttpRequest), volume.id) \
.AndReturn(volume)
@@ -856,14 +856,14 @@ class VolumeViewTests(test.TestCase):
def test_create_button_disabled_when_quota_exceeded(self):
quota_usages = self.quota_usages.first()
quota_usages['volumes']['available'] = 0
- volumes = self.volumes.list()
+ volumes = self.cinder_volumes.list()
cinder.volume_list(IsA(http.HttpRequest), search_opts=None)\
.AndReturn(volumes)
api.nova.server_list(IsA(http.HttpRequest), search_opts=None)\
.AndReturn([self.servers.list(), False])
cinder.volume_snapshot_list(IsA(http.HttpRequest))\
- .AndReturn(self.volume_snapshots.list())
+ .AndReturn(self.cinder_volume_snapshots.list())
cinder.volume_list(IsA(http.HttpRequest)).AndReturn(volumes)
quotas.tenant_quota_usages(IsA(http.HttpRequest))\
.MultipleTimes().AndReturn(quota_usages)
@@ -874,7 +874,7 @@ class VolumeViewTests(test.TestCase):
self.assertTemplateUsed(res, 'project/volumes/index.html')
volumes = res.context['volumes_table'].data
- self.assertItemsEqual(volumes, self.volumes.list())
+ self.assertItemsEqual(volumes, self.cinder_volumes.list())
create_link = tables.CreateVolume()
url = create_link.get_link_url()
@@ -891,7 +891,7 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',),
api.nova: ('server_get',)})
def test_detail_view(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
server = self.servers.first()
volume.attachments = [{"server_id": server.id}]
@@ -908,10 +908,7 @@ class VolumeViewTests(test.TestCase):
self.assertContains(res, "Volume Details: Volume name
",
1, 200)
self.assertContains(res, "- Volume name
", 1, 200)
- self.assertContains(res,
- "- 41023e92-8008-4c8b-8059-7f2293ff3775
",
- 1,
- 200)
+ self.assertContains(res, "- %s
" % volume.id, 1, 200)
self.assertContains(res, "- Available
", 1, 200)
self.assertContains(res, "- 40 GB
", 1, 200)
self.assertContains(res,
@@ -924,8 +921,8 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',)})
def test_get_data(self):
- volume = self.volumes.first()
- volume.display_name = ''
+ volume = self.cinder_volumes.get(name='v2_volume')
+ volume._apiresource.name = ""
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
@@ -938,11 +935,11 @@ class VolumeViewTests(test.TestCase):
HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(res.status_code, 200)
- self.assertEqual(volume.display_name, volume.id)
+ self.assertEqual(volume.name, volume.id)
@test.create_stubs({cinder: ('volume_get',)})
def test_detail_view_with_exception(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
server = self.servers.first()
volume.attachments = [{"server_id": server.id}]
@@ -961,19 +958,19 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_update',
'volume_get',)})
def test_update_volume(self):
- volume = self.volumes.get(name="my_volume")
+ volume = self.cinder_volumes.get(name="my_volume")
cinder.volume_get(IsA(http.HttpRequest), volume.id).AndReturn(volume)
cinder.volume_update(IsA(http.HttpRequest),
volume.id,
- volume.display_name,
- volume.display_description)
+ volume.name,
+ volume.description)
self.mox.ReplayAll()
formData = {'method': 'UpdateForm',
- 'name': volume.display_name,
- 'description': volume.display_description}
+ 'name': volume.name,
+ 'description': volume.description}
url = reverse('horizon:project:volumes:volumes:update',
args=[volume.id])
@@ -983,13 +980,13 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',
'volume_extend')})
def test_extend_volume(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
formData = {'name': u'A Volume I Am Making',
'orig_size': volume.size,
'new_size': 100}
cinder.volume_get(IsA(http.HttpRequest), volume.id).\
- AndReturn(self.volumes.first())
+ AndReturn(self.cinder_volumes.first())
cinder.volume_extend(IsA(http.HttpRequest),
volume.id,
@@ -1007,17 +1004,17 @@ class VolumeViewTests(test.TestCase):
@test.create_stubs({cinder: ('volume_get',),
quotas: ('tenant_limit_usages',)})
def test_extend_volume_with_wrong_size(self):
- volume = self.volumes.first()
+ volume = self.cinder_volumes.first()
usage_limit = {'maxTotalVolumeGigabytes': 100,
'gigabytesUsed': 20,
- 'volumesUsed': len(self.volumes.list()),
+ 'volumesUsed': len(self.cinder_volumes.list()),
'maxTotalVolumes': 6}
formData = {'name': u'A Volume I Am Making',
'orig_size': volume.size,
'new_size': 10}
cinder.volume_get(IsA(http.HttpRequest), volume.id).\
- AndReturn(self.volumes.first())
+ AndReturn(self.cinder_volumes.first())
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
AndReturn(usage_limit)
diff --git a/openstack_dashboard/dashboards/project/volumes/volumes/views.py b/openstack_dashboard/dashboards/project/volumes/volumes/views.py
index 7ab620a290..967399fccb 100644
--- a/openstack_dashboard/dashboards/project/volumes/volumes/views.py
+++ b/openstack_dashboard/dashboards/project/volumes/volumes/views.py
@@ -115,7 +115,7 @@ class ExtendView(forms.ModalFormView):
def get_initial(self):
volume = self.get_object()
return {'id': self.kwargs['volume_id'],
- 'name': volume.display_name,
+ 'name': volume.name,
'orig_size': volume.size}
@@ -171,8 +171,8 @@ class UpdateView(forms.ModalFormView):
def get_initial(self):
volume = self.get_object()
return {'volume_id': self.kwargs["volume_id"],
- 'name': volume.display_name,
- 'description': volume.display_description}
+ 'name': volume.name,
+ 'description': volume.description}
class EditAttachmentsView(tables.DataTableView, forms.ModalFormView):
diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example
index 3cb6d82055..a9c96c182e 100644
--- a/openstack_dashboard/local/local_settings.py.example
+++ b/openstack_dashboard/local/local_settings.py.example
@@ -32,7 +32,8 @@ TEMPLATE_DEBUG = DEBUG
# service API. For example, The identity service APIs have inconsistent
# use of the decimal point, so valid options would be "2.0" or "3".
# OPENSTACK_API_VERSIONS = {
-# "identity": 3
+# "identity": 3,
+# "volume": 2
# }
# Set this to True if running on multi-domain model. When this is enabled, it
diff --git a/openstack_dashboard/test/api_tests/cinder_tests.py b/openstack_dashboard/test/api_tests/cinder_tests.py
index d395a54f30..54c0c20d06 100644
--- a/openstack_dashboard/test/api_tests/cinder_tests.py
+++ b/openstack_dashboard/test/api_tests/cinder_tests.py
@@ -14,6 +14,9 @@
# License for the specific language governing permissions and limitations
# under the License.
+from django.test.utils import override_settings
+
+import cinderclient as cinder_client
from openstack_dashboard import api
from openstack_dashboard.test import helpers as test
@@ -22,7 +25,7 @@ from openstack_dashboard.test import helpers as test
class CinderApiTests(test.APITestCase):
def test_volume_list(self):
search_opts = {'all_tenants': 1}
- volumes = self.volumes.list()
+ volumes = self.cinder_volumes.list()
cinderclient = self.stub_cinderclient()
cinderclient.volumes = self.mox.CreateMockAnything()
cinderclient.volumes.list(search_opts=search_opts,).AndReturn(volumes)
@@ -32,7 +35,7 @@ class CinderApiTests(test.APITestCase):
api.cinder.volume_list(self.request, search_opts=search_opts)
def test_volume_snapshot_list(self):
- volume_snapshots = self.volume_snapshots.list()
+ volume_snapshots = self.cinder_volume_snapshots.list()
cinderclient = self.stub_cinderclient()
cinderclient.volume_snapshots = self.mox.CreateMockAnything()
cinderclient.volume_snapshots.list().AndReturn(volume_snapshots)
@@ -46,7 +49,7 @@ class CinderApiTests(test.APITestCase):
for service in catalog:
if service["type"] == "volume":
self.service_catalog.remove(service)
- volume_snapshots = self.volume_snapshots.list()
+ volume_snapshots = self.cinder_volume_snapshots.list()
cinderclient = self.stub_cinderclient()
cinderclient.volume_snapshots = self.mox.CreateMockAnything()
@@ -54,3 +57,109 @@ class CinderApiTests(test.APITestCase):
self.mox.ReplayAll()
api.cinder.volume_snapshot_list(self.request)
+
+
+class CinderApiVersionTests(test.TestCase):
+
+ def setUp(self):
+ super(CinderApiVersionTests, self).setUp()
+ # The version is set when the module is loaded. Reset the
+ # active version each time so that we can test with different
+ # versions.
+ api.cinder.VERSIONS._active = None
+
+ def test_default_client_is_v1(self):
+ client = api.cinder.cinderclient(self.request)
+ self.assertIsInstance(client, cinder_client.v1.client.Client)
+
+ @override_settings(OPENSTACK_API_VERSIONS={'volume': 1})
+ def test_v1_setting_returns_v1_client(self):
+ client = api.cinder.cinderclient(self.request)
+ self.assertIsInstance(client, cinder_client.v1.client.Client)
+
+ @override_settings(OPENSTACK_API_VERSIONS={'volume': 2})
+ def test_v2_setting_returns_v2_client(self):
+ client = api.cinder.cinderclient(self.request)
+ self.assertIsInstance(client, cinder_client.v2.client.Client)
+
+ def test_get_v1_volume_attributes(self):
+ # Get a v1 volume
+ volume = self.cinder_volumes.first()
+ self.assertTrue(hasattr(volume._apiresource, 'display_name'))
+ self.assertFalse(hasattr(volume._apiresource, 'name'))
+
+ name = "A test volume name"
+ description = "A volume description"
+ setattr(volume._apiresource, 'display_name', name)
+ setattr(volume._apiresource, 'display_description', description)
+ self.assertEqual(volume.name, name)
+ self.assertEqual(volume.description, description)
+
+ def test_get_v2_volume_attributes(self):
+ # Get a v2 volume
+ volume = self.cinder_volumes.get(name="v2_volume")
+ self.assertTrue(hasattr(volume._apiresource, 'name'))
+ self.assertFalse(hasattr(volume._apiresource, 'display_name'))
+
+ name = "A v2 test volume name"
+ description = "A v2 volume description"
+ setattr(volume._apiresource, 'name', name)
+ setattr(volume._apiresource, 'description', description)
+ self.assertEqual(volume.name, name)
+ self.assertEqual(volume.description, description)
+
+ def test_get_v1_snapshot_attributes(self):
+ # Get a v1 snapshot
+ snapshot = self.cinder_volume_snapshots.first()
+ self.assertFalse(hasattr(snapshot._apiresource, 'name'))
+
+ name = "A test snapshot name"
+ description = "A snapshot description"
+ setattr(snapshot._apiresource, 'display_name', name)
+ setattr(snapshot._apiresource, 'display_description', description)
+ self.assertEqual(snapshot.name, name)
+ self.assertEqual(snapshot.description, description)
+
+ def test_get_v2_snapshot_attributes(self):
+ # Get a v2 snapshot
+ snapshot = self.cinder_volume_snapshots.get(
+ description="v2 volume snapshot description")
+ self.assertFalse(hasattr(snapshot._apiresource, 'display_name'))
+
+ name = "A v2 test snapshot name"
+ description = "A v2 snapshot description"
+ setattr(snapshot._apiresource, 'name', name)
+ setattr(snapshot._apiresource, 'description', description)
+ self.assertEqual(snapshot.name, name)
+ self.assertEqual(snapshot.description, description)
+
+ def test_get_id_for_nameless_volume(self):
+ volume = self.cinder_volumes.first()
+ setattr(volume._apiresource, 'display_name', "")
+ self.assertEqual(volume.name, volume.id)
+
+ @override_settings(OPENSTACK_API_VERSIONS={'volume': 1})
+ def test_adapt_dictionary_to_v1(self):
+ volume = self.cinder_volumes.first()
+ data = {'name': volume.name,
+ 'description': volume.description,
+ 'size': volume.size}
+
+ ret_data = api.cinder._replace_v2_parameters(data)
+ self.assertIn('display_name', ret_data.keys())
+ self.assertIn('display_description', ret_data.keys())
+ self.assertNotIn('name', ret_data.keys())
+ self.assertNotIn('description', ret_data.keys())
+
+ @override_settings(OPENSTACK_API_VERSIONS={'volume': 2})
+ def test_adapt_dictionary_to_v2(self):
+ volume = self.cinder_volumes.first()
+ data = {'name': volume.name,
+ 'description': volume.description,
+ 'size': volume.size}
+
+ ret_data = api.cinder._replace_v2_parameters(data)
+ self.assertIn('name', ret_data.keys())
+ self.assertIn('description', ret_data.keys())
+ self.assertNotIn('display_name', ret_data.keys())
+ self.assertNotIn('display_description', ret_data.keys())
diff --git a/openstack_dashboard/test/test_data/cinder_data.py b/openstack_dashboard/test/test_data/cinder_data.py
index 18c5f6eeb9..9deb2e0d17 100644
--- a/openstack_dashboard/test/test_data/cinder_data.py
+++ b/openstack_dashboard/test/test_data/cinder_data.py
@@ -14,25 +14,94 @@
from cinderclient.v1 import availability_zones
from cinderclient.v1 import quotas
+from cinderclient.v1 import volume_snapshots as vol_snaps
+from cinderclient.v1 import volumes
+from cinderclient.v2 import volume_snapshots as vol_snaps_v2
+from cinderclient.v2 import volumes as volumes_v2
-from openstack_dashboard.api import base
+from openstack_dashboard import api
from openstack_dashboard.usage import quotas as usage_quotas
from openstack_dashboard.test.test_data import utils
def data(TEST):
+ TEST.cinder_volumes = utils.TestDataContainer()
+ TEST.cinder_volume_snapshots = utils.TestDataContainer()
TEST.cinder_quotas = utils.TestDataContainer()
TEST.cinder_quota_usages = utils.TestDataContainer()
TEST.cinder_availability_zones = utils.TestDataContainer()
+ # Volumes - Cinder v1
+ volume = volumes.Volume(volumes.VolumeManager(None),
+ {'id': "11023e92-8008-4c8b-8059-7f2293ff3887",
+ 'status': 'available',
+ 'size': 40,
+ 'display_name': 'Volume name',
+ 'display_description': 'Volume description',
+ 'created_at': '2014-01-27 10:30:00',
+ 'volume_type': None,
+ 'attachments': []})
+ nameless_volume = volumes.Volume(volumes.VolumeManager(None),
+ dict(id="4b069dd0-6eaa-4272-8abc-5448a68f1cce",
+ status='available',
+ size=10,
+ display_name='',
+ display_description='',
+ device="/dev/hda",
+ created_at='2010-11-21 18:34:25',
+ volume_type='vol_type_1',
+ attachments=[]))
+ other_volume = volumes.Volume(volumes.VolumeManager(None),
+ {'id': "21023e92-8008-1234-8059-7f2293ff3889",
+ 'status': 'in-use',
+ 'size': 10,
+ 'display_name': u'my_volume',
+ 'display_description': '',
+ 'created_at': '2013-04-01 10:30:00',
+ 'volume_type': None,
+ 'attachments': [{"id": "1", "server_id": '1',
+ "device": "/dev/hda"}]})
+ TEST.cinder_volumes.add(api.cinder.Volume(volume))
+ TEST.cinder_volumes.add(api.cinder.Volume(nameless_volume))
+ TEST.cinder_volumes.add(api.cinder.Volume(other_volume))
+
+ # Volumes - Cinder v2
+ volume_v2 = volumes_v2.Volume(volumes_v2.VolumeManager(None),
+ {'id': "31023e92-8008-4c8b-8059-7f2293ff1234",
+ 'name': 'v2_volume',
+ 'description': "v2 Volume Description",
+ 'status': 'available',
+ 'size': 20,
+ 'created_at': '2014-01-27 10:30:00',
+ 'volume_type': None,
+ 'attachments': []})
+ TEST.cinder_volumes.add(api.cinder.Volume(volume_v2))
+
+ snapshot = vol_snaps.Snapshot(vol_snaps.SnapshotManager(None),
+ {'id': '5f3d1c33-7d00-4511-99df-a2def31f3b5d',
+ 'display_name': 'test snapshot',
+ 'display_description': 'volume snapshot',
+ 'size': 40,
+ 'status': 'available',
+ 'volume_id': '11023e92-8008-4c8b-8059-7f2293ff3887'})
+ snapshot2 = vol_snaps_v2.Snapshot(vol_snaps_v2.SnapshotManager(None),
+ {'id': 'c9d0881a-4c0b-4158-a212-ad27e11c2b0f',
+ 'name': '',
+ 'description': 'v2 volume snapshot description',
+ 'size': 80,
+ 'status': 'available',
+ 'volume_id': '31023e92-8008-4c8b-8059-7f2293ff1234'})
+
+ TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot))
+ TEST.cinder_volume_snapshots.add(api.cinder.VolumeSnapshot(snapshot2))
+
# 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(base.QuotaSet(quota))
+ TEST.cinder_quotas.add(api.base.QuotaSet(quota))
# Quota Usages
quota_usage_data = {'gigabytes': {'used': 0,
@@ -43,7 +112,7 @@ def data(TEST):
'quota': 10}}
quota_usage = usage_quotas.QuotaUsage()
for k, v in quota_usage_data.items():
- quota_usage.add_quota(base.Quota(k, v['quota']))
+ quota_usage.add_quota(api.base.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/keystone_data.py b/openstack_dashboard/test/test_data/keystone_data.py
index d190a076ab..210454b4b2 100644
--- a/openstack_dashboard/test/test_data/keystone_data.py
+++ b/openstack_dashboard/test/test_data/keystone_data.py
@@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import copy
from datetime import timedelta # noqa
from django.conf import settings
@@ -47,7 +48,7 @@ SERVICE_CATALOG = [
"internalURL": "http://int.nova2.example.com:8774/v2",
"publicURL": "http://public.nova2.example.com:8774/v2"}]},
{"type": "volume",
- "name": "nova",
+ "name": "cinder",
"endpoints_links": [],
"endpoints": [
{"region": "RegionOne",
@@ -126,7 +127,9 @@ SERVICE_CATALOG = [
def data(TEST):
- TEST.service_catalog = SERVICE_CATALOG
+ # Make a deep copy of the catalog to avoid persisting side-effects
+ # when tests modify the catalog.
+ TEST.service_catalog = copy.deepcopy(SERVICE_CATALOG)
TEST.tokens = utils.TestDataContainer()
TEST.domains = utils.TestDataContainer()
TEST.users = utils.TestDataContainer()
@@ -205,7 +208,7 @@ def data(TEST):
user5 = users.User(users.UserManager(None), user_dict)
TEST.users.add(user, user2, user3, user4, user5)
TEST.user = user # Your "current" user
- TEST.user.service_catalog = SERVICE_CATALOG
+ TEST.user.service_catalog = copy.deepcopy(SERVICE_CATALOG)
group_dict = {'id': "1",
'name': 'group_one',