Fix 'no actual-pathname' NetApp API error
Cinder volume logs sometimes show this error
NetApp API failed. Reason - 13114:
No actual-pathname for 10.1.0.9:/vol/whatever
with Kilo code and 7-mode DOT system.
The issue is due to our Cinder driver passing the
entire share to the relevant API instead of just
the export path portion of the share. This only
happens when the NFS image cache is full, and cached
files need to be removed.
Change-Id: I0c40840dac975dd7fd2c62f1f9c0cd3f8c5c1252
Closes-Bug: #1468884
(cherry picked from commit 6a65422c69
)
This commit is contained in:
parent
6c055943e7
commit
4f86ae7f2f
|
@ -12,7 +12,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
VOLUME = 'f10d1a84-9b7b-427e-8fec-63c48b509a56'
|
||||
LUN = 'ee6b4cc7-477b-4016-aa0c-7127b4e3af86'
|
||||
SIZE = '1024'
|
||||
|
@ -115,12 +114,16 @@ ISCSI_TARGET_DETAILS_LIST = [
|
|||
HOSTNAME = 'fake.host.com'
|
||||
IPV4_ADDRESS = '192.168.14.2'
|
||||
IPV6_ADDRESS = 'fe80::6e40:8ff:fe8a:130'
|
||||
SHARE_IP = '192.168.99.24'
|
||||
EXPORT_PATH = '/fake/export/path'
|
||||
NFS_SHARE = HOSTNAME + ':' + EXPORT_PATH
|
||||
NFS_SHARE_IPV4 = IPV4_ADDRESS + ':' + EXPORT_PATH
|
||||
NFS_SHARE_IPV6 = IPV6_ADDRESS + ':' + EXPORT_PATH
|
||||
FLEXVOL = 'openstack-flexvol'
|
||||
|
||||
RESERVED_PERCENTAGE = 7
|
||||
TOTAL_BYTES = 4797892092432
|
||||
AVAILABLE_BYTES = 13479932478
|
||||
CAPACITY_VALUES = (TOTAL_BYTES, AVAILABLE_BYTES)
|
||||
|
||||
FILE_LIST = ['file1', 'file2', 'file3']
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Mock unit tests for the NetApp 7mode nfs storage driver
|
||||
Unit tests for the NetApp 7mode NFS storage driver
|
||||
"""
|
||||
|
||||
import mock
|
||||
|
@ -40,6 +40,7 @@ class NetApp7modeNfsDriverTestCase(test.TestCase):
|
|||
self.driver = nfs_7mode.NetApp7modeNfsDriver(**kwargs)
|
||||
self.driver._mounted_shares = [fake.NFS_SHARE]
|
||||
self.driver.ssc_vols = True
|
||||
self.driver.zapi_client = mock.Mock()
|
||||
|
||||
def get_config_7mode(self):
|
||||
config = na_fakes.create_configuration_cmode()
|
||||
|
@ -73,3 +74,34 @@ class NetApp7modeNfsDriverTestCase(test.TestCase):
|
|||
result[0]['reserved_percentage'])
|
||||
self.assertEqual(total_capacity_gb, result[0]['total_capacity_gb'])
|
||||
self.assertEqual(free_capacity_gb, result[0]['free_capacity_gb'])
|
||||
|
||||
def test_shortlist_del_eligible_files(self):
|
||||
mock_get_path_for_export = self.mock_object(
|
||||
self.driver.zapi_client, 'get_actual_path_for_export')
|
||||
mock_get_path_for_export.return_value = fake.FLEXVOL
|
||||
|
||||
mock_get_file_usage = self.mock_object(
|
||||
self.driver.zapi_client, 'get_file_usage')
|
||||
mock_get_file_usage.return_value = fake.CAPACITY_VALUES[0]
|
||||
|
||||
expected = [(old_file, fake.CAPACITY_VALUES[0]) for old_file
|
||||
in fake.FILE_LIST]
|
||||
|
||||
result = self.driver._shortlist_del_eligible_files(
|
||||
fake.NFS_SHARE, fake.FILE_LIST)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_shortlist_del_eligible_files_empty_list(self):
|
||||
mock_get_export_ip_path = self.mock_object(
|
||||
self.driver, '_get_export_ip_path')
|
||||
mock_get_export_ip_path.return_value = ('', '/export_path')
|
||||
|
||||
mock_get_path_for_export = self.mock_object(
|
||||
self.driver.zapi_client, 'get_actual_path_for_export')
|
||||
mock_get_path_for_export.return_value = fake.FLEXVOL
|
||||
|
||||
result = self.driver._shortlist_del_eligible_files(
|
||||
fake.NFS_SHARE, [])
|
||||
|
||||
self.assertEqual([], result)
|
||||
|
|
|
@ -13,13 +13,14 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Mock unit tests for the NetApp nfs storage driver
|
||||
Unit tests for the NetApp NFS storage driver
|
||||
"""
|
||||
|
||||
import mock
|
||||
from oslo_utils import units
|
||||
|
||||
from cinder.brick.remotefs import remotefs as remotefs_brick
|
||||
from cinder import exception
|
||||
from cinder import test
|
||||
from cinder.tests.volume.drivers.netapp.dataontap import fakes as fake
|
||||
from cinder import utils
|
||||
|
@ -43,6 +44,7 @@ class NetAppNfsDriverTestCase(test.TestCase):
|
|||
with mock.patch.object(remotefs_brick, 'RemoteFsClient',
|
||||
return_value=mock.Mock()):
|
||||
self.driver = nfs_base.NetAppNfsDriver(**kwargs)
|
||||
self.driver.db = mock.Mock()
|
||||
|
||||
@mock.patch.object(nfs.NfsDriver, 'do_setup')
|
||||
@mock.patch.object(na_utils, 'check_flags')
|
||||
|
@ -98,3 +100,63 @@ class NetAppNfsDriverTestCase(test.TestCase):
|
|||
self.assertEqual(expected, result)
|
||||
get_capacity.assert_has_calls([
|
||||
mock.call(fake.EXPORT_PATH)])
|
||||
|
||||
def test_get_export_ip_path_volume_id_provided(self):
|
||||
mock_get_host_ip = self.mock_object(self.driver, '_get_host_ip')
|
||||
mock_get_host_ip.return_value = fake.IPV4_ADDRESS
|
||||
|
||||
mock_get_export_path = self.mock_object(
|
||||
self.driver, '_get_export_path')
|
||||
mock_get_export_path.return_value = fake.EXPORT_PATH
|
||||
|
||||
expected = (fake.IPV4_ADDRESS, fake.EXPORT_PATH)
|
||||
|
||||
result = self.driver._get_export_ip_path(fake.VOLUME)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_get_export_ip_path_share_provided(self):
|
||||
expected = (fake.HOSTNAME, fake.EXPORT_PATH)
|
||||
|
||||
result = self.driver._get_export_ip_path(share=fake.NFS_SHARE)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_get_export_ip_path_volume_id_and_share_provided(self):
|
||||
mock_get_host_ip = self.mock_object(self.driver, '_get_host_ip')
|
||||
mock_get_host_ip.return_value = fake.IPV4_ADDRESS
|
||||
|
||||
mock_get_export_path = self.mock_object(
|
||||
self.driver, '_get_export_path')
|
||||
mock_get_export_path.return_value = fake.EXPORT_PATH
|
||||
|
||||
expected = (fake.IPV4_ADDRESS, fake.EXPORT_PATH)
|
||||
|
||||
result = self.driver._get_export_ip_path(
|
||||
fake.VOLUME, fake.NFS_SHARE)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_get_export_ip_path_no_args(self):
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
self.driver._get_export_ip_path)
|
||||
|
||||
def test_get_host_ip(self):
|
||||
mock_get_provider_location = self.mock_object(
|
||||
self.driver, '_get_provider_location')
|
||||
mock_get_provider_location.return_value = fake.NFS_SHARE_IPV4
|
||||
expected = fake.IPV4_ADDRESS
|
||||
|
||||
result = self.driver._get_host_ip(fake.VOLUME)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
def test_get_export_path(self):
|
||||
mock_get_provider_location = self.mock_object(
|
||||
self.driver, '_get_provider_location')
|
||||
mock_get_provider_location.return_value = fake.NFS_SHARE
|
||||
expected = fake.EXPORT_PATH
|
||||
|
||||
result = self.driver._get_export_path(fake.VOLUME)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
Volume driver for NetApp NFS storage.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
|
@ -152,11 +154,13 @@ class NetApp7modeNfsDriver(nfs_base.NetAppNfsDriver):
|
|||
def _shortlist_del_eligible_files(self, share, old_files):
|
||||
"""Prepares list of eligible files to be deleted from cache."""
|
||||
file_list = []
|
||||
exp_volume = self.zapi_client.get_actual_path_for_export(share)
|
||||
for file in old_files:
|
||||
path = '/vol/%s/%s' % (exp_volume, file)
|
||||
(_, export_path) = self._get_export_ip_path(share=share)
|
||||
exported_volume = self.zapi_client.get_actual_path_for_export(
|
||||
export_path)
|
||||
for old_file in old_files:
|
||||
path = os.path.join(exported_volume, old_file)
|
||||
u_bytes = self.zapi_client.get_file_usage(path)
|
||||
file_list.append((file, u_bytes))
|
||||
file_list.append((old_file, u_bytes))
|
||||
LOG.debug('Shortlisted files eligible for deletion: %s', file_list)
|
||||
return file_list
|
||||
|
||||
|
|
|
@ -149,11 +149,11 @@ class NetAppNfsDriver(nfs.NfsDriver):
|
|||
|
||||
def _get_host_ip(self, volume_id):
|
||||
"""Returns IP address for the given volume."""
|
||||
return self._get_provider_location(volume_id).split(':')[0]
|
||||
return self._get_provider_location(volume_id).rsplit(':')[0]
|
||||
|
||||
def _get_export_path(self, volume_id):
|
||||
"""Returns NFS export path for the given volume."""
|
||||
return self._get_provider_location(volume_id).split(':')[1]
|
||||
return self._get_provider_location(volume_id).rsplit(':')[1]
|
||||
|
||||
def _volume_not_present(self, nfs_mount, volume_name):
|
||||
"""Check if volume exists."""
|
||||
|
|
Loading…
Reference in New Issue