diff --git a/heat/engine/resources/openstack/cinder/volume.py b/heat/engine/resources/openstack/cinder/volume.py index 0091a47664..16b852883c 100644 --- a/heat/engine/resources/openstack/cinder/volume.py +++ b/heat/engine/resources/openstack/cinder/volume.py @@ -68,7 +68,12 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin): SIZE: properties.Schema( properties.Schema.INTEGER, _('The size of the volume in GB. ' - 'On update only increase in size is supported.'), + 'On update only increase in size is supported. This property ' + 'is required unless property %(backup)s or %(vol)s or ' + '%(snapshot)s is specified.') + % dict(backup=BACKUP_ID, + vol=SOURCE_VOLID, + snapshot=SNAPSHOT_ID), update_allowed=True, constraints=[ constraints.Range(min=1), @@ -553,29 +558,30 @@ class CinderVolume(vb.BaseVolume, sh.SchedulerHintsMixin): def _build_exclusive_options(self): exclusive_options = [] + allow_no_size_options = [] if self.properties.get(self.SNAPSHOT_ID): exclusive_options.append(self.SNAPSHOT_ID) + allow_no_size_options.append(self.SNAPSHOT_ID) if self.properties.get(self.SOURCE_VOLID): exclusive_options.append(self.SOURCE_VOLID) + allow_no_size_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 + return exclusive_options, allow_no_size_options def _validate_create_sources(self): - exclusive_options = self._build_exclusive_options() + exclusive_options, allow_no_size_ops = self._build_exclusive_options() size = self.properties.get(self.SIZE) - if size is None and len(exclusive_options) != 1: + if (size is None and + (len(allow_no_size_ops) != 1 or len(exclusive_options) != 1)): msg = (_('If neither "%(backup_id)s" nor "%(size)s" is ' - 'provided, one and only one of ' - '"%(image)s", "%(image_ref)s", "%(source_vol)s", ' + 'provided, one and only one of "%(source_vol)s", ' '"%(snapshot_id)s" must be specified, 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}) diff --git a/heat/tests/openstack/cinder/test_volume.py b/heat/tests/openstack/cinder/test_volume.py index 00aabc95d5..9edb650226 100644 --- a/heat/tests/openstack/cinder/test_volume.py +++ b/heat/tests/openstack/cinder/test_volume.py @@ -1072,6 +1072,18 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): stack.get, 'volume2') self.assertEqual(err_msg, six.text_type(ex)) + def test_cinder_create_with_image_and_size(self): + stack_name = 'test_create_with_image_and_size' + combinations = {'image': 'image-123'} + err_msg = ('If neither "backup_id" nor "size" is provided, one and ' + 'only one of "source_volid", "snapshot_id" must be ' + 'specified, but currently ' + 'specified options: [\'image\'].') + self.stub_ImageConstraint_validate() + self._test_cinder_create_invalid_property_combinations( + stack_name, combinations, + err_msg, exception.StackValidationFailed) + def test_cinder_create_with_size_snapshot_and_image(self): stack_name = 'test_create_with_size_snapshot_and_image' combinations = { @@ -1127,8 +1139,8 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): 'source_volid': 'source_volume-123', 'snapshot_id': 'snapshot-123'} err_msg = ('If neither "backup_id" nor "size" is provided, one and ' - 'only one of "image", "imageRef", "source_volid", ' - '"snapshot_id" must be specified, but currently ' + 'only one of "source_volid", "snapshot_id" must be ' + 'specified, but currently ' 'specified options: [\'snapshot_id\', \'source_volid\'].') self.stub_VolumeConstraint_validate() self.stub_SnapshotConstraint_validate() @@ -1142,8 +1154,8 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): 'source_volid': 'source_volume-123', 'image': 'image-123'} err_msg = ('If neither "backup_id" nor "size" is provided, one and ' - 'only one of "image", "imageRef", "source_volid", ' - '"snapshot_id" must be specified, but currently ' + 'only one of "source_volid", "snapshot_id" must be ' + 'specified, but currently ' 'specified options: [\'source_volid\', \'image\'].') self.stub_VolumeConstraint_validate() self.stub_ImageConstraint_validate() @@ -1155,9 +1167,8 @@ class CinderVolumeTest(vt_base.BaseVolumeTest): stack_name = 'test_create_no_size_no_options' combinations = {} err_msg = ('If neither "backup_id" nor "size" is provided, one and ' - 'only one of "image", "imageRef", "source_volid", ' - '"snapshot_id" must be specified, but currently ' - 'specified options: [].') + 'only one of "source_volid", "snapshot_id" must be ' + 'specified, but currently specified options: [].') self._test_cinder_create_invalid_property_combinations( stack_name, combinations, err_msg, exception.StackValidationFailed)