Merge "Add Availability Zone to Volume screens"
This commit is contained in:
commit
27b5b9f3fc
@ -28,8 +28,10 @@ from django.conf import settings # noqa
|
|||||||
from django.utils.translation import ugettext_lazy as _ # noqa
|
from django.utils.translation import ugettext_lazy as _ # noqa
|
||||||
|
|
||||||
from cinderclient.v1 import client as cinder_client
|
from cinderclient.v1 import client as cinder_client
|
||||||
|
from cinderclient.v1.contrib import list_extensions as cinder_list_extensions
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
|
from horizon.utils.memoized import memoized # noqa
|
||||||
|
|
||||||
from openstack_dashboard.api import base
|
from openstack_dashboard.api import base
|
||||||
from openstack_dashboard.api import nova
|
from openstack_dashboard.api import nova
|
||||||
@ -92,10 +94,12 @@ def volume_get(request, volume_id):
|
|||||||
|
|
||||||
|
|
||||||
def volume_create(request, size, name, description, volume_type,
|
def volume_create(request, size, name, description, volume_type,
|
||||||
snapshot_id=None, metadata=None, image_id=None):
|
snapshot_id=None, metadata=None, image_id=None,
|
||||||
|
availability_zone=None):
|
||||||
return cinderclient(request).volumes.create(size, display_name=name,
|
return cinderclient(request).volumes.create(size, display_name=name,
|
||||||
display_description=description, volume_type=volume_type,
|
display_description=description, volume_type=volume_type,
|
||||||
snapshot_id=snapshot_id, metadata=metadata, imageRef=image_id)
|
snapshot_id=snapshot_id, metadata=metadata, imageRef=image_id,
|
||||||
|
availability_zone=availability_zone)
|
||||||
|
|
||||||
|
|
||||||
def volume_delete(request, volume_id):
|
def volume_delete(request, volume_id):
|
||||||
@ -163,3 +167,25 @@ def tenant_absolute_limits(request):
|
|||||||
else:
|
else:
|
||||||
limits_dict[limit.name] = limit.value
|
limits_dict[limit.name] = limit.value
|
||||||
return limits_dict
|
return limits_dict
|
||||||
|
|
||||||
|
|
||||||
|
def availability_zone_list(request, detailed=False):
|
||||||
|
return cinderclient(request).availability_zones.list(detailed=detailed)
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def list_extensions(request):
|
||||||
|
return cinder_list_extensions.ListExtManager(cinderclient(request))\
|
||||||
|
.show_all()
|
||||||
|
|
||||||
|
|
||||||
|
@memoized
|
||||||
|
def extension_supported(request, extension_name):
|
||||||
|
"""
|
||||||
|
This method will determine if Cinder supports a given extension name.
|
||||||
|
"""
|
||||||
|
extensions = list_extensions(request)
|
||||||
|
for extension in extensions:
|
||||||
|
if extension.name == extension_name:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
@ -51,6 +51,8 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
data_attrs=('size', 'name'),
|
data_attrs=('size', 'name'),
|
||||||
transform=lambda x: "%s (%s)" % (x.name, filesizeformat(x.bytes))),
|
transform=lambda x: "%s (%s)" % (x.name, filesizeformat(x.bytes))),
|
||||||
required=False)
|
required=False)
|
||||||
|
availability_zone = forms.ChoiceField(label=_("Availability Zone"),
|
||||||
|
required=False)
|
||||||
|
|
||||||
def __init__(self, request, *args, **kwargs):
|
def __init__(self, request, *args, **kwargs):
|
||||||
super(CreateForm, self).__init__(request, *args, **kwargs)
|
super(CreateForm, self).__init__(request, *args, **kwargs)
|
||||||
@ -58,6 +60,8 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
self.fields['type'].choices = [("", "")] + \
|
self.fields['type'].choices = [("", "")] + \
|
||||||
[(type.name, type.name)
|
[(type.name, type.name)
|
||||||
for type in volume_types]
|
for type in volume_types]
|
||||||
|
self.fields['availability_zone'].choices = \
|
||||||
|
self.availability_zones(request)
|
||||||
|
|
||||||
if ("snapshot_id" in request.GET):
|
if ("snapshot_id" in request.GET):
|
||||||
try:
|
try:
|
||||||
@ -137,6 +141,34 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
else:
|
else:
|
||||||
del self.fields['volume_source_type']
|
del self.fields['volume_source_type']
|
||||||
|
|
||||||
|
# Determine whether the extension for Cinder AZs is enabled
|
||||||
|
def cinder_az_supported(self, request):
|
||||||
|
try:
|
||||||
|
return cinder.extension_supported(request, 'AvailabilityZones')
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Unable to determine if '
|
||||||
|
'availability zones extension '
|
||||||
|
'is supported.'))
|
||||||
|
return False
|
||||||
|
|
||||||
|
def availability_zones(self, request):
|
||||||
|
zone_list = []
|
||||||
|
if self.cinder_az_supported(request):
|
||||||
|
try:
|
||||||
|
zones = api.cinder.availability_zone_list(request)
|
||||||
|
zone_list = [(zone.zoneName, zone.zoneName)
|
||||||
|
for zone in zones if zone.zoneState['available']]
|
||||||
|
zone_list.sort()
|
||||||
|
except Exception:
|
||||||
|
exceptions.handle(request, _('Unable to retrieve availability '
|
||||||
|
'zones.'))
|
||||||
|
if not zone_list:
|
||||||
|
zone_list.insert(0, ("", _("No availability zones found.")))
|
||||||
|
elif len(zone_list) > 0:
|
||||||
|
zone_list.insert(0, ("", _("Any Availability Zone")))
|
||||||
|
|
||||||
|
return zone_list
|
||||||
|
|
||||||
def handle(self, request, data):
|
def handle(self, request, data):
|
||||||
try:
|
try:
|
||||||
usages = quotas.tenant_limit_usages(self.request)
|
usages = quotas.tenant_limit_usages(self.request)
|
||||||
@ -188,6 +220,8 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
|
|
||||||
metadata = {}
|
metadata = {}
|
||||||
|
|
||||||
|
az = data['availability_zone'] or None
|
||||||
|
|
||||||
volume = cinder.volume_create(request,
|
volume = cinder.volume_create(request,
|
||||||
data['size'],
|
data['size'],
|
||||||
data['name'],
|
data['name'],
|
||||||
@ -195,7 +229,8 @@ class CreateForm(forms.SelfHandlingForm):
|
|||||||
data['type'],
|
data['type'],
|
||||||
snapshot_id=snapshot_id,
|
snapshot_id=snapshot_id,
|
||||||
image_id=image_id,
|
image_id=image_id,
|
||||||
metadata=metadata)
|
metadata=metadata,
|
||||||
|
availability_zone=az)
|
||||||
message = _('Creating volume "%s"') % data['name']
|
message = _('Creating volume "%s"') % data['name']
|
||||||
messages.info(request, message)
|
messages.info(request, message)
|
||||||
return volume
|
return volume
|
||||||
|
@ -199,6 +199,8 @@ class VolumesTable(VolumesTableBase):
|
|||||||
empty_value="-")
|
empty_value="-")
|
||||||
attachments = AttachmentColumn("attachments",
|
attachments = AttachmentColumn("attachments",
|
||||||
verbose_name=_("Attached To"))
|
verbose_name=_("Attached To"))
|
||||||
|
availability_zone = tables.Column("availability_zone",
|
||||||
|
verbose_name=_("Availability Zone"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
name = "volumes"
|
name = "volumes"
|
||||||
|
@ -35,12 +35,15 @@ from openstack_dashboard.usage import quotas
|
|||||||
class VolumeViewTests(test.TestCase):
|
class VolumeViewTests(test.TestCase):
|
||||||
@test.create_stubs({cinder: ('volume_create',
|
@test.create_stubs({cinder: ('volume_create',
|
||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
'volume_type_list',),
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume(self):
|
def test_create_volume(self):
|
||||||
volume = self.volumes.first()
|
volume = self.volumes.first()
|
||||||
volume_type = self.volume_types.first()
|
volume_type = self.volume_types.first()
|
||||||
|
az = self.cinder_availability_zones.first().zoneName
|
||||||
usage_limit = {'maxTotalVolumeGigabytes': 250,
|
usage_limit = {'maxTotalVolumeGigabytes': 250,
|
||||||
'gigabytesUsed': 20,
|
'gigabytesUsed': 20,
|
||||||
'volumesUsed': len(self.volumes.list()),
|
'volumesUsed': len(self.volumes.list()),
|
||||||
@ -50,7 +53,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'method': u'CreateForm',
|
'method': u'CreateForm',
|
||||||
'type': volume_type.name,
|
'type': volume_type.name,
|
||||||
'size': 50,
|
'size': 50,
|
||||||
'snapshot_source': ''}
|
'snapshot_source': '',
|
||||||
|
'availability_zone': az}
|
||||||
|
|
||||||
cinder.volume_type_list(IsA(http.HttpRequest)).\
|
cinder.volume_type_list(IsA(http.HttpRequest)).\
|
||||||
AndReturn(self.volume_types.list())
|
AndReturn(self.volume_types.list())
|
||||||
@ -66,6 +70,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
filters={'property-owner_id': self.tenant.id,
|
filters={'property-owner_id': self.tenant.id,
|
||||||
'status': 'active'}) \
|
'status': 'active'}) \
|
||||||
.AndReturn([[], False])
|
.AndReturn([[], False])
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -73,7 +83,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
formData['type'],
|
formData['type'],
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
image_id=None).AndReturn(volume)
|
image_id=None,
|
||||||
|
availability_zone=formData['availability_zone'])\
|
||||||
|
.AndReturn(volume)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -85,7 +97,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_create',
|
@test.create_stubs({cinder: ('volume_create',
|
||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
'volume_type_list',),
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_dropdown(self):
|
def test_create_volume_dropdown(self):
|
||||||
@ -117,6 +131,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
.AndReturn([[], False])
|
.AndReturn([[], False])
|
||||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -124,8 +144,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'',
|
'',
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
image_id=None).\
|
image_id=None,
|
||||||
AndReturn(volume)
|
availability_zone=None).AndReturn(volume)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -138,7 +158,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
@test.create_stubs({cinder: ('volume_create',
|
@test.create_stubs({cinder: ('volume_create',
|
||||||
'volume_snapshot_get',
|
'volume_snapshot_get',
|
||||||
'volume_get',
|
'volume_get',
|
||||||
'volume_type_list',),
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_from_snapshot(self):
|
def test_create_volume_from_snapshot(self):
|
||||||
volume = self.volumes.first()
|
volume = self.volumes.first()
|
||||||
@ -162,6 +184,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
str(snapshot.id)).AndReturn(snapshot)
|
str(snapshot.id)).AndReturn(snapshot)
|
||||||
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
|
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
|
||||||
AndReturn(self.volumes.first())
|
AndReturn(self.volumes.first())
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -169,8 +197,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'',
|
'',
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=snapshot.id,
|
snapshot_id=snapshot.id,
|
||||||
image_id=None).\
|
image_id=None,
|
||||||
AndReturn(volume)
|
availability_zone=None).AndReturn(volume)
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
# get snapshot from url
|
# get snapshot from url
|
||||||
@ -186,7 +214,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'volume_snapshot_list',
|
'volume_snapshot_list',
|
||||||
'volume_snapshot_get',
|
'volume_snapshot_get',
|
||||||
'volume_get',
|
'volume_get',
|
||||||
'volume_type_list',),
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_from_snapshot_dropdown(self):
|
def test_create_volume_from_snapshot_dropdown(self):
|
||||||
@ -220,6 +250,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
cinder.volume_snapshot_get(IsA(http.HttpRequest),
|
cinder.volume_snapshot_get(IsA(http.HttpRequest),
|
||||||
str(snapshot.id)).AndReturn(snapshot)
|
str(snapshot.id)).AndReturn(snapshot)
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -227,8 +263,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'',
|
'',
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=snapshot.id,
|
snapshot_id=snapshot.id,
|
||||||
image_id=None).\
|
image_id=None,
|
||||||
AndReturn(volume)
|
availability_zone=None).AndReturn(volume)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -241,7 +277,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_snapshot_get',
|
@test.create_stubs({cinder: ('volume_snapshot_get',
|
||||||
'volume_type_list',
|
'volume_type_list',
|
||||||
'volume_get',),
|
'volume_get',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_from_snapshot_invalid_size(self):
|
def test_create_volume_from_snapshot_invalid_size(self):
|
||||||
@ -263,6 +301,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
str(snapshot.id)).AndReturn(snapshot)
|
str(snapshot.id)).AndReturn(snapshot)
|
||||||
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
|
cinder.volume_get(IsA(http.HttpRequest), snapshot.volume_id).\
|
||||||
AndReturn(self.volumes.first())
|
AndReturn(self.volumes.first())
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
|
|
||||||
@ -278,7 +322,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
"snapshot size (40GB)")
|
"snapshot size (40GB)")
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_create',
|
@test.create_stubs({cinder: ('volume_create',
|
||||||
'volume_type_list',),
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_get',),
|
api.glance: ('image_get',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_from_image(self):
|
def test_create_volume_from_image(self):
|
||||||
@ -301,6 +347,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
api.glance.image_get(IsA(http.HttpRequest),
|
api.glance.image_get(IsA(http.HttpRequest),
|
||||||
str(image.id)).AndReturn(image)
|
str(image.id)).AndReturn(image)
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -308,8 +360,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'',
|
'',
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
image_id=image.id).\
|
image_id=image.id,
|
||||||
AndReturn(volume)
|
availability_zone=None).AndReturn(volume)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -324,7 +376,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_create',
|
@test.create_stubs({cinder: ('volume_create',
|
||||||
'volume_type_list',
|
'volume_type_list',
|
||||||
'volume_snapshot_list',),
|
'volume_snapshot_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_get',
|
api.glance: ('image_get',
|
||||||
'image_list_detailed'),
|
'image_list_detailed'),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
@ -360,6 +414,12 @@ class VolumeViewTests(test.TestCase):
|
|||||||
.AndReturn(usage_limit)
|
.AndReturn(usage_limit)
|
||||||
api.glance.image_get(IsA(http.HttpRequest),
|
api.glance.image_get(IsA(http.HttpRequest),
|
||||||
str(image.id)).AndReturn(image)
|
str(image.id)).AndReturn(image)
|
||||||
|
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
|
|
||||||
cinder.volume_create(IsA(http.HttpRequest),
|
cinder.volume_create(IsA(http.HttpRequest),
|
||||||
formData['size'],
|
formData['size'],
|
||||||
formData['name'],
|
formData['name'],
|
||||||
@ -367,8 +427,8 @@ class VolumeViewTests(test.TestCase):
|
|||||||
'',
|
'',
|
||||||
metadata={},
|
metadata={},
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
image_id=image.id).\
|
image_id=image.id,
|
||||||
AndReturn(volume)
|
availability_zone=None).AndReturn(volume)
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
|
|
||||||
@ -379,7 +439,9 @@ class VolumeViewTests(test.TestCase):
|
|||||||
redirect_url = reverse('horizon:project:volumes:index')
|
redirect_url = reverse('horizon:project:volumes:index')
|
||||||
self.assertRedirectsNoFollow(res, redirect_url)
|
self.assertRedirectsNoFollow(res, redirect_url)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_type_list',),
|
@test.create_stubs({cinder: ('volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_get',
|
api.glance: ('image_get',
|
||||||
'image_list_detailed'),
|
'image_list_detailed'),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
@ -400,6 +462,10 @@ class VolumeViewTests(test.TestCase):
|
|||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
api.glance.image_get(IsA(http.HttpRequest),
|
api.glance.image_get(IsA(http.HttpRequest),
|
||||||
str(image.id)).AndReturn(image)
|
str(image.id)).AndReturn(image)
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
|
|
||||||
@ -414,7 +480,10 @@ class VolumeViewTests(test.TestCase):
|
|||||||
"The volume size cannot be less than the "
|
"The volume size cannot be less than the "
|
||||||
"image size (20.0 GB)")
|
"image size (20.0 GB)")
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_snapshot_list', 'volume_type_list',),
|
@test.create_stubs({cinder: ('volume_snapshot_list',
|
||||||
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_gb_used_over_alloted_quota(self):
|
def test_create_volume_gb_used_over_alloted_quota(self):
|
||||||
@ -441,6 +510,10 @@ class VolumeViewTests(test.TestCase):
|
|||||||
filters={'property-owner_id': self.tenant.id,
|
filters={'property-owner_id': self.tenant.id,
|
||||||
'status': 'active'}) \
|
'status': 'active'}) \
|
||||||
.AndReturn([[], False])
|
.AndReturn([[], False])
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
|
|
||||||
@ -453,7 +526,10 @@ class VolumeViewTests(test.TestCase):
|
|||||||
' have 20GB of your quota available.']
|
' have 20GB of your quota available.']
|
||||||
self.assertEqual(res.context['form'].errors['__all__'], expected_error)
|
self.assertEqual(res.context['form'].errors['__all__'], expected_error)
|
||||||
|
|
||||||
@test.create_stubs({cinder: ('volume_snapshot_list', 'volume_type_list',),
|
@test.create_stubs({cinder: ('volume_snapshot_list',
|
||||||
|
'volume_type_list',
|
||||||
|
'availability_zone_list',
|
||||||
|
'extension_supported'),
|
||||||
api.glance: ('image_list_detailed',),
|
api.glance: ('image_list_detailed',),
|
||||||
quotas: ('tenant_limit_usages',)})
|
quotas: ('tenant_limit_usages',)})
|
||||||
def test_create_volume_number_over_alloted_quota(self):
|
def test_create_volume_number_over_alloted_quota(self):
|
||||||
@ -480,6 +556,10 @@ class VolumeViewTests(test.TestCase):
|
|||||||
filters={'property-owner_id': self.tenant.id,
|
filters={'property-owner_id': self.tenant.id,
|
||||||
'status': 'active'}) \
|
'status': 'active'}) \
|
||||||
.AndReturn([[], False])
|
.AndReturn([[], False])
|
||||||
|
cinder.extension_supported(IsA(http.HttpRequest), 'AvailabilityZones')\
|
||||||
|
.AndReturn(True)
|
||||||
|
cinder.availability_zone_list(IsA(http.HttpRequest)).AndReturn(
|
||||||
|
self.cinder_availability_zones.list())
|
||||||
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
quotas.tenant_limit_usages(IsA(http.HttpRequest)).\
|
||||||
AndReturn(usage_limit)
|
AndReturn(usage_limit)
|
||||||
|
|
||||||
|
@ -12,7 +12,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from cinderclient.v1 import availability_zones
|
||||||
from cinderclient.v1 import quotas
|
from cinderclient.v1 import quotas
|
||||||
|
|
||||||
from openstack_dashboard.api import base
|
from openstack_dashboard.api import base
|
||||||
from openstack_dashboard.usage import quotas as usage_quotas
|
from openstack_dashboard.usage import quotas as usage_quotas
|
||||||
|
|
||||||
@ -22,6 +24,7 @@ from openstack_dashboard.test.test_data import utils
|
|||||||
def data(TEST):
|
def data(TEST):
|
||||||
TEST.cinder_quotas = utils.TestDataContainer()
|
TEST.cinder_quotas = utils.TestDataContainer()
|
||||||
TEST.cinder_quota_usages = utils.TestDataContainer()
|
TEST.cinder_quota_usages = utils.TestDataContainer()
|
||||||
|
TEST.cinder_availability_zones = utils.TestDataContainer()
|
||||||
|
|
||||||
# Quota Sets
|
# Quota Sets
|
||||||
quota_data = dict(volumes='1',
|
quota_data = dict(volumes='1',
|
||||||
@ -44,3 +47,18 @@ def data(TEST):
|
|||||||
quota_usage.tally(k, v['used'])
|
quota_usage.tally(k, v['used'])
|
||||||
|
|
||||||
TEST.cinder_quota_usages.add(quota_usage)
|
TEST.cinder_quota_usages.add(quota_usage)
|
||||||
|
|
||||||
|
# Availability Zones
|
||||||
|
# Cinder returns the following structure from os-availability-zone
|
||||||
|
# {"availabilityZoneInfo":
|
||||||
|
# [{"zoneState": {"available": true}, "zoneName": "nova"}]}
|
||||||
|
# Note that the default zone is still "nova" even though this is cinder
|
||||||
|
TEST.cinder_availability_zones.add(
|
||||||
|
availability_zones.AvailabilityZone(
|
||||||
|
availability_zones.AvailabilityZoneManager(None),
|
||||||
|
{
|
||||||
|
'zoneName': 'nova',
|
||||||
|
'zoneState': {'available': True}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user