NetApp: Refresh directory before waiting

After image cloning the NFS client cache needs to be refreshed.
This can be accomplished by touching the directory hosting the
cached image file.

See also: https://bugs.launchpad.net/nova/+bug/1617299
Co-Authored-By: Sebastian Schee <sebastian.schee@sap.com>
Co-Authored-By: Goutham Pacha Ravi <gouthampravi@gmail.com>

Closes-bug: #1679716
Change-Id: If392f41f65978721668b53cfab94393f074d24e9
(cherry picked from commit ff6acd62ec)
(cherry picked from commit cd3c1c2c37)
This commit is contained in:
Marc Koderer 2017-04-05 08:54:53 +02:00 committed by Goutham Pacha Ravi
parent 3b5a0fcef9
commit e4d719f646
3 changed files with 56 additions and 11 deletions

View File

@ -16,6 +16,9 @@
Mock unit tests for the NetApp cmode nfs storage driver
"""
import hashlib
import uuid
import ddt
import mock
from os_brick.remotefs import remotefs as remotefs_brick
@ -809,23 +812,35 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
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/'
# To get the cinder mount point directory, we use:
mount_dir = hashlib.md5(
'203.0.113.122:/cinder-flexvol1'.encode('utf-8')).hexdigest()
cinder_mount_point = cinder_mount_point_base + mount_dir
destination_copied_file = (
'/cinder-flexvol1/a155308c-0290-497b-b278-4cdd01de0253'
)
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
image_id = 'image_id'
context = object()
image_service = mock.Mock()
image_service.get_location.return_value = ('nfs://ip1/openstack/img',
None)
image_service.get_location.return_value = (
'nfs://203.0.113.122/glance-flexvol1', None)
image_service.show.return_value = {'size': 1,
'disk_format': 'qcow2'}
drv._check_get_nfs_path_segs =\
mock.Mock(return_value=('ip1', '/openstack'))
drv._check_get_nfs_path_segs = (
mock.Mock(return_value=('203.0.113.122', '/openstack'))
)
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._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._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
drv._execute_as_root = False
drv._get_mount_point_for_share = mock.Mock(
return_value=cinder_mount_point)
img_inf = mock.Mock()
img_inf.file_format = 'raw'
mock_qemu_img_info.return_value = img_inf
@ -835,17 +850,33 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
drv._delete_file_at_path = mock.Mock()
drv._clone_file_dst_exists = mock.Mock()
drv._post_clone_image = mock.Mock()
self.mock_object(uuid, 'uuid4', mock.Mock(
return_value='a155308c-0290-497b-b278-4cdd01de0253'))
retval = drv._copy_from_img_service(
context, volume, image_service, image_id)
self.assertIsNone(retval)
drv._get_ip_verify_on_cluster.assert_any_call('ip1')
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)
self.assertEqual(1, drv._execute.call_count)
# _execute must be called once for copy-offload and again to touch
# the top directory to refresh cache
drv._execute.assert_has_calls(
[
mock.call(
'copyoffload_tool_path', '203.0.113.122',
'203.0.113.122', '/openstack/glance-flexvol1',
destination_copied_file, run_as_root=False,
check_exit_code=0
),
mock.call('touch', cinder_mount_point, run_as_root=False)
]
)
self.assertEqual(2, drv._execute.call_count)
self.assertEqual(2, drv._delete_file_at_path.call_count)
self.assertEqual(1, drv._clone_file_dst_exists.call_count)

View File

@ -645,6 +645,15 @@ class NetAppNfsDriver(driver.ManageableVD,
else:
return False
@utils.trace_method
def _touch_path_to_refresh(self, path):
try:
# Touching parent directory forces NFS client to flush its cache.
self._execute('touch', path, run_as_root=self._execute_as_root)
except processutils.ProcessExecutionError:
LOG.exception(_LE("Failed to touch path %s."), path)
@utils.trace_method
def _discover_file_till_timeout(self, path, timeout=75):
"""Checks if file size at path is equal to size."""
# Sometimes nfs takes time to discover file
@ -656,6 +665,9 @@ class NetAppNfsDriver(driver.ManageableVD,
# retries to ensure that this cache has refreshed.
retry_seconds = timeout
sleep_interval = 2
base_path = os.path.dirname(path)
self._touch_path_to_refresh(base_path)
while True:
if os.path.exists(path):
return True
@ -666,6 +678,7 @@ class NetAppNfsDriver(driver.ManageableVD,
else:
time.sleep(sleep_interval)
retry_seconds -= sleep_interval
self._touch_path_to_refresh(base_path)
def _is_cloneable_share(self, image_location):
"""Finds if the image at location is cloneable."""

View File

@ -119,8 +119,9 @@ rm: CommandFilter, rm, root
# cinder/volume/drivers/remotefs.py
mkdir: CommandFilter, mkdir, root
# cinder/volume/drivers/netapp/nfs.py:
# cinder/volume/drivers/netapp/dataontap/nfs_base.py:
netapp_nfs_find: RegExpFilter, find, root, find, ^[/]*([^/\0]+(/+)?)*$, -maxdepth, \d+, -name, img-cache.*, -amin, \+\d+
netapp_nfs_touch: CommandFilter, touch, root
# cinder/volume/drivers/glusterfs.py
chgrp: CommandFilter, chgrp, root