diff --git a/cinder/tests/unit/test_hitachi_hbsd_horcm_fc.py b/cinder/tests/unit/test_hitachi_hbsd_horcm_fc.py index d2e419e5237..d8117d7747d 100644 --- a/cinder/tests/unit/test_hitachi_hbsd_horcm_fc.py +++ b/cinder/tests/unit/test_hitachi_hbsd_horcm_fc.py @@ -444,6 +444,10 @@ STS : NML" 'id': 'test-volume', 'provider_location': '1', 'status': 'available'} + test_volume_larger = {'name': 'test_volume', 'size': 256, + 'id': 'test-volume', + 'provider_location': '1', 'status': 'available'} + test_volume_error = {'name': 'test_volume', 'size': 256, 'id': 'test-volume', 'status': 'creating'} @@ -752,6 +756,28 @@ STS : NML" self.assertEqual('1', vol['provider_location']) return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', + return_value={'dummy_volume_meta': 'meta'}) + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', + return_value=_VOLUME) + @mock.patch.object(hbsd_common.HBSDCommon, 'extend_volume') + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'exec_raidcom', + side_effect=_exec_raidcom) + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'start_horcm', + return_value=[0, "", ""]) + @mock.patch.object(hbsd_horcm.HBSDHORCM, 'check_horcm', + return_value=[0, "", ""]) + def test_create_cloned_volume_larger_size(self, arg1, arg2, arg3, arg4, + arg5, arg6, arg7): + """test create_cloned_volume.""" + vol = self.driver.create_cloned_volume(self.test_volume_larger, + self._VOLUME) + self.assertEqual('1', vol['provider_location']) + arg5.assert_called_once_with(self.test_volume_larger, + self.test_volume_larger['size']) + return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', return_value={'dummy_volume_meta': 'meta'}) @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', diff --git a/cinder/tests/unit/test_hitachi_hbsd_snm2_fc.py b/cinder/tests/unit/test_hitachi_hbsd_snm2_fc.py index f03ce356e80..147d6ba33de 100644 --- a/cinder/tests/unit/test_hitachi_hbsd_snm2_fc.py +++ b/cinder/tests/unit/test_hitachi_hbsd_snm2_fc.py @@ -196,6 +196,10 @@ Host Group\n abcdefg 10000000C97BCE7A \ 'id': 'test-volume-0', 'provider_location': '1', 'status': 'available'} + test_volume_larger = {'name': 'test_volume', 'size': 256, + 'id': 'test-volume-0', + 'provider_location': '1', 'status': 'available'} + test_volume_error = {'name': 'test_volume_error', 'size': 256, 'id': 'test-volume-error', 'provider_location': '3', 'status': 'available'} @@ -415,6 +419,22 @@ Host Group\n abcdefg 10000000C97BCE7A \ self.assertIsNotNone(vol) return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', + return_value={'dummy_volume_meta': 'meta'}) + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', + return_value=_VOLUME) + @mock.patch.object(hbsd_common.HBSDCommon, 'extend_volume') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + def test_create_cloned_volume_larger(self, arg1, arg2, arg3, arg4, arg5): + """test create_cloned_volume.""" + vol = self.driver.create_cloned_volume(self.test_volume_larger, + self._VOLUME) + self.assertIsNotNone(vol) + arg3.assert_called_once_with(self.test_volume_larger, + self.test_volume_larger['size']) + return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', return_value={'dummy_volume_meta': 'meta'}) @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', diff --git a/cinder/tests/unit/test_hitachi_hbsd_snm2_iscsi.py b/cinder/tests/unit/test_hitachi_hbsd_snm2_iscsi.py index 3184a7c5af7..28d64e3f951 100644 --- a/cinder/tests/unit/test_hitachi_hbsd_snm2_iscsi.py +++ b/cinder/tests/unit/test_hitachi_hbsd_snm2_iscsi.py @@ -212,6 +212,10 @@ Authentication\n\ 'id': 'test-volume-0', 'provider_location': '1', 'status': 'available'} + test_volume_larger = {'name': 'test_volume', 'size': 256, + 'id': 'test-volume-0', + 'provider_location': '1', 'status': 'available'} + test_volume_error = {'name': 'test_volume_error', 'size': 256, 'id': 'test-volume-error', 'provider_location': '3', 'status': 'available'} @@ -450,6 +454,22 @@ Authentication\n\ self.assertIsNotNone(vol) return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', + return_value={'dummy_volume_meta': 'meta'}) + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', + return_value=_VOLUME) + @mock.patch.object(hbsd_common.HBSDCommon, 'extend_volume') + @mock.patch.object(hbsd_snm2.HBSDSNM2, 'exec_hsnm', side_effect=_exec_hsnm) + @mock.patch.object(hbsd_basiclib, 'get_process_lock') + def test_create_cloned_volume_larger(self, arg1, arg2, arg3, arg4, arg5): + """test create_cloned_volume.""" + vol = self.driver.create_cloned_volume(self.test_volume_larger, + self._VOLUME) + self.assertIsNotNone(vol) + arg3.assert_called_once_with(self.test_volume_larger, + self.test_volume_larger['size']) + return + @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata', return_value={'dummy_volume_meta': 'meta'}) @mock.patch.object(hbsd_common.HBSDCommon, 'get_volume', diff --git a/cinder/tests/unit/test_hitachi_hnas_iscsi.py b/cinder/tests/unit/test_hitachi_hnas_iscsi.py index b980bd508a6..a2a690f7184 100644 --- a/cinder/tests/unit/test_hitachi_hnas_iscsi.py +++ b/cinder/tests/unit/test_hitachi_hnas_iscsi.py @@ -388,6 +388,25 @@ class HNASiSCSIDriverTest(test.TestCase): self.backend.deleteVolumebyProvider(src_vol['provider_location']) self.backend.deleteVolumebyProvider(loc['provider_location']) + @mock.patch.object(iscsi.HDSISCSIDriver, '_id_to_vol') + @mock.patch.object(iscsi.HDSISCSIDriver, 'extend_volume') + def test_create_clone_larger_size(self, m_extend_volume, m_id_to_vol): + + src_vol = self._create_volume() + m_id_to_vol.return_value = src_vol + src_vol['volume_size'] = src_vol['size'] + + dst_vol = self._create_volume() + dst_vol['size'] = 256 + dst_vol['volume_size'] = dst_vol['size'] + + loc = self.driver.create_cloned_volume(dst_vol, src_vol) + self.assertNotEqual(loc, None) + m_extend_volume.assert_called_once_with(dst_vol, 256) + # cleanup + self.backend.deleteVolumebyProvider(src_vol['provider_location']) + self.backend.deleteVolumebyProvider(loc['provider_location']) + @mock.patch.object(iscsi.HDSISCSIDriver, '_id_to_vol') def test_delete_snapshot(self, m_id_to_vol): svol = self._create_volume() diff --git a/cinder/tests/unit/test_hitachi_hnas_nfs.py b/cinder/tests/unit/test_hitachi_hnas_nfs.py index 03165cc72ce..d67e2849a5c 100644 --- a/cinder/tests/unit/test_hitachi_hnas_nfs.py +++ b/cinder/tests/unit/test_hitachi_hnas_nfs.py @@ -335,6 +335,30 @@ class HDSNFSDriverTest(test.TestCase): out = "{'provider_location': \'" + _SHARE + "'}" self.assertEqual(out, str(loc)) + @mock.patch.object(nfs.HDSNFSDriver, '_get_service') + @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol) + @mock.patch.object(nfs.HDSNFSDriver, '_get_provider_location') + @mock.patch.object(nfs.HDSNFSDriver, '_get_volume_location') + @mock.patch.object(nfs.HDSNFSDriver, 'extend_volume') + def test_create_cloned_volume_larger(self, m_extend_volume, + m_get_volume_location, + m_get_provider_location, + m_id_to_vol, m_get_service): + vol = _VOLUME.copy() + svol = _SNAPVOLUME.copy() + + m_get_service.return_value = _SERVICE + m_get_provider_location.return_value = _SHARE + m_get_volume_location.return_value = _SHARE + + svol['size'] = 256 + + loc = self.driver.create_cloned_volume(svol, vol) + + out = "{'provider_location': \'" + _SHARE + "'}" + self.assertEqual(out, str(loc)) + m_extend_volume.assert_called_once_with(svol, svol['size']) + @mock.patch.object(nfs.HDSNFSDriver, '_ensure_shares_mounted') @mock.patch.object(nfs.HDSNFSDriver, '_do_create_volume') @mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol) diff --git a/cinder/volume/drivers/hitachi/hbsd_common.py b/cinder/volume/drivers/hitachi/hbsd_common.py index d93a50c2254..15a03a1652d 100644 --- a/cinder/volume/drivers/hitachi/hbsd_common.py +++ b/cinder/volume/drivers/hitachi/hbsd_common.py @@ -644,7 +644,7 @@ class HBSDCommon(object): self.check_volume_status(self.get_volume(src_vref['id']), is_vvol) size = volume['size'] src_size = src_vref['size'] - if size != src_size: + if size < src_size: msg = basic_lib.output_err(617, type='volume', volume_id=volume['id']) raise exception.HBSDError(message=msg) @@ -652,7 +652,10 @@ class HBSDCommon(object): metadata = self.get_volume_metadata(volume['id']) method = None if is_vvol else self.get_copy_method(volume) - svol, type = self.copy_data(pvol, size, is_vvol, method) + svol, type = self.copy_data(pvol, src_size, is_vvol, method) + + if size > src_size: + self.extend_volume(volume, size) metadata['type'] = type metadata['volume'] = src_vref['id'] diff --git a/cinder/volume/drivers/hitachi/hnas_iscsi.py b/cinder/volume/drivers/hitachi/hnas_iscsi.py index 418e9450df3..c31688d67af 100644 --- a/cinder/volume/drivers/hitachi/hnas_iscsi.py +++ b/cinder/volume/drivers/hitachi/hnas_iscsi.py @@ -579,9 +579,10 @@ class HDSISCSIDriver(driver.ISCSIDriver): :param src: ditctionary source volume reference """ - if src['size'] != dst['size']: - msg = 'clone volume size mismatch' + if src['size'] > dst['size']: + msg = 'Clone volume size must not be smaller than source volume' raise exception.VolumeBackendAPIException(data=msg) + hdp = self._get_service(dst) size = int(src['size']) * units.Ki source_vol = self._id_to_vol(src['id']) @@ -594,7 +595,12 @@ class HDSISCSIDriver(driver.ISCSIDriver): dst['name']) lun = self.arid + '.' + out.split()[1] - size = int(out.split()[5]) + + if src['size'] < dst['size']: + size = dst['size'] + self.extend_volume(dst, size) + else: + size = int(out.split()[5]) LOG.debug("LUN %(lun)s of size %(size)s MB is cloned.", {'lun': lun, 'size': size}) diff --git a/cinder/volume/drivers/hitachi/hnas_nfs.py b/cinder/volume/drivers/hitachi/hnas_nfs.py index e13e085ea1b..bfe343ad3f3 100644 --- a/cinder/volume/drivers/hitachi/hnas_nfs.py +++ b/cinder/volume/drivers/hitachi/hnas_nfs.py @@ -401,13 +401,17 @@ class HDSNFSDriver(nfs.NfsDriver): vol_size = volume['size'] src_vol_size = src_vref['size'] - if vol_size != src_vol_size: + if vol_size < src_vol_size: msg = _("Cannot create clone of size %(vol_size)s from " "volume of size %(src_vol_size)s") msg_fmt = {'vol_size': vol_size, 'src_vol_size': src_vol_size} raise exception.CinderException(msg % msg_fmt) self._clone_volume(src_vref['name'], volume['name'], src_vref['id']) + + if vol_size > src_vol_size: + self.extend_volume(volume, vol_size) + share = self._get_volume_location(src_vref['id']) return {'provider_location': share}