Merge "NetApp ONTAP: Copy offload bugfix"

This commit is contained in:
Zuul 2017-12-15 19:17:05 +00:00 committed by Gerrit Code Review
commit 4e51d33861
4 changed files with 136 additions and 168 deletions

View File

@ -763,26 +763,25 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.driver.zapi_client.clone_file.assert_called_once_with(
'nfsvol', 'vol', 'clone', None, is_snapshot=True)
def test__copy_from_img_service_copyoffload_nonexistent_binary_path(self):
def test_copy_from_img_service_copyoffload_nonexistent_binary_path(self):
self.mock_object(nfs_cmode.LOG, 'debug')
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
volume = {'id': 'vol_id', 'name': 'name',
'host': 'openstack@nfscmode#192.128.1.1:/mnt_point'}
image_service = mock.Mock()
image_service.get_location.return_value = (mock.Mock(), mock.Mock())
image_service.show.return_value = {'size': 0}
image_id = 'image_id'
drv._client = mock.Mock()
drv._client.get_api_version = mock.Mock(return_value=(1, 20))
drv._find_image_in_cache = mock.Mock(return_value=[])
nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
return_value=[])
drv._construct_image_nfs_url = mock.Mock(return_value=["nfs://1"])
drv._check_get_nfs_path_segs = mock.Mock(
return_value=("test:test", "dr"))
drv._get_ip_verify_on_cluster = mock.Mock(return_value="192.128.1.1")
drv._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
drv._get_host_ip = mock.Mock()
drv._get_provider_location = mock.Mock()
drv._get_export_path = mock.Mock(return_value="dr")
drv._check_share_can_hold_size = mock.Mock()
# Raise error as if the copyoffload file can not be found
drv._clone_file_dst_exists = mock.Mock(side_effect=OSError())
@ -795,10 +794,11 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
drv._discover_file_till_timeout.assert_not_called()
@mock.patch.object(image_utils, 'qemu_img_info')
def test__copy_from_img_service_raw_copyoffload_workflow_success(
def test_copy_from_img_service_raw_copyoffload_workflow_success(
self, mock_qemu_img_info):
drv = self.driver
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
'host': 'openstack@nfscmode#ip1:/mnt_point'}
image_id = 'image_id'
context = object()
image_service = mock.Mock()
@ -827,17 +827,16 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
retval = drv._copy_from_img_service(
context, volume, image_service, image_id)
self.assertIsNone(retval)
self.assertTrue(retval)
drv._get_ip_verify_on_cluster.assert_any_call('ip1')
drv._get_export_path.assert_called_with('vol_id')
drv._check_share_can_hold_size.assert_called_with('share', 1)
drv._post_clone_image.assert_called_with(volume)
drv._check_share_can_hold_size.assert_called_with(
'ip1:/mnt_point', 1)
self.assertEqual(1, drv._execute.call_count)
@mock.patch.object(image_utils, 'convert_image')
@mock.patch.object(image_utils, 'qemu_img_info')
@mock.patch('os.path.exists')
def test__copy_from_img_service_qcow2_copyoffload_workflow_success(
def test_copy_from_img_service_qcow2_copyoffload_workflow_success(
self, mock_exists, mock_qemu_img_info, mock_cvrt_image):
drv = self.driver
cinder_mount_point_base = '/opt/stack/data/cinder/mnt/'
@ -848,7 +847,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
destination_copied_file = (
'/cinder-flexvol1/a155308c-0290-497b-b278-4cdd01de0253'
)
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
'host': 'openstack@nfscmode#203.0.113.122:/cinder-flexvol1'}
image_id = 'image_id'
context = object()
image_service = mock.Mock()
@ -861,10 +861,6 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
)
drv._get_ip_verify_on_cluster = mock.Mock(return_value='203.0.113.122')
drv._get_host_ip = mock.Mock(return_value='203.0.113.122')
drv._get_export_path = mock.Mock(
return_value='/cinder-flexvol1')
drv._get_provider_location = mock.Mock(return_value='share')
drv._execute = mock.Mock()
drv._execute_as_root = False
drv._get_mount_point_for_share = mock.Mock(
@ -884,12 +880,10 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
retval = drv._copy_from_img_service(
context, volume, image_service, image_id)
self.assertIsNone(retval)
self.assertTrue(retval)
drv._get_ip_verify_on_cluster.assert_any_call('203.0.113.122')
drv._get_export_path.assert_called_with('vol_id')
drv._check_share_can_hold_size.assert_called_with('share', 1)
drv._post_clone_image.assert_called_with(volume)
self.assertEqual(1, mock_cvrt_image.call_count)
drv._check_share_can_hold_size.assert_called_with(
'203.0.113.122:/cinder-flexvol1', 1)
# _execute must be called once for copy-offload and again to touch
# the top directory to refresh cache
@ -908,30 +902,25 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.assertEqual(2, drv._delete_file_at_path.call_count)
self.assertEqual(1, drv._clone_file_dst_exists.call_count)
def test__copy_from_cache_copyoffload_success(self):
def test_copy_from_cache_copyoffload_success(self):
drv = self.driver
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
volume = {'id': 'vol_id', 'name': 'name', 'size': 1,
'host': 'openstack@nfscmode#192.128.1.1:/exp_path'}
image_id = 'image_id'
cache_result = [('ip1:/openstack', 'img-cache-imgid')]
drv._get_ip_verify_on_cluster = mock.Mock(return_value='ip1')
drv._get_host_ip = mock.Mock(return_value='ip2')
drv._get_export_path = mock.Mock(return_value='/exp_path')
drv._execute = mock.Mock()
drv._register_image_in_cache = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='/share')
drv._post_clone_image = mock.Mock()
copied = drv._copy_from_cache(volume, image_id, cache_result)
self.assertTrue(copied)
drv._get_ip_verify_on_cluster.assert_any_call('ip1')
drv._get_export_path.assert_called_with('vol_id')
drv._execute.assert_called_once_with(
'copyoffload_tool_path', 'ip1', 'ip1',
'/openstack/img-cache-imgid', '/exp_path/name',
run_as_root=False, check_exit_code=0)
drv._post_clone_image.assert_called_with(volume)
drv._get_provider_location.assert_called_with('vol_id')
def test_unmanage(self):
mock_get_info = self.mock_object(na_utils,
@ -1080,40 +1069,38 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
(local_share, 'img-cache-imgid'),
('ip3:/openstack', 'img-cache-imgid'),
]
self.driver._get_provider_location = mock.Mock(
return_value=local_share)
mock_extract_host = self.mock_object(volume_utils, 'extract_host')
mock_extract_host.return_value = local_share
cache_copy, found_local_copy = self.driver._find_image_location(
cache_result, fake.VOLUME_ID)
cache_result, fake.VOLUME)
self.assertEqual(cache_result[2], cache_copy)
self.assertTrue(found_local_copy)
self.driver._get_provider_location.assert_called_once_with(
fake.VOLUME_ID)
def test_find_image_location_with_remote_copy(self):
cache_result = [('ip1:/openstack', 'img-cache-imgid')]
self.driver._get_provider_location = mock.Mock(return_value='/share')
mock_extract_host = self.mock_object(volume_utils, 'extract_host')
mock_extract_host.return_value = '/share'
cache_copy, found_local_copy = self.driver._find_image_location(
cache_result, fake.VOLUME_ID)
cache_result, fake.VOLUME)
self.assertEqual(cache_result[0], cache_copy)
self.assertFalse(found_local_copy)
self.driver._get_provider_location.assert_called_once_with(
fake.VOLUME_ID)
def test_find_image_location_without_cache_copy(self):
cache_result = []
self.driver._get_provider_location = mock.Mock(return_value='/share')
mock_extract_host = self.mock_object(volume_utils, 'extract_host')
mock_extract_host.return_value = '/share'
cache_copy, found_local_copy = self.driver._find_image_location(
cache_result, fake.VOLUME_ID)
cache_result, fake.VOLUME)
self.assertIsNone(cache_copy)
self.assertFalse(found_local_copy)
self.driver._get_provider_location.assert_called_once_with(
fake.VOLUME_ID)
def test_clone_file_dest_exists(self):
self.driver._get_vserver_and_exp_vol = mock.Mock(
@ -1146,8 +1133,8 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
def test_get_destination_ip_and_path(self):
self.driver._get_ip_verify_on_cluster = mock.Mock(
return_value=fake.SHARE_IP)
self.driver._get_host_ip = mock.Mock(return_value='host.ip')
self.driver._get_export_path = mock.Mock(return_value=fake.EXPORT_PATH)
mock_extract_host = self.mock_object(volume_utils, 'extract_host')
mock_extract_host.return_value = fake.NFS_SHARE
dest_ip, dest_path = self.driver._get_destination_ip_and_path(
fake.VOLUME)
@ -1156,98 +1143,85 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
assert_path = fake.EXPORT_PATH + '/' + fake.LUN_NAME
self.assertEqual(assert_path, dest_path)
self.driver._get_ip_verify_on_cluster.assert_called_once_with(
'host.ip')
self.driver._get_host_ip.assert_called_once_with(fake.VOLUME_ID)
self.driver._get_export_path.assert_called_once_with(fake.VOLUME_ID)
fake.SHARE_IP)
def test_copy_image_to_volume_copyoffload_non_cached_ssc_update(self):
mock_log = self.mock_object(nfs_cmode, 'LOG')
def test_clone_image_copyoffload_from_cache_success(self):
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
volume = {'id': 'vol_id', 'name': 'name',
'host': 'openstack@nfscmode#192.128.1.1:/mnt_point'}
image_service = object()
image_location = 'img-loc'
image_id = 'image_id'
image_meta = {'id': image_id}
drv.zapi_client = mock.Mock()
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
drv._copy_from_img_service = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol')
retval = drv.copy_image_to_volume(
context, volume, image_service, image_id)
self.assertIsNone(retval)
drv._copy_from_img_service.assert_called_once_with(
context, volume, image_service, image_id)
self.assertEqual(1, mock_log.debug.call_count)
self.assertEqual(1, mock_log.info.call_count)
def test_copy_image_to_volume_copyoffload_from_cache_success(self):
mock_info_log = self.mock_object(nfs_cmode.LOG, 'info')
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
image_service = object()
image_id = 'image_id'
drv.zapi_client = mock.Mock()
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol')
drv._find_image_in_cache = mock.Mock(return_value=[('share', 'img')])
nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
return_value=[('share', 'img')])
nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
return_value=False)
drv._copy_from_cache = mock.Mock(return_value=True)
drv.copy_image_to_volume(context, volume, image_service, image_id)
drv.clone_image(context, volume, image_location, image_meta,
image_service)
drv._copy_from_cache.assert_called_once_with(
volume, image_id, [('share', 'img')])
self.assertEqual(1, mock_info_log.call_count)
def test_copy_image_to_volume_copyoffload_from_img_service(self):
def test_clone_image_copyoffload_from_img_service(self):
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
volume = {'id': 'vol_id', 'name': 'name',
'host': 'openstack@nfscmode#192.128.1.1:/mnt_point',
'provider_location': '192.128.1.1:/mnt_point'}
image_service = object()
image_id = 'image_id'
image_meta = {'id': image_id}
image_location = 'img-loc'
drv.zapi_client = mock.Mock()
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol')
drv._find_image_in_cache = mock.Mock(return_value=False)
drv._copy_from_img_service = mock.Mock()
nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
return_value=[])
nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
return_value=False)
nfs_base.NetAppNfsDriver._post_clone_image = mock.Mock(
return_value=True)
drv._copy_from_img_service = mock.Mock(return_value=True)
retval = drv.copy_image_to_volume(
context, volume, image_service, image_id)
retval = drv.clone_image(
context, volume, image_location, image_meta, image_service)
self.assertIsNone(retval)
self.assertEqual(retval, (
{'provider_location': '192.128.1.1:/mnt_point',
'bootable': True}, True))
drv._copy_from_img_service.assert_called_once_with(
context, volume, image_service, image_id)
def test_copy_image_to_volume_copyoffload_failure(self):
def test_clone_image_copyoffload_failure(self):
mock_log = self.mock_object(nfs_cmode, 'LOG')
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
image_service = object()
image_id = 'image_id'
image_meta = {'id': image_id}
image_location = 'img-loc'
drv.zapi_client = mock.Mock()
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
nfs_base.NetAppNfsDriver._find_image_in_cache = mock.Mock(
return_value=[])
nfs_base.NetAppNfsDriver._direct_nfs_clone = mock.Mock(
return_value=False)
drv._copy_from_img_service = mock.Mock(side_effect=Exception())
nfs_base.NetAppNfsDriver.copy_image_to_volume = mock.Mock()
drv._get_provider_location = mock.Mock(return_value='share')
drv._get_vol_for_share = mock.Mock(return_value='vol')
retval = drv.copy_image_to_volume(
context, volume, image_service, image_id)
retval = drv.clone_image(
context, volume, image_location, image_meta, image_service)
self.assertIsNone(retval)
self.assertEqual(retval, ({'bootable': False,
'provider_location': None}, False))
drv._copy_from_img_service.assert_called_once_with(
context, volume, image_service, image_id)
nfs_base.NetAppNfsDriver.copy_image_to_volume. \
assert_called_once_with(context, volume, image_service, image_id)
mock_log.info.assert_not_called()
self.assertEqual(1, mock_log.exception.call_count)
def test_copy_from_remote_cache(self):
source_ip = '192.0.1.1'
@ -1289,7 +1263,6 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.assertTrue(copied)
self.driver._copy_from_remote_cache.assert_called_once_with(
fake.VOLUME, fake.IMAGE_FILE_ID, cache_result[0])
self.driver._post_clone_image.assert_called_once_with(fake.VOLUME)
def test_copy_from_cache_workflow_remote_location_no_copyoffload(self):
cache_result = [('ip1:/openstack', fake.IMAGE_FILE_ID),
@ -1327,7 +1300,6 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.driver._clone_file_dst_exists.assert_called_once_with(
local_share, fake.IMAGE_FILE_ID, fake.VOLUME['name'],
dest_exists=True)
self.driver._post_clone_image.assert_called_once_with(fake.VOLUME)
def test_copy_from_cache_workflow_no_location(self):
cache_result = []

View File

@ -511,6 +511,14 @@ class NetAppNfsDriver(driver.ManageableVD,
LOG.warning('Exception during deleting %s', ex)
return False
def _copy_from_cache(self, volume, image_id, cache_result):
"""Try copying image file_name from cached file"""
raise NotImplementedError()
def _copy_from_img_service(self, context, volume, image_service,
image_id):
raise NotImplementedError()
def clone_image(self, context, volume,
image_location, image_meta,
image_service):
@ -528,14 +536,22 @@ class NetAppNfsDriver(driver.ManageableVD,
post_clone = False
extra_specs = na_utils.get_volume_extra_specs(volume)
major, minor = self.zapi_client.get_ontapi_version()
col_path = self.configuration.netapp_copyoffload_tool_path
try:
cache_result = self._find_image_in_cache(image_id)
if cache_result:
cloned = self._clone_from_cache(volume, image_id, cache_result)
cloned = self._copy_from_cache(volume, image_id, cache_result)
else:
cloned = self._direct_nfs_clone(volume, image_location,
image_id)
# Try to use the copy offload tool
if not cloned and col_path and major == 1 and minor >= 20:
cloned = self._copy_from_img_service(context, volume,
image_service, image_id)
if cloned:
self._do_qos_for_volume(volume, extra_specs)
post_clone = self._post_clone_image(volume)
@ -546,7 +562,8 @@ class NetAppNfsDriver(driver.ManageableVD,
{'image_id': image_id, 'msg': msg})
finally:
cloned = cloned and post_clone
share = volume['provider_location'] if cloned else None
share = (volume_utils.extract_host(volume['host'], level='pool')
if cloned else None)
bootable = True if cloned else False
return {'provider_location': share, 'bootable': bootable}, cloned
@ -583,7 +600,6 @@ class NetAppNfsDriver(driver.ManageableVD,
share = self._is_cloneable_share(loc)
if share and self._is_share_clone_compatible(volume, share):
LOG.debug('Share is cloneable %s', share)
volume['provider_location'] = share
(__, ___, img_file) = loc.rpartition('/')
dir_path = self._get_mount_point_for_share(share)
img_path = '%s/%s' % (dir_path, img_file)
@ -619,7 +635,10 @@ class NetAppNfsDriver(driver.ManageableVD,
def _post_clone_image(self, volume):
"""Do operations post image cloning."""
LOG.info('Performing post clone for %s', volume['name'])
vol_path = self.local_path(volume)
share = volume_utils.extract_host(volume['host'], level='pool')
vol_path = self._get_volume_path(share, volume['name'])
if self._discover_file_till_timeout(vol_path):
self._set_rw_permissions(vol_path)
self._resize_image_file(vol_path, volume['size'])

View File

@ -458,39 +458,6 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
LOG.exception('Exec of "rm" command on backing file for'
' %s was unsuccessful.', snapshot['id'])
@utils.trace_method
def copy_image_to_volume(self, context, volume, image_service, image_id):
"""Fetch the image from image_service and write it to the volume."""
copy_success = False
try:
major, minor = self.zapi_client.get_ontapi_version()
col_path = self.configuration.netapp_copyoffload_tool_path
# Search the local image cache before attempting copy offload
cache_result = self._find_image_in_cache(image_id)
if cache_result:
copy_success = self._copy_from_cache(volume, image_id,
cache_result)
if copy_success:
LOG.info('Copied image %(img)s to volume %(vol)s '
'using local image cache.',
{'img': image_id, 'vol': volume['id']})
# Image cache was not present, attempt copy offload workflow
if (not copy_success and col_path and
major == 1 and minor >= 20):
LOG.debug('No result found in image cache')
self._copy_from_img_service(context, volume, image_service,
image_id)
LOG.info('Copied image %(img)s to volume %(vol)s using'
' copy offload workflow.',
{'img': image_id, 'vol': volume['id']})
copy_success = True
except Exception:
LOG.exception('Copy offload workflow unsuccessful.')
finally:
if not copy_success:
super(NetAppCmodeNfsDriver, self).copy_image_to_volume(
context, volume, image_service, image_id)
def _get_ip_verify_on_cluster(self, host):
"""Verifies if host on same cluster and returns ip."""
ip = na_utils.resolve_hostname(host)
@ -502,13 +469,13 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
def _copy_from_cache(self, volume, image_id, cache_result):
"""Try copying image file_name from cached file_name."""
LOG.debug("Trying copy from cache using copy offload.")
copied = False
cache_copy, found_local = self._find_image_location(cache_result,
volume['id'])
volume)
try:
if found_local:
LOG.debug("Trying copy from cache using cloning.")
(nfs_share, file_name) = cache_copy
self._clone_file_dst_exists(
nfs_share, file_name, volume['name'], dest_exists=True)
@ -517,17 +484,14 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
copied = True
elif (cache_copy and
self.configuration.netapp_copyoffload_tool_path):
LOG.debug("Trying copy from cache using copy offload.")
self._copy_from_remote_cache(volume, image_id, cache_copy)
copied = True
if copied:
self._post_clone_image(volume)
except Exception:
LOG.exception('Error in workflow copy from cache.')
return copied
def _find_image_location(self, cache_result, volume_id):
def _find_image_location(self, cache_result, volume):
"""Finds the location of a cached image.
Returns image location local to the NFS share, that matches the
@ -537,7 +501,10 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
found_local_copy = False
cache_copy = None
provider_location = self._get_provider_location(volume_id)
provider_location = volume_utils.extract_host(volume['host'],
level='pool')
for res in cache_result:
(share, file_name) = res
if share == provider_location:
@ -575,10 +542,11 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
return src_ip, src_path
def _get_destination_ip_and_path(self, volume):
dest_ip = self._get_ip_verify_on_cluster(
self._get_host_ip(volume['id']))
dest_path = os.path.join(self._get_export_path(
volume['id']), volume['name'])
share = volume_utils.extract_host(volume['host'], level='pool')
share_ip_and_path = share.split(":")
dest_ip = self._get_ip_verify_on_cluster(share_ip_and_path[0])
dest_path = os.path.join(share_ip_and_path[1], volume['name'])
return dest_ip, dest_path
def _clone_file_dst_exists(self, share, src_name, dst_name,
@ -591,11 +559,14 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
def _copy_from_img_service(self, context, volume, image_service,
image_id):
"""Copies from the image service using copy offload."""
LOG.debug("Trying copy from image service using copy offload.")
image_loc = image_service.get_location(context, image_id)
locations = self._construct_image_nfs_url(image_loc)
src_ip = None
selected_loc = None
cloned = False
# this will match the first location that has a valid IP on cluster
for location in locations:
conn, dr = self._check_get_nfs_path_segs(location)
@ -610,32 +581,31 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
raise exception.NotFound(_("Source host details not found."))
(__, ___, img_file) = selected_loc.rpartition('/')
src_path = os.path.join(dr, img_file)
dst_ip = self._get_ip_verify_on_cluster(self._get_host_ip(
volume['id']))
dst_ip, vol_path = self._get_destination_ip_and_path(volume)
share_path = vol_path.rsplit("/", 1)[0]
dst_share = dst_ip + ':' + share_path
# tmp file is required to deal with img formats
tmp_img_file = six.text_type(uuid.uuid4())
col_path = self.configuration.netapp_copyoffload_tool_path
img_info = image_service.show(context, image_id)
dst_share = self._get_provider_location(volume['id'])
self._check_share_can_hold_size(dst_share, img_info['size'])
run_as_root = self._execute_as_root
dst_dir = self._get_mount_point_for_share(dst_share)
dst_img_local = os.path.join(dst_dir, tmp_img_file)
try:
# If src and dst share not equal
if (('%s:%s' % (src_ip, dr)) !=
('%s:%s' % (dst_ip, self._get_export_path(volume['id'])))):
dst_img_serv_path = os.path.join(
self._get_export_path(volume['id']), tmp_img_file)
# Always run copy offload as regular user, it's sufficient
# and rootwrap doesn't allow copy offload to run as root
# anyways.
self._execute(col_path, src_ip, dst_ip, src_path,
dst_img_serv_path, run_as_root=False,
check_exit_code=0)
else:
self._clone_file_dst_exists(dst_share, img_file, tmp_img_file)
dst_img_serv_path = os.path.join(
share_path, tmp_img_file)
# Always run copy offload as regular user, it's sufficient
# and rootwrap doesn't allow copy offload to run as root
# anyways.
self._execute(col_path, src_ip, dst_ip, src_path,
dst_img_serv_path, run_as_root=False,
check_exit_code=0)
self._discover_file_till_timeout(dst_img_local, timeout=120)
LOG.debug('Copied image %(img)s to tmp file %(tmp)s.',
{'img': image_id, 'tmp': tmp_img_file})
@ -677,11 +647,13 @@ class NetAppCmodeNfsDriver(nfs_base.NetAppNfsDriver,
finally:
if os.path.exists(dst_img_conv_local):
self._delete_file_at_path(dst_img_conv_local)
self._post_clone_image(volume)
cloned = True
finally:
if os.path.exists(dst_img_local):
self._delete_file_at_path(dst_img_local)
return cloned
@utils.trace_method
def unmanage(self, volume):
"""Removes the specified volume from Cinder management.

View File

@ -0,0 +1,5 @@
---
fixes:
- |
Fixed bug 1632333 with the NetApp ONTAP Driver. Now the copy offload method is invoked
early to avoid downloading Glance images twice.