Merge "Create volume from snapshot must be in the same AZ as snapshot"
This commit is contained in:
commit
9f0bb808b8
@ -89,7 +89,8 @@ class VolumeTestCase(test.TestCase):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _create_volume(size=0, snapshot_id=None, image_id=None,
|
def _create_volume(size=0, snapshot_id=None, image_id=None,
|
||||||
source_volid=None, metadata=None, status="creating"):
|
source_volid=None, metadata=None, status="creating",
|
||||||
|
availability_zone=None):
|
||||||
"""Create a volume object."""
|
"""Create a volume object."""
|
||||||
vol = {}
|
vol = {}
|
||||||
vol['size'] = size
|
vol['size'] = size
|
||||||
@ -98,7 +99,8 @@ class VolumeTestCase(test.TestCase):
|
|||||||
vol['source_volid'] = source_volid
|
vol['source_volid'] = source_volid
|
||||||
vol['user_id'] = 'fake'
|
vol['user_id'] = 'fake'
|
||||||
vol['project_id'] = 'fake'
|
vol['project_id'] = 'fake'
|
||||||
vol['availability_zone'] = CONF.storage_availability_zone
|
vol['availability_zone'] = \
|
||||||
|
availability_zone or CONF.storage_availability_zone
|
||||||
vol['status'] = status
|
vol['status'] = status
|
||||||
vol['attach_status'] = "detached"
|
vol['attach_status'] = "detached"
|
||||||
vol['host'] = CONF.host
|
vol['host'] = CONF.host
|
||||||
@ -353,6 +355,41 @@ class VolumeTestCase(test.TestCase):
|
|||||||
description='fake_desc',
|
description='fake_desc',
|
||||||
snapshot=snapshot)
|
snapshot=snapshot)
|
||||||
|
|
||||||
|
def test_create_volume_from_snapshot_fail_wrong_az(self):
|
||||||
|
"""Test volume can't be created from snapshot in a different az."""
|
||||||
|
volume_api = cinder.volume.api.API()
|
||||||
|
|
||||||
|
def fake_list_availability_zones():
|
||||||
|
return ({'name': 'nova', 'available': True},
|
||||||
|
{'name': 'az2', 'available': True})
|
||||||
|
|
||||||
|
self.stubs.Set(volume_api,
|
||||||
|
'list_availability_zones',
|
||||||
|
fake_list_availability_zones)
|
||||||
|
|
||||||
|
volume_src = self._create_volume(availability_zone='az2')
|
||||||
|
self.volume.create_volume(self.context, volume_src['id'])
|
||||||
|
snapshot = self._create_snapshot(volume_src['id'])
|
||||||
|
self.volume.create_snapshot(self.context, volume_src['id'],
|
||||||
|
snapshot['id'])
|
||||||
|
snapshot = db.snapshot_get(self.context, snapshot['id'])
|
||||||
|
|
||||||
|
volume_dst = volume_api.create(self.context,
|
||||||
|
size=1,
|
||||||
|
name='fake_name',
|
||||||
|
description='fake_desc',
|
||||||
|
snapshot=snapshot)
|
||||||
|
self.assertEqual(volume_dst['availability_zone'], 'az2')
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
volume_api.create,
|
||||||
|
self.context,
|
||||||
|
size=1,
|
||||||
|
name='fake_name',
|
||||||
|
description='fake_desc',
|
||||||
|
snapshot=snapshot,
|
||||||
|
availability_zone='nova')
|
||||||
|
|
||||||
def test_create_volume_with_invalid_exclusive_options(self):
|
def test_create_volume_with_invalid_exclusive_options(self):
|
||||||
"""Test volume create with multiple exclusive options fails."""
|
"""Test volume create with multiple exclusive options fails."""
|
||||||
volume_api = cinder.volume.api.API()
|
volume_api = cinder.volume.api.API()
|
||||||
@ -1394,6 +1431,39 @@ class VolumeTestCase(test.TestCase):
|
|||||||
self.volume.delete_volume(self.context, volume_dst['id'])
|
self.volume.delete_volume(self.context, volume_dst['id'])
|
||||||
self.volume.delete_volume(self.context, volume_src['id'])
|
self.volume.delete_volume(self.context, volume_src['id'])
|
||||||
|
|
||||||
|
def test_create_volume_from_sourcevol_fail_wrong_az(self):
|
||||||
|
"""Test volume can't be cloned from an other volume in different az."""
|
||||||
|
volume_api = cinder.volume.api.API()
|
||||||
|
|
||||||
|
def fake_list_availability_zones():
|
||||||
|
return ({'name': 'nova', 'available': True},
|
||||||
|
{'name': 'az2', 'available': True})
|
||||||
|
|
||||||
|
self.stubs.Set(volume_api,
|
||||||
|
'list_availability_zones',
|
||||||
|
fake_list_availability_zones)
|
||||||
|
|
||||||
|
volume_src = self._create_volume(availability_zone='az2')
|
||||||
|
self.volume.create_volume(self.context, volume_src['id'])
|
||||||
|
|
||||||
|
volume_src = db.volume_get(self.context, volume_src['id'])
|
||||||
|
|
||||||
|
volume_dst = volume_api.create(self.context,
|
||||||
|
size=1,
|
||||||
|
name='fake_name',
|
||||||
|
description='fake_desc',
|
||||||
|
source_volume=volume_src)
|
||||||
|
self.assertEqual(volume_dst['availability_zone'], 'az2')
|
||||||
|
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
volume_api.create,
|
||||||
|
self.context,
|
||||||
|
size=1,
|
||||||
|
name='fake_name',
|
||||||
|
description='fake_desc',
|
||||||
|
source_volume=volume_src,
|
||||||
|
availability_zone='nova')
|
||||||
|
|
||||||
def test_create_volume_from_sourcevol_with_glance_metadata(self):
|
def test_create_volume_from_sourcevol_with_glance_metadata(self):
|
||||||
"""Test glance metadata can be correctly copied to new volume."""
|
"""Test glance metadata can be correctly copied to new volume."""
|
||||||
def fake_create_cloned_volume(volume, src_vref):
|
def fake_create_cloned_volume(volume, src_vref):
|
||||||
|
@ -45,9 +45,14 @@ volume_host_opt = cfg.BoolOpt('snapshot_same_host',
|
|||||||
default=True,
|
default=True,
|
||||||
help='Create volume from snapshot at the host '
|
help='Create volume from snapshot at the host '
|
||||||
'where snapshot resides')
|
'where snapshot resides')
|
||||||
|
volume_same_az_opt = cfg.BoolOpt('cloned_volume_same_az',
|
||||||
|
default=True,
|
||||||
|
help='Ensure that the new volumes are the '
|
||||||
|
'same AZ as snapshot or source volume')
|
||||||
|
|
||||||
CONF = cfg.CONF
|
CONF = cfg.CONF
|
||||||
CONF.register_opt(volume_host_opt)
|
CONF.register_opt(volume_host_opt)
|
||||||
|
CONF.register_opt(volume_same_az_opt)
|
||||||
CONF.import_opt('storage_availability_zone', 'cinder.volume.manager')
|
CONF.import_opt('storage_availability_zone', 'cinder.volume.manager')
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -160,6 +165,29 @@ class API(base.Base):
|
|||||||
msg = _('Image minDisk size is larger than the volume size.')
|
msg = _('Image minDisk size is larger than the volume size.')
|
||||||
raise exception.InvalidInput(reason=msg)
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
|
if availability_zone is None:
|
||||||
|
if snapshot is not None:
|
||||||
|
availability_zone = snapshot['volume']['availability_zone']
|
||||||
|
elif source_volume is not None:
|
||||||
|
availability_zone = source_volume['availability_zone']
|
||||||
|
else:
|
||||||
|
availability_zone = CONF.storage_availability_zone
|
||||||
|
else:
|
||||||
|
self._check_availabilty_zone(availability_zone)
|
||||||
|
|
||||||
|
if CONF.cloned_volume_same_az:
|
||||||
|
if (snapshot and
|
||||||
|
snapshot['volume']['availability_zone'] !=
|
||||||
|
availability_zone):
|
||||||
|
msg = _("Volume must be in the same "
|
||||||
|
"availability zone as the snapshot")
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
elif source_volume and \
|
||||||
|
source_volume['availability_zone'] != availability_zone:
|
||||||
|
msg = _("Volume must be in the same "
|
||||||
|
"availability zone as the source volume")
|
||||||
|
raise exception.InvalidInput(reason=msg)
|
||||||
|
|
||||||
if not volume_type and not source_volume:
|
if not volume_type and not source_volume:
|
||||||
volume_type = volume_types.get_default_volume_type()
|
volume_type = volume_types.get_default_volume_type()
|
||||||
|
|
||||||
@ -198,11 +226,6 @@ class API(base.Base):
|
|||||||
'd_consumed': _consumed(over)})
|
'd_consumed': _consumed(over)})
|
||||||
raise exception.VolumeLimitExceeded(allowed=quotas[over])
|
raise exception.VolumeLimitExceeded(allowed=quotas[over])
|
||||||
|
|
||||||
if availability_zone is None:
|
|
||||||
availability_zone = CONF.storage_availability_zone
|
|
||||||
else:
|
|
||||||
self._check_availabilty_zone(availability_zone)
|
|
||||||
|
|
||||||
self._check_metadata_properties(context, metadata)
|
self._check_metadata_properties(context, metadata)
|
||||||
options = {'size': size,
|
options = {'size': size,
|
||||||
'user_id': context.user_id,
|
'user_id': context.user_id,
|
||||||
|
Loading…
Reference in New Issue
Block a user