Hitachi drivers: resize volume if cloned image is larger
Extend volume if during create_volume_from_snapshot() the new volume is larger than the image it was cloned from. Extended test cases to cover the change. Closes-Bug: #1554779 Change-Id: I001d40e9aaa15dfa98230a1b6902b1d24931c9af Signed-off-by: Danny Al-Gaaf <danny.al-gaaf@bisect.de>
This commit is contained in:
parent
fd5817881a
commit
dbf7495f51
|
@ -444,6 +444,10 @@ STS : NML"
|
||||||
'id': 'test-volume',
|
'id': 'test-volume',
|
||||||
'provider_location': '1', 'status': 'available'}
|
'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,
|
test_volume_error = {'name': 'test_volume', 'size': 256,
|
||||||
'id': 'test-volume',
|
'id': 'test-volume',
|
||||||
'status': 'creating'}
|
'status': 'creating'}
|
||||||
|
@ -752,6 +756,28 @@ STS : NML"
|
||||||
self.assertEqual('1', vol['provider_location'])
|
self.assertEqual('1', vol['provider_location'])
|
||||||
return
|
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',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata',
|
||||||
return_value={'dummy_volume_meta': 'meta'})
|
return_value={'dummy_volume_meta': 'meta'})
|
||||||
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
||||||
|
|
|
@ -196,6 +196,10 @@ Host Group\n abcdefg 10000000C97BCE7A \
|
||||||
'id': 'test-volume-0',
|
'id': 'test-volume-0',
|
||||||
'provider_location': '1', 'status': 'available'}
|
'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,
|
test_volume_error = {'name': 'test_volume_error', 'size': 256,
|
||||||
'id': 'test-volume-error',
|
'id': 'test-volume-error',
|
||||||
'provider_location': '3', 'status': 'available'}
|
'provider_location': '3', 'status': 'available'}
|
||||||
|
@ -415,6 +419,22 @@ Host Group\n abcdefg 10000000C97BCE7A \
|
||||||
self.assertIsNotNone(vol)
|
self.assertIsNotNone(vol)
|
||||||
return
|
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',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata',
|
||||||
return_value={'dummy_volume_meta': 'meta'})
|
return_value={'dummy_volume_meta': 'meta'})
|
||||||
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
||||||
|
|
|
@ -212,6 +212,10 @@ Authentication\n\
|
||||||
'id': 'test-volume-0',
|
'id': 'test-volume-0',
|
||||||
'provider_location': '1', 'status': 'available'}
|
'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,
|
test_volume_error = {'name': 'test_volume_error', 'size': 256,
|
||||||
'id': 'test-volume-error',
|
'id': 'test-volume-error',
|
||||||
'provider_location': '3', 'status': 'available'}
|
'provider_location': '3', 'status': 'available'}
|
||||||
|
@ -450,6 +454,22 @@ Authentication\n\
|
||||||
self.assertIsNotNone(vol)
|
self.assertIsNotNone(vol)
|
||||||
return
|
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',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume_metadata',
|
||||||
return_value={'dummy_volume_meta': 'meta'})
|
return_value={'dummy_volume_meta': 'meta'})
|
||||||
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
@mock.patch.object(hbsd_common.HBSDCommon, 'get_volume',
|
||||||
|
|
|
@ -388,6 +388,25 @@ class HNASiSCSIDriverTest(test.TestCase):
|
||||||
self.backend.deleteVolumebyProvider(src_vol['provider_location'])
|
self.backend.deleteVolumebyProvider(src_vol['provider_location'])
|
||||||
self.backend.deleteVolumebyProvider(loc['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')
|
@mock.patch.object(iscsi.HDSISCSIDriver, '_id_to_vol')
|
||||||
def test_delete_snapshot(self, m_id_to_vol):
|
def test_delete_snapshot(self, m_id_to_vol):
|
||||||
svol = self._create_volume()
|
svol = self._create_volume()
|
||||||
|
|
|
@ -335,6 +335,30 @@ class HDSNFSDriverTest(test.TestCase):
|
||||||
out = "{'provider_location': \'" + _SHARE + "'}"
|
out = "{'provider_location': \'" + _SHARE + "'}"
|
||||||
self.assertEqual(out, str(loc))
|
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, '_ensure_shares_mounted')
|
||||||
@mock.patch.object(nfs.HDSNFSDriver, '_do_create_volume')
|
@mock.patch.object(nfs.HDSNFSDriver, '_do_create_volume')
|
||||||
@mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol)
|
@mock.patch.object(nfs.HDSNFSDriver, '_id_to_vol', side_effect=id_to_vol)
|
||||||
|
|
|
@ -644,7 +644,7 @@ class HBSDCommon(object):
|
||||||
self.check_volume_status(self.get_volume(src_vref['id']), is_vvol)
|
self.check_volume_status(self.get_volume(src_vref['id']), is_vvol)
|
||||||
size = volume['size']
|
size = volume['size']
|
||||||
src_size = src_vref['size']
|
src_size = src_vref['size']
|
||||||
if size != src_size:
|
if size < src_size:
|
||||||
msg = basic_lib.output_err(617, type='volume',
|
msg = basic_lib.output_err(617, type='volume',
|
||||||
volume_id=volume['id'])
|
volume_id=volume['id'])
|
||||||
raise exception.HBSDError(message=msg)
|
raise exception.HBSDError(message=msg)
|
||||||
|
@ -652,7 +652,10 @@ class HBSDCommon(object):
|
||||||
metadata = self.get_volume_metadata(volume['id'])
|
metadata = self.get_volume_metadata(volume['id'])
|
||||||
method = None if is_vvol else self.get_copy_method(volume)
|
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['type'] = type
|
||||||
metadata['volume'] = src_vref['id']
|
metadata['volume'] = src_vref['id']
|
||||||
|
|
|
@ -579,9 +579,10 @@ class HDSISCSIDriver(driver.ISCSIDriver):
|
||||||
:param src: ditctionary source volume reference
|
:param src: ditctionary source volume reference
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if src['size'] != dst['size']:
|
if src['size'] > dst['size']:
|
||||||
msg = 'clone volume size mismatch'
|
msg = 'Clone volume size must not be smaller than source volume'
|
||||||
raise exception.VolumeBackendAPIException(data=msg)
|
raise exception.VolumeBackendAPIException(data=msg)
|
||||||
|
|
||||||
hdp = self._get_service(dst)
|
hdp = self._get_service(dst)
|
||||||
size = int(src['size']) * units.Ki
|
size = int(src['size']) * units.Ki
|
||||||
source_vol = self._id_to_vol(src['id'])
|
source_vol = self._id_to_vol(src['id'])
|
||||||
|
@ -594,6 +595,11 @@ class HDSISCSIDriver(driver.ISCSIDriver):
|
||||||
dst['name'])
|
dst['name'])
|
||||||
|
|
||||||
lun = self.arid + '.' + out.split()[1]
|
lun = self.arid + '.' + out.split()[1]
|
||||||
|
|
||||||
|
if src['size'] < dst['size']:
|
||||||
|
size = dst['size']
|
||||||
|
self.extend_volume(dst, size)
|
||||||
|
else:
|
||||||
size = int(out.split()[5])
|
size = int(out.split()[5])
|
||||||
|
|
||||||
LOG.debug("LUN %(lun)s of size %(size)s MB is cloned.",
|
LOG.debug("LUN %(lun)s of size %(size)s MB is cloned.",
|
||||||
|
|
|
@ -401,13 +401,17 @@ class HDSNFSDriver(nfs.NfsDriver):
|
||||||
vol_size = volume['size']
|
vol_size = volume['size']
|
||||||
src_vol_size = src_vref['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 "
|
msg = _("Cannot create clone of size %(vol_size)s from "
|
||||||
"volume of size %(src_vol_size)s")
|
"volume of size %(src_vol_size)s")
|
||||||
msg_fmt = {'vol_size': vol_size, 'src_vol_size': src_vol_size}
|
msg_fmt = {'vol_size': vol_size, 'src_vol_size': src_vol_size}
|
||||||
raise exception.CinderException(msg % msg_fmt)
|
raise exception.CinderException(msg % msg_fmt)
|
||||||
|
|
||||||
self._clone_volume(src_vref['name'], volume['name'], src_vref['id'])
|
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'])
|
share = self._get_volume_location(src_vref['id'])
|
||||||
|
|
||||||
return {'provider_location': share}
|
return {'provider_location': share}
|
||||||
|
|
Loading…
Reference in New Issue