@staticmethod
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."""
vol = {}
vol['size'] = size
vol['source_volid'] = source_volid
vol['user_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['attach_status'] = "detached"
vol['host'] = CONF.host
description='fake_desc',
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):
"""Test volume create with multiple exclusive options fails."""
volume_api = cinder.volume.api.API()
self.volume.delete_volume(self.context, volume_dst['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):
"""Test glance metadata can be correctly copied to new volume."""
def fake_create_cloned_volume(volume, src_vref):
default=True,
help='Create volume from snapshot at the host '
'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.register_opt(volume_host_opt)
+CONF.register_opt(volume_same_az_opt)
CONF.import_opt('storage_availability_zone', 'cinder.volume.manager')
LOG = logging.getLogger(__name__)
msg = _('Image minDisk size is larger than the volume size.')
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:
volume_type = volume_types.get_default_volume_type()
'd_consumed': _consumed(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)
options = {'size': size,
'user_id': context.user_id,