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 commitff6acd62ec
) (cherry picked from commitcd3c1c2c37
)
This commit is contained in:
parent
3b5a0fcef9
commit
e4d719f646
@ -16,6 +16,9 @@
|
|||||||
Mock unit tests for the NetApp cmode nfs storage driver
|
Mock unit tests for the NetApp cmode nfs storage driver
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import hashlib
|
||||||
|
import uuid
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
import mock
|
import mock
|
||||||
from os_brick.remotefs import remotefs as remotefs_brick
|
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(
|
def test__copy_from_img_service_qcow2_copyoffload_workflow_success(
|
||||||
self, mock_exists, mock_qemu_img_info, mock_cvrt_image):
|
self, mock_exists, mock_qemu_img_info, mock_cvrt_image):
|
||||||
drv = self.driver
|
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}
|
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
|
||||||
image_id = 'image_id'
|
image_id = 'image_id'
|
||||||
context = object()
|
context = object()
|
||||||
image_service = mock.Mock()
|
image_service = mock.Mock()
|
||||||
image_service.get_location.return_value = ('nfs://ip1/openstack/img',
|
image_service.get_location.return_value = (
|
||||||
None)
|
'nfs://203.0.113.122/glance-flexvol1', None)
|
||||||
image_service.show.return_value = {'size': 1,
|
image_service.show.return_value = {'size': 1,
|
||||||
'disk_format': 'qcow2'}
|
'disk_format': 'qcow2'}
|
||||||
drv._check_get_nfs_path_segs =\
|
drv._check_get_nfs_path_segs = (
|
||||||
mock.Mock(return_value=('ip1', '/openstack'))
|
mock.Mock(return_value=('203.0.113.122', '/openstack'))
|
||||||
|
)
|
||||||
|
|
||||||
drv._get_ip_verify_on_cluster = mock.Mock(return_value='ip1')
|
drv._get_ip_verify_on_cluster = mock.Mock(return_value='203.0.113.122')
|
||||||
drv._get_host_ip = mock.Mock(return_value='ip2')
|
drv._get_host_ip = mock.Mock(return_value='203.0.113.122')
|
||||||
drv._get_export_path = mock.Mock(return_value='/exp_path')
|
drv._get_export_path = mock.Mock(
|
||||||
|
return_value='/cinder-flexvol1')
|
||||||
drv._get_provider_location = mock.Mock(return_value='share')
|
drv._get_provider_location = mock.Mock(return_value='share')
|
||||||
drv._execute = mock.Mock()
|
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 = mock.Mock()
|
||||||
img_inf.file_format = 'raw'
|
img_inf.file_format = 'raw'
|
||||||
mock_qemu_img_info.return_value = img_inf
|
mock_qemu_img_info.return_value = img_inf
|
||||||
@ -835,17 +850,33 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
|
|||||||
drv._delete_file_at_path = mock.Mock()
|
drv._delete_file_at_path = mock.Mock()
|
||||||
drv._clone_file_dst_exists = mock.Mock()
|
drv._clone_file_dst_exists = mock.Mock()
|
||||||
drv._post_clone_image = 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(
|
retval = drv._copy_from_img_service(
|
||||||
context, volume, image_service, image_id)
|
context, volume, image_service, image_id)
|
||||||
|
|
||||||
self.assertIsNone(retval)
|
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._get_export_path.assert_called_with('vol_id')
|
||||||
drv._check_share_can_hold_size.assert_called_with('share', 1)
|
drv._check_share_can_hold_size.assert_called_with('share', 1)
|
||||||
drv._post_clone_image.assert_called_with(volume)
|
drv._post_clone_image.assert_called_with(volume)
|
||||||
self.assertEqual(1, mock_cvrt_image.call_count)
|
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(2, drv._delete_file_at_path.call_count)
|
||||||
self.assertEqual(1, drv._clone_file_dst_exists.call_count)
|
self.assertEqual(1, drv._clone_file_dst_exists.call_count)
|
||||||
|
|
||||||
|
@ -645,6 +645,15 @@ class NetAppNfsDriver(driver.ManageableVD,
|
|||||||
else:
|
else:
|
||||||
return False
|
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):
|
def _discover_file_till_timeout(self, path, timeout=75):
|
||||||
"""Checks if file size at path is equal to size."""
|
"""Checks if file size at path is equal to size."""
|
||||||
# Sometimes nfs takes time to discover file
|
# Sometimes nfs takes time to discover file
|
||||||
@ -656,6 +665,9 @@ class NetAppNfsDriver(driver.ManageableVD,
|
|||||||
# retries to ensure that this cache has refreshed.
|
# retries to ensure that this cache has refreshed.
|
||||||
retry_seconds = timeout
|
retry_seconds = timeout
|
||||||
sleep_interval = 2
|
sleep_interval = 2
|
||||||
|
base_path = os.path.dirname(path)
|
||||||
|
self._touch_path_to_refresh(base_path)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
return True
|
return True
|
||||||
@ -666,6 +678,7 @@ class NetAppNfsDriver(driver.ManageableVD,
|
|||||||
else:
|
else:
|
||||||
time.sleep(sleep_interval)
|
time.sleep(sleep_interval)
|
||||||
retry_seconds -= sleep_interval
|
retry_seconds -= sleep_interval
|
||||||
|
self._touch_path_to_refresh(base_path)
|
||||||
|
|
||||||
def _is_cloneable_share(self, image_location):
|
def _is_cloneable_share(self, image_location):
|
||||||
"""Finds if the image at location is cloneable."""
|
"""Finds if the image at location is cloneable."""
|
||||||
|
@ -119,8 +119,9 @@ rm: CommandFilter, rm, root
|
|||||||
# cinder/volume/drivers/remotefs.py
|
# cinder/volume/drivers/remotefs.py
|
||||||
mkdir: CommandFilter, mkdir, root
|
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_find: RegExpFilter, find, root, find, ^[/]*([^/\0]+(/+)?)*$, -maxdepth, \d+, -name, img-cache.*, -amin, \+\d+
|
||||||
|
netapp_nfs_touch: CommandFilter, touch, root
|
||||||
|
|
||||||
# cinder/volume/drivers/glusterfs.py
|
# cinder/volume/drivers/glusterfs.py
|
||||||
chgrp: CommandFilter, chgrp, root
|
chgrp: CommandFilter, chgrp, root
|
||||||
|
Loading…
Reference in New Issue
Block a user