Merge "Add validation for cinder volume"

This commit is contained in:
Jenkins 2015-05-14 15:50:00 +00:00 committed by Gerrit Code Review
commit 27dec537fd
2 changed files with 118 additions and 9 deletions

View File

@ -353,6 +353,49 @@ class CinderVolume(vb.BaseVolume):
def check_delete_snapshot_complete(self, delete_task):
return delete_task.step()
def _build_exclusive_options(self):
exclusive_options = []
if self.properties.get(self.SNAPSHOT_ID):
exclusive_options.append(self.SNAPSHOT_ID)
if self.properties.get(self.SOURCE_VOLID):
exclusive_options.append(self.SOURCE_VOLID)
if self.properties.get(self.IMAGE):
exclusive_options.append(self.IMAGE)
if self.properties.get(self.IMAGE_REF):
exclusive_options.append(self.IMAGE_REF)
return exclusive_options
def _validate_create_sources(self):
exclusive_options = self._build_exclusive_options()
size = self.properties.get(self.SIZE)
if not size and len(exclusive_options) != 1:
msg = (_('If neither "%(backup_id)s" nor "%(size)s" is '
'specified, you should specify only one of '
'"%(image)s/%(image_ref)s", "%(source_vol)s" '
'or "%(snapshot_id)s", but currently specified '
'options: %(exclusive_options)s.')
% {'backup_id': self.BACKUP_ID,
'size': self.SIZE,
'image': self.IMAGE,
'image_ref': self.IMAGE_REF,
'source_vol': self.SOURCE_VOLID,
'snapshot_id': self.SNAPSHOT_ID,
'exclusive_options': exclusive_options})
raise exception.StackValidationFailed(message=msg)
elif size and len(exclusive_options) > 1:
msg = (_('If "%(backup_id)s" is not specified, you can specify '
'"%(size)s" or/and one of "%(image)s/%(image_ref)s", '
'"%(source_vol)s" or "%(snapshot_id)s", but currently '
'specified options: %(exclusive_options)s.')
% {'backup_id': self.BACKUP_ID,
'size': self.SIZE,
'image': self.IMAGE,
'image_ref': self.IMAGE_REF,
'source_vol': self.SOURCE_VOLID,
'snapshot_id': self.SNAPSHOT_ID,
'exclusive_options': exclusive_options})
raise exception.StackValidationFailed(message=msg)
def validate(self):
"""Validate provided params."""
res = super(CinderVolume, self).validate()
@ -365,6 +408,15 @@ class CinderVolume(vb.BaseVolume):
raise exception.StackValidationFailed(
message=_('Scheduler hints are not supported by the current '
'volume API.'))
# can not specify both image and imageRef
image = self.properties.get(self.IMAGE)
imageRef = self.properties.get(self.IMAGE_REF)
if image and imageRef:
raise exception.ResourcePropertyConflict(self.IMAGE,
self.IMAGE_REF)
# if not create from backup, need to check other create sources
if not self.properties.get(self.BACKUP_ID):
self._validate_create_sources()
def handle_restore(self, defn, restore_data):
backup_id = restore_data['resource_data']['backup_id']

View File

@ -119,10 +119,7 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
size=1, availability_zone='nova',
description='test_description',
name='test_name',
imageRef='46988116-6703-4623-9dbc-2bc6d284021b',
snapshot_id='snap-123',
metadata={'key': 'value'},
source_volid='vol-012',
volume_type='lvm').AndReturn(fv)
self.cinder_fc.volumes.get(fv.id).AndReturn(fv)
fv_ready = vt_base.FakeVolume('available', id=fv.id)
@ -132,12 +129,6 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
self.t['resources']['volume']['properties'].update({
'volume_type': 'lvm',
# Note that specifying all these arguments doesn't work in
# practice, as they are conflicting, but we just want to check they
# are sent to the backend.
'imageRef': '46988116-6703-4623-9dbc-2bc6d284021b',
'snapshot_id': 'snap-123',
'source_volid': 'vol-012',
})
stack = utils.parse_stack(self.t, stack_name=stack_name)
self.create_volume(self.t, stack, 'volume')
@ -894,6 +885,72 @@ class CinderVolumeTest(vt_base.BaseVolumeTest):
'volume API.', six.text_type(ex))
self.m.VerifyAll()
def test_cinder_create_with_image_and_imageRef(self):
stack_name = 'test_create_with_size_snapshot_and_image'
stack = utils.parse_stack(self.t, stack_name=stack_name)
vp = stack.t['Resources']['volume2']['Properties']
vp['imageRef'] = 'image-456'
vp['image'] = 'image-123'
vp.pop('size')
rsrc = stack['volume2']
self.stub_ImageConstraint_validate()
ex = self.assertRaises(exception.ResourcePropertyConflict,
rsrc.validate)
self.assertEqual("Cannot define the following properties at the same "
"time: image, imageRef.",
six.text_type(ex))
def test_cinder_create_with_size_snapshot_and_image(self):
stack_name = 'test_create_with_size_snapshot_and_image'
stack = utils.parse_stack(self.t, stack_name=stack_name)
vp = stack.t['Resources']['volume2']['Properties']
vp['snapshot_id'] = 'snapshot-123'
vp['image'] = 'image-123'
rsrc = stack['volume2']
self.stub_ImageConstraint_validate()
self.stub_SnapshotConstraint_validate()
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertIn('If "backup_id" is not specified, you can specify '
'"size" or/and one of "image/imageRef", '
'"source_volid" or "snapshot_id", but currently '
'specified options: [\'snapshot_id\', \'image\']',
six.text_type(ex))
def test_cinder_create_with_snapshot_and_source_volume(self):
stack_name = 'test_create_with_snapshot_and_source_volume'
stack = utils.parse_stack(self.t, stack_name=stack_name)
vp = stack.t['Resources']['volume2']['Properties']
vp['snapshot_id'] = 'snapshot-123'
vp['source_volid'] = 'source_volume-123'
vp.pop('size')
rsrc = stack['volume2']
self.stub_VolumeConstraint_validate()
self.stub_SnapshotConstraint_validate()
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertIn('If neither "backup_id" nor "size" is specified, you '
'should specify only one of "image/imageRef", '
'"source_volid" or "snapshot_id", but currently '
'specified options: [\'snapshot_id\', \'source_volid\']',
six.text_type(ex))
def test_cinder_create_no_size_no_options(self):
stack_name = 'test_create_no_size_no_options'
stack = utils.parse_stack(self.t, stack_name=stack_name)
vp = stack.t['Resources']['volume2']['Properties']
vp.pop('size')
rsrc = stack['volume2']
self.stub_VolumeConstraint_validate()
self.stub_SnapshotConstraint_validate()
ex = self.assertRaises(exception.StackValidationFailed,
rsrc.validate)
self.assertIn('If neither "backup_id" nor "size" is specified, you '
'should specify only one of "image/imageRef", '
'"source_volid" or "snapshot_id", but currently '
'specified options: []',
six.text_type(ex))
def test_volume_restore(self):
stack_name = 'test_cvolume_restore_stack'