Basic support for Cinder v2

Change-Id: I6540720866c9005cf9537fe5b3a241f769529b3a
Implements blueprint: cinder-v2-horizon
Closes-Bug: #1226944
This commit is contained in:
Julie Pichon 2014-01-29 15:07:15 +00:00 committed by Gerrit Code Review
parent 898ccff4c9
commit 77dcd64341
23 changed files with 440 additions and 195 deletions

View File

@ -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;

View File

@ -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):

View File

@ -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"))

View File

@ -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 %}

View File

@ -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])

View File

@ -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

View File

@ -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}))

View File

@ -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")

View File

@ -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,
"<h2>Volume Snapshot Details: %s</h2>" %
snapshot.display_name,
snapshot.name,
1, 200)
self.assertContains(res, "<dd>test snapshot</dd>", 1, 200)
self.assertContains(res,
"<dd>40f3fabf-3613-4f5e-90e5-6c9a08333fc3</dd>",
1,
200)
self.assertContains(res, "<dd>%s</dd>" % snapshot.id, 1, 200)
self.assertContains(res, "<dd>Available</dd>", 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)

View File

@ -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

View File

@ -8,20 +8,20 @@
<hr class="header_rule">
<dl>
<dt>{% trans "Name" %}</dt>
<dd>{{ snapshot.display_name }}</dd>
<dd>{{ snapshot.name }}</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ snapshot.id }}</dd>
{% if snapshot.display_description %}
{% if snapshot.description %}
<dt>{% trans "Description" %}</dt>
<dd>{{ snapshot.display_description }}</dd>
<dd>{{ snapshot.description }}</dd>
{% endif %}
<dt>{% trans "Status" %}</dt>
<dd>{{ snapshot.status|capfirst }}</dd>
<dt>{% trans "Volume" %}</dt>
<dd>
<a href="{% url 'horizon:project:volumes:volumes:detail' snapshot.volume_id %}">
{% if volume.display_name %}
{{ volume.display_name }}
{% if volume.name %}
{{ volume.name }}
{% else %}
{{ snapshot.volume_id }}
{% endif %}

View File

@ -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 %}
<div class="row-fluid">

View File

@ -8,12 +8,12 @@
<hr class="header_rule">
<dl>
<dt>{% trans "Name" %}</dt>
<dd>{{ volume.display_name }}</dd>
<dd>{{ volume.name }}</dd>
<dt>{% trans "ID" %}</dt>
<dd>{{ volume.id }}</dd>
{% if volume.display_description %}
{% if volume.description %}
<dt>{% trans "Description" %}</dt>
<dd>{{ volume.display_description }}</dd>
<dd>{{ volume.description }}</dd>
{% endif %}
<dt>{% trans "Status" %}</dt>
<dd>{{ volume.status|capfirst }}</dd>

View File

@ -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 %}

View File

@ -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')

View File

@ -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)

View File

@ -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,

View File

@ -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, "<h2>Volume Details: Volume name</h2>",
1, 200)
self.assertContains(res, "<dd>Volume name</dd>", 1, 200)
self.assertContains(res,
"<dd>41023e92-8008-4c8b-8059-7f2293ff3775</dd>",
1,
200)
self.assertContains(res, "<dd>%s</dd>" % volume.id, 1, 200)
self.assertContains(res, "<dd>Available</dd>", 1, 200)
self.assertContains(res, "<dd>40 GB</dd>", 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)

View File

@ -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):

View File

@ -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

View File

@ -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())

View File

@ -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)

View File

@ -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',