Merge "NetApp: Refactor unit tests"

This commit is contained in:
Jenkins 2016-07-27 15:34:49 +00:00 committed by Gerrit Code Review
commit 3a614935fe
6 changed files with 954 additions and 2942 deletions

View File

@ -38,6 +38,12 @@ FLEXVOL = 'openstack-flexvol'
NFS_FILE_PATH = 'nfsvol'
PATH = '/vol/%s/%s' % (POOL_NAME, LUN_NAME)
IMAGE_FILE_ID = 'img-cache-imgid'
PROVIDER_LOCATION = 'fake_provider_location'
NFS_HOST = 'nfs-host1'
NFS_SHARE_PATH = '/export'
NFS_EXPORT_1 = '%s:%s' % (NFS_HOST, NFS_SHARE_PATH)
NFS_EXPORT_2 = 'nfs-host2:/export'
MOUNT_POINT = '/mnt/nfs'
LUN_METADATA = {
'OsType': None,
'SpaceReserved': 'true',
@ -56,10 +62,74 @@ NFS_VOLUME = {
'size': SIZE,
'id': VOLUME_ID,
'host': NFS_HOST_STRING,
'provider_location': PROVIDER_LOCATION,
}
FAKE_MANAGE_VOLUME = {
'name': 'volume-new-managed-123',
'id': 'volume-new-managed-123',
}
FAKE_IMAGE_LOCATION = (
None,
[
# valid metadata
{
'metadata': {
'share_location': 'nfs://host/path',
'mountpoint': '/opt/stack/data/glance',
'id': 'abc-123',
'type': 'nfs'
},
'url': 'file:///opt/stack/data/glance/image-id-0'
},
# missing metadata
{
'metadata': {},
'url': 'file:///opt/stack/data/glance/image-id-1'
},
# missing location_type
{
'metadata': {'location_type': None},
'url': 'file:///opt/stack/data/glance/image-id-2'
},
# non-nfs location_type
{
'metadata': {'location_type': 'not-NFS'},
'url': 'file:///opt/stack/data/glance/image-id-3'
},
# missing share_location
{
'metadata': {'location_type': 'nfs', 'share_location': None},
'url': 'file:///opt/stack/data/glance/image-id-4'},
# missing mountpoint
{
'metadata': {
'location_type': 'nfs',
'share_location': 'nfs://host/path',
# Pre-kilo we documented "mount_point"
'mount_point': '/opt/stack/data/glance'
},
'url': 'file:///opt/stack/data/glance/image-id-5'
},
# Valid metadata
{
'metadata':
{
'share_location': 'nfs://host/path',
'mountpoint': '/opt/stack/data/glance',
'id': 'abc-123',
'type': 'nfs',
},
'url': 'file:///opt/stack/data/glance/image-id-6'
}
]
)
NETAPP_VOLUME = 'fake_netapp_volume'
VFILER = 'fake_netapp_vfiler'
UUID1 = '12345678-1234-5678-1234-567812345678'
LUN_PATH = '/vol/vol0/%s' % LUN_NAME
@ -211,14 +281,18 @@ CLONE_DESTINATION = {
'id': CLONE_DESTINATION_ID,
}
VOLUME_NAME = 'volume-fake_volume_id'
MOUNT_PATH = '168.10.16.11:/' + VOLUME_ID
SNAPSHOT_NAME = 'fake_snapshot_name'
SNAPSHOT_LUN_HANDLE = 'fake_snapshot_lun_handle'
SNAPSHOT_MOUNT = '/fake/mount/path'
SNAPSHOT = {
'name': SNAPSHOT_NAME,
'volume_name': 'volume-fake_volume_id',
'volume_size': SIZE,
'volume_id': 'fake_volume_id',
'volume_id': VOLUME_ID,
'volume_name': VOLUME_NAME,
'busy': False,
}
@ -407,9 +481,30 @@ class test_snapshot(object):
def __getitem__(self, key):
return getattr(self, key)
PROVIDER_LOCATION = 'fake_provider_location'
test_snapshot = test_snapshot()
test_snapshot.id = 'fake_snap_id'
test_snapshot.name = 'snapshot-%s' % test_snapshot.id
test_snapshot.volume_id = 'fake_volume_id'
test_snapshot.provider_location = PROVIDER_LOCATION
def get_fake_net_interface_get_iter_response():
return etree.XML("""<results status="passed">
<num-records>1</num-records>
<attributes-list>
<net-interface-info></net-interface-info>
<address>FAKE_IP</address>
</attributes-list>
</results>""")
def get_fake_ifs():
list_of_ifs = [
etree.XML("""<net-interface-info>
<address>FAKE_IP</address></net-interface-info>"""),
etree.XML("""<net-interface-info>
<address>FAKE_IP2</address></net-interface-info>"""),
etree.XML("""<net-interface-info>
<address>FAKE_IP3</address></net-interface-info>"""),
]
return [netapp_api.NaElement(el) for el in list_of_ifs]

View File

@ -24,6 +24,8 @@ import ddt
from lxml import etree
import mock
from oslo_utils import timeutils
from cinder import exception
from cinder import test
import cinder.tests.unit.volume.drivers.netapp.dataontap.client.fakes \
@ -127,11 +129,25 @@ class NetAppBlockStorage7modeLibraryTestCase(test.TestCase):
self.assertRaises(exception.NetAppDriverException,
self.library.check_for_setup_error)
def test_check_for_setup_error_too_old(self):
self.zapi_client.get_ontapi_version.return_value = (1, 8)
@ddt.data(None, (1, 8))
def test_check_for_setup_error_unsupported_or_no_version(self, version):
self.zapi_client.get_ontapi_version.return_value = version
self.assertRaises(exception.VolumeBackendAPIException,
self.library.check_for_setup_error)
@ddt.data(None, fake.VFILER)
def test__get_owner(self, vfiler):
self.library.configuration.netapp_server_hostname = 'openstack'
self.library.vfiler = vfiler
expected_owner = 'openstack'
retval = self.library._get_owner()
if vfiler:
expected_owner += ':' + vfiler
self.assertEqual(expected_owner, retval)
def test_find_mapped_lun_igroup(self):
response = netapp_api.NaElement(etree.XML("""
<results status="passed">
@ -635,6 +651,78 @@ class NetAppBlockStorage7modeLibraryTestCase(test.TestCase):
self.assertListEqual([], pools)
@ddt.data((None, False, False),
(30, True, False),
(30, False, True))
@ddt.unpack
def test__refresh_volume_info_already_running(self,
vol_refresh_time,
vol_refresh_voluntary,
is_newer):
mock_warning_log = self.mock_object(block_7mode.LOG, 'warning')
self.library.vol_refresh_time = vol_refresh_time
self.library.vol_refresh_voluntary = vol_refresh_voluntary
self.library.vol_refresh_interval = 30
self.mock_object(timeutils, 'is_newer_than', mock.Mock(
return_value=is_newer))
self.mock_object(na_utils, 'set_safe_attr', mock.Mock(
return_value=False))
retval = self.library._refresh_volume_info()
self.assertIsNone(retval)
# Assert no values are unset by the method
self.assertEqual(vol_refresh_voluntary,
self.library.vol_refresh_voluntary)
self.assertEqual(vol_refresh_time, self.library.vol_refresh_time)
if timeutils.is_newer_than.called:
timeutils.is_newer_than.assert_called_once_with(
vol_refresh_time, self.library.vol_refresh_interval)
na_utils.set_safe_attr.assert_has_calls([
mock.call(self.library, 'vol_refresh_running', True),
mock.call(self.library, 'vol_refresh_running', False)])
self.assertEqual(1, mock_warning_log.call_count)
def test__refresh_volume_info(self):
mock_warning_log = self.mock_object(block_7mode.LOG, 'warning')
self.library.vol_refresh_time = None
self.library.vol_refresh_voluntary = True
self.mock_object(timeutils, 'is_newer_than')
self.mock_object(self.library.zapi_client, 'get_filer_volumes')
self.mock_object(self.library, '_get_filtered_pools', mock.Mock(
return_value=['vol1', 'vol2']))
self.mock_object(na_utils, 'set_safe_attr', mock.Mock(
return_value=True))
retval = self.library._refresh_volume_info()
self.assertIsNone(retval)
self.assertEqual(False, self.library.vol_refresh_voluntary)
self.assertEqual(['vol1', 'vol2'], self.library.volume_list)
self.assertIsNotNone(self.library.vol_refresh_time)
na_utils.set_safe_attr.assert_has_calls([
mock.call(self.library, 'vol_refresh_running', True),
mock.call(self.library, 'vol_refresh_running', False)])
self.assertFalse(mock_warning_log.called)
def test__refresh_volume_info_exception(self):
mock_warning_log = self.mock_object(block_7mode.LOG, 'warning')
self.library.vol_refresh_time = None
self.library.vol_refresh_voluntary = True
self.mock_object(timeutils, 'is_newer_than')
self.mock_object(na_utils, 'set_safe_attr', mock.Mock(
return_value=True))
self.mock_object(
self.library.zapi_client, 'get_filer_volumes',
mock.Mock(side_effect=exception.NetAppDriverException))
self.mock_object(self.library, '_get_filtered_pools')
retval = self.library._refresh_volume_info()
self.assertIsNone(retval)
self.assertFalse(self.library._get_filtered_pools.called)
self.assertEqual(1, mock_warning_log.call_count)
def test_delete_volume(self):
self.library.vol_refresh_voluntary = False
mock_super_delete_volume = self.mock_object(

View File

@ -16,23 +16,30 @@
"""
Unit tests for the NetApp NFS storage driver
"""
import os
import copy
import os
import threading
import time
import ddt
import mock
from os_brick.remotefs import remotefs as remotefs_brick
from oslo_concurrency import processutils
from oslo_utils import units
import shutil
from cinder import context
from cinder import exception
from cinder import test
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import fake_volume
from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
from cinder import utils
from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
from cinder.volume.drivers.netapp.dataontap import nfs_base
from cinder.volume.drivers.netapp import utils as na_utils
from cinder.volume.drivers import nfs
from cinder.volume.drivers import remotefs
@ddt.ddt
@ -44,6 +51,10 @@ class NetAppNfsDriverTestCase(test.TestCase):
configuration.nfs_mount_point_base = '/mnt/test'
configuration.reserved_percentage = 0
configuration.max_over_subscription_ratio = 1.1
self.fake_nfs_export_1 = fake.NFS_EXPORT_1
self.fake_nfs_export_2 = fake.NFS_EXPORT_2
self.fake_mount_point = fake.MOUNT_POINT
self.ctxt = context.RequestContext('fake', 'fake', auth_token=True)
kwargs = {'configuration': configuration}
@ -105,6 +116,11 @@ class NetAppNfsDriverTestCase(test.TestCase):
get_capacity.assert_has_calls([
mock.call(flexvol_path=fake.EXPORT_PATH)])
def test_get_pool(self):
pool = self.driver.get_pool({'provider_location': 'fake-share'})
self.assertEqual('fake-share', pool)
def test_create_volume(self):
self.mock_object(self.driver, '_ensure_shares_mounted')
self.mock_object(na_utils, 'get_volume_extra_specs')
@ -135,17 +151,6 @@ class NetAppNfsDriverTestCase(test.TestCase):
self.driver.create_volume,
fake.NFS_VOLUME)
def test_create_volume_from_snapshot(self):
provider_location = fake.POOL_NAME
snapshot = fake.CLONE_SOURCE
self.mock_object(self.driver, '_clone_source_to_destination_volume',
mock.Mock(return_value=provider_location))
result = self.driver.create_cloned_volume(fake.NFS_VOLUME,
snapshot)
self.assertEqual(provider_location, result)
def test_clone_source_to_destination_volume(self):
self.mock_object(self.driver, '_get_volume_location', mock.Mock(
return_value=fake.POOL_NAME))
@ -243,6 +248,22 @@ class NetAppNfsDriverTestCase(test.TestCase):
fake.CLONE_SOURCE,
fake.NFS_VOLUME)
def test_create_volume_from_snapshot(self):
volume = fake.VOLUME
expected_source = {
'name': fake.SNAPSHOT_NAME,
'size': fake.SIZE,
'id': fake.VOLUME_ID,
}
mock_clone_call = self.mock_object(
self.driver, '_clone_source_to_destination_volume',
mock.Mock(return_value='fake'))
retval = self.driver.create_volume_from_snapshot(volume, fake.SNAPSHOT)
self.assertEqual('fake', retval)
mock_clone_call.assert_called_once_with(expected_source, volume)
def test_create_cloned_volume(self):
provider_location = fake.POOL_NAME
src_vref = fake.CLONE_SOURCE
@ -270,6 +291,188 @@ class NetAppNfsDriverTestCase(test.TestCase):
fake.SNAPSHOT['volume_name'], fake.SNAPSHOT['name'],
fake.SNAPSHOT['volume_id'], is_snapshot=True)
@ddt.data(True, False)
def test_delete_snapshot(self, volume_present):
updates = {
'name': fake.SNAPSHOT_NAME,
'volume_size': fake.SIZE,
'volume_id': fake.VOLUME_ID,
'volume_name': fake.VOLUME_NAME,
'busy': False,
}
snapshot = fake_snapshot.fake_snapshot_obj(self.ctxt, **updates)
self.mock_object(self.driver, '_get_provider_location',
mock.Mock(return_value=fake.SNAPSHOT_MOUNT))
self.mock_object(self.driver, '_volume_not_present',
mock.Mock(return_value=volume_present))
self.mock_object(self.driver, '_execute')
self.mock_object(self.driver, '_get_volume_path',
mock.Mock(return_value='fake'))
self.driver._execute_as_root = True
retval = self.driver.delete_snapshot(snapshot)
if volume_present:
self.assertTrue(retval)
self.driver._execute.assert_not_called()
else:
self.assertIsNone(retval)
self.driver._execute.assert_called_once_with(
'rm', 'fake', run_as_root=True)
def test__get_volume_location(self):
volume_id = fake.VOLUME_ID
self.mock_object(self.driver, '_get_host_ip',
mock.Mock(return_value='168.124.10.12'))
self.mock_object(self.driver, '_get_export_path',
mock.Mock(return_value='/fake_mount_path'))
retval = self.driver._get_volume_location(volume_id)
self.assertEqual('168.124.10.12:/fake_mount_path', retval)
self.driver._get_host_ip.assert_called_once_with(volume_id)
self.driver._get_export_path.assert_called_once_with(volume_id)
def test__clone_backing_file_for_volume(self):
self.assertRaises(NotImplementedError,
self.driver._clone_backing_file_for_volume,
fake.VOLUME_NAME, fake.CLONE_SOURCE_NAME,
fake.VOLUME_ID, share=None)
def test__get_provider_location(self):
updates = {'provider_location': fake.PROVIDER_LOCATION}
volume = fake_volume.fake_volume_obj(self.ctxt, **updates)
self.mock_object(self.driver.db, 'volume_get', mock.Mock(
return_value=volume))
retval = self.driver._get_provider_location(fake.VOLUME_ID)
self.assertEqual(fake.PROVIDER_LOCATION, retval)
@ddt.data(None, processutils.ProcessExecutionError)
def test__volume_not_present(self, side_effect):
self.mock_object(self.driver, '_get_volume_path')
self.mock_object(self.driver, '_try_execute',
mock.Mock(side_effect=side_effect))
retval = self.driver._volume_not_present(
fake.MOUNT_PATH, fake.VOLUME_NAME)
self.assertEqual(side_effect is not None, retval)
@mock.patch.object(time, 'sleep')
def test__try_execute_exception(self, patched_sleep):
self.mock_object(self.driver, '_execute', mock.Mock(
side_effect=processutils.ProcessExecutionError))
mock_exception_log = self.mock_object(nfs_base.LOG, 'exception')
self.driver.configuration.num_shell_tries = 3
self.assertRaises(processutils.ProcessExecutionError,
self.driver._try_execute,
'fake-command', attr1='val1', attr2='val2')
self.assertEqual(2, mock_exception_log.call_count)
self.driver._execute.assert_has_calls([
mock.call('fake-command', attr1='val1', attr2='val2'),
mock.call('fake-command', attr1='val1', attr2='val2'),
mock.call('fake-command', attr1='val1', attr2='val2')])
self.assertEqual(2, time.sleep.call_count)
patched_sleep.assert_has_calls([mock.call(1), mock.call(4)])
def test__update_volume_stats(self):
self.assertRaises(NotImplementedError,
self.driver._update_volume_stats)
def test_copy_image_to_volume_base_exception(self):
updates = {
'name': fake.VOLUME_NAME,
'id': fake.VOLUME_ID,
'provider_location': fake.PROVIDER_LOCATION,
}
mock_info_log = self.mock_object(nfs_base.LOG, 'info')
fake_vol = fake_volume.fake_volume_obj(self.ctxt, **updates)
self.mock_object(remotefs.RemoteFSDriver, 'copy_image_to_volume',
mock.Mock(side_effect=exception.NfsException))
self.assertRaises(exception.NfsException,
self.driver.copy_image_to_volume,
'fake_context', fake_vol,
'fake_img_service', fake.IMAGE_FILE_ID)
mock_info_log.assert_not_called()
@ddt.data(None, Exception)
def test_copy_image_to_volume(self, exc):
mock_log = self.mock_object(nfs_base, 'LOG')
self.mock_object(remotefs.RemoteFSDriver, 'copy_image_to_volume')
self.mock_object(self.driver, '_do_clone_rel_img_cache',
mock.Mock(side_effect=exc))
retval = self.driver.copy_image_to_volume(
'fake_context', fake.NFS_VOLUME, 'fake_img_service',
fake.IMAGE_FILE_ID)
self.assertIsNone(retval)
self.assertEqual(exc is not None, mock_log.warning.called)
self.assertEqual(2, mock_log.info.call_count)
@ddt.data(True, False)
def test_do_clone_rel_img_cache(self, path_exists):
self.mock_object(nfs_base.LOG, 'info')
self.mock_object(utils, 'synchronized',
mock.Mock(return_value=lambda f: f))
self.mock_object(self.driver, '_get_mount_point_for_share',
mock.Mock(return_value='dir'))
self.mock_object(os.path, 'exists',
mock.Mock(return_value=path_exists))
self.mock_object(self.driver, '_clone_backing_file_for_volume')
retval = self.driver._do_clone_rel_img_cache(
fake.CLONE_SOURCE_NAME, fake.CLONE_DESTINATION_NAME,
fake.NFS_SHARE, 'fake_cache_file')
self.assertIsNone(retval)
self.assertTrue(self.driver._get_mount_point_for_share.called)
if not path_exists:
self.driver._clone_backing_file_for_volume.assert_called_once_with(
fake.CLONE_SOURCE_NAME, fake.CLONE_DESTINATION_NAME,
share=fake.NFS_SHARE, volume_id=None)
else:
self.driver._clone_backing_file_for_volume.assert_not_called()
os.path.exists.assert_called_once_with(
'dir/' + fake.CLONE_DESTINATION_NAME)
def test__spawn_clean_cache_job_clean_job_setup(self):
self.driver.cleaning = True
mock_debug_log = self.mock_object(nfs_base.LOG, 'debug')
self.mock_object(utils, 'synchronized',
mock.Mock(return_value=lambda f: f))
retval = self.driver._spawn_clean_cache_job()
self.assertIsNone(retval)
self.assertEqual(1, mock_debug_log.call_count)
def test__spawn_clean_cache_job_new_clean_job(self):
class FakeTimer(object):
def start(self):
pass
fake_timer = FakeTimer()
self.mock_object(utils, 'synchronized',
mock.Mock(return_value=lambda f: f))
self.mock_object(fake_timer, 'start')
self.mock_object(nfs_base.LOG, 'debug')
self.mock_object(self.driver, '_clean_image_cache')
self.mock_object(threading, 'Timer',
mock.Mock(return_value=fake_timer))
retval = self.driver._spawn_clean_cache_job()
self.assertIsNone(retval)
threading.Timer.assert_called_once_with(
0, self.driver._clean_image_cache)
fake_timer.start.assert_called_once_with()
def test_cleanup_volume_on_failure(self):
path = '%s/%s' % (fake.NFS_SHARE, fake.NFS_VOLUME['name'])
mock_local_path = self.mock_object(self.driver, 'local_path')
@ -352,6 +555,22 @@ class NetAppNfsDriverTestCase(test.TestCase):
self.assertEqual(expected, result)
def test_construct_image_url_loc(self):
img_loc = fake.FAKE_IMAGE_LOCATION
locations = self.driver._construct_image_nfs_url(img_loc)
self.assertIn("nfs://host/path/image-id-0", locations)
self.assertIn("nfs://host/path/image-id-6", locations)
self.assertEqual(2, len(locations))
def test_construct_image_url_direct(self):
img_loc = ("nfs://host/path/image-id", None)
locations = self.driver._construct_image_nfs_url(img_loc)
self.assertIn("nfs://host/path/image-id", locations)
def test_extend_volume(self):
new_size = 100
@ -499,3 +718,185 @@ class NetAppNfsDriverTestCase(test.TestCase):
size,
thin=thin)
self.assertEqual(expected, result)
def test_get_share_mount_and_vol_from_vol_ref(self):
self.mock_object(na_utils, 'resolve_hostname',
mock.Mock(return_value='10.12.142.11'))
self.mock_object(os.path, 'isfile', mock.Mock(return_value=True))
self.driver._mounted_shares = [self.fake_nfs_export_1]
vol_path = "%s/%s" % (self.fake_nfs_export_1, 'test_file_name')
vol_ref = {'source-name': vol_path}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
(share, mount, file_path) = (
self.driver._get_share_mount_and_vol_from_vol_ref(vol_ref))
self.assertEqual(self.fake_nfs_export_1, share)
self.assertEqual(self.fake_mount_point, mount)
self.assertEqual('test_file_name', file_path)
def test_get_share_mount_and_vol_from_vol_ref_with_bad_ref(self):
self.mock_object(na_utils, 'resolve_hostname',
mock.Mock(return_value='10.12.142.11'))
self.driver._mounted_shares = [self.fake_nfs_export_1]
vol_ref = {'source-id': '1234546'}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver._get_share_mount_and_vol_from_vol_ref,
vol_ref)
def test_get_share_mount_and_vol_from_vol_ref_where_not_found(self):
self.mock_object(na_utils, 'resolve_hostname',
mock.Mock(return_value='10.12.142.11'))
self.driver._mounted_shares = [self.fake_nfs_export_1]
vol_path = "%s/%s" % (self.fake_nfs_export_2, 'test_file_name')
vol_ref = {'source-name': vol_path}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver._get_share_mount_and_vol_from_vol_ref,
vol_ref)
def test_get_share_mount_and_vol_from_vol_ref_where_is_dir(self):
self.mock_object(na_utils, 'resolve_hostname',
mock.Mock(return_value='10.12.142.11'))
self.driver._mounted_shares = [self.fake_nfs_export_1]
vol_ref = {'source-name': self.fake_nfs_export_2}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver._get_share_mount_and_vol_from_vol_ref,
vol_ref)
def test_manage_existing(self):
self.mock_object(utils, 'get_file_size',
mock.Mock(return_value=1074253824))
self.driver._mounted_shares = [self.fake_nfs_export_1]
test_file = 'test_file_name'
volume = fake.FAKE_MANAGE_VOLUME
vol_path = "%s/%s" % (self.fake_nfs_export_1, test_file)
vol_ref = {'source-name': vol_path}
self.driver._check_volume_type = mock.Mock()
shutil.move = mock.Mock()
self.stubs.Set(self.driver, '_execute', mock.Mock())
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.driver._get_share_mount_and_vol_from_vol_ref = mock.Mock(
return_value=(self.fake_nfs_export_1, self.fake_mount_point,
test_file))
mock_get_specs = self.mock_object(na_utils, 'get_volume_extra_specs')
mock_get_specs.return_value = {}
self.mock_object(self.driver, '_do_qos_for_volume')
location = self.driver.manage_existing(volume, vol_ref)
self.assertEqual(self.fake_nfs_export_1, location['provider_location'])
self.driver._check_volume_type.assert_called_once_with(
volume, self.fake_nfs_export_1, test_file, {})
def test_manage_existing_move_fails(self):
self.mock_object(utils, 'get_file_size',
mock.Mock(return_value=1074253824))
self.driver._mounted_shares = [self.fake_nfs_export_1]
test_file = 'test_file_name'
volume = fake.FAKE_MANAGE_VOLUME
vol_path = "%s/%s" % (self.fake_nfs_export_1, test_file)
vol_ref = {'source-name': vol_path}
mock_check_volume_type = self.driver._check_volume_type = mock.Mock()
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.driver._get_share_mount_and_vol_from_vol_ref = mock.Mock(
return_value=(self.fake_nfs_export_1, self.fake_mount_point,
test_file))
self.driver._execute = mock.Mock(side_effect=OSError)
mock_get_specs = self.mock_object(na_utils, 'get_volume_extra_specs')
mock_get_specs.return_value = {}
self.mock_object(self.driver, '_do_qos_for_volume')
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.manage_existing, volume, vol_ref)
mock_check_volume_type.assert_called_once_with(
volume, self.fake_nfs_export_1, test_file, {})
def test_unmanage(self):
mock_log = self.mock_object(nfs_base, 'LOG')
volume = {'id': '123', 'provider_location': '/share'}
retval = self.driver.unmanage(volume)
self.assertIsNone(retval)
self.assertEqual(1, mock_log.info.call_count)
def test_manage_existing_get_size(self):
test_file = 'test_file_name'
self.driver._get_share_mount_and_vol_from_vol_ref = mock.Mock(
return_value=(self.fake_nfs_export_1, self.fake_mount_point,
test_file))
self.mock_object(utils, 'get_file_size',
mock.Mock(return_value=1073741824))
self.driver._mounted_shares = [self.fake_nfs_export_1]
volume = fake.FAKE_MANAGE_VOLUME
vol_path = "%s/%s" % (self.fake_nfs_export_1, test_file)
vol_ref = {'source-name': vol_path}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
vol_size = self.driver.manage_existing_get_size(volume, vol_ref)
self.assertEqual(1, vol_size)
def test_manage_existing_get_size_round_up(self):
test_file = 'test_file_name'
self.driver._get_share_mount_and_vol_from_vol_ref = mock.Mock(
return_value=(self.fake_nfs_export_1, self.fake_mount_point,
test_file))
self.mock_object(utils, 'get_file_size',
mock.Mock(return_value=1073760270))
self.driver._mounted_shares = [self.fake_nfs_export_1]
volume = fake.FAKE_MANAGE_VOLUME
vol_path = "%s/%s" % (self.fake_nfs_export_1, test_file)
vol_ref = {'source-name': vol_path}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
vol_size = self.driver.manage_existing_get_size(volume, vol_ref)
self.assertEqual(2, vol_size)
def test_manage_existing_get_size_error(self):
test_file = 'test_file_name'
self.driver._get_share_mount_and_vol_from_vol_ref = mock.Mock(
return_value=(self.fake_nfs_export_1, self.fake_mount_point,
test_file))
self.driver._mounted_shares = [self.fake_nfs_export_1]
volume = fake.FAKE_MANAGE_VOLUME
vol_path = "%s/%s" % (self.fake_nfs_export_1, test_file)
vol_ref = {'source-name': vol_path}
self.driver._ensure_shares_mounted = mock.Mock()
self.driver._get_mount_point_for_share = mock.Mock(
return_value=self.fake_mount_point)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.manage_existing_get_size,
volume,
vol_ref)

View File

@ -23,6 +23,7 @@ from oslo_service import loopingcall
from oslo_utils import units
from cinder import exception
from cinder.image import image_utils
from cinder import test
from cinder.tests.unit.volume.drivers.netapp.dataontap import fakes as fake
from cinder.tests.unit.volume.drivers.netapp.dataontap.utils import fakes as \
@ -81,6 +82,30 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.assertTrue(mock_check_flags.called)
self.assertTrue(mock_super_do_setup.called)
def test__update_volume_stats(self):
mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
self.mock_object(self.driver, 'get_filter_function')
self.mock_object(self.driver, 'get_goodness_function')
self.mock_object(self.driver, '_spawn_clean_cache_job')
self.driver.zapi_client = mock.Mock()
self.mock_object(
self.driver, '_get_pool_stats', mock.Mock(return_value={}))
expected_stats = {
'driver_version': self.driver.VERSION,
'pools': {},
'sparse_copy_volume': True,
'storage_protocol': 'nfs',
'vendor_name': 'NetApp',
'volume_backend_name': 'NetApp_NFS_Cluster_direct',
}
retval = self.driver._update_volume_stats()
self.assertIsNone(retval)
self.assertTrue(self.driver._spawn_clean_cache_job.called)
self.assertEqual(1, mock_debug_log.call_count)
self.assertEqual(expected_stats, self.driver._stats)
def test_get_pool_stats(self):
self.driver.zapi_client = mock.Mock()
@ -252,6 +277,68 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.assertEqual({}, result)
@ddt.data(['/mnt/img-id1', '/mnt/img-id2'], [])
def test__shortlist_del_eligible_files(self, old_files):
self.driver.zapi_client = mock.Mock()
self.driver.zapi_client.get_file_usage = mock.Mock(return_value='1000')
mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
self.mock_object(self.driver, '_get_vserver_and_exp_vol',
mock.Mock(return_value=('openstack', 'fake_share')))
expected_list = [(o, '1000') for o in old_files]
observed_list = self.driver._shortlist_del_eligible_files(
'fake_ip:fake_share', old_files)
self.assertEqual(expected_list, observed_list)
self.assertEqual(1, mock_debug_log.call_count)
@ddt.data({'ip': None, 'shares': None},
{'ip': 'fake_ip', 'shares': ['fip:/fsh1']})
@ddt.unpack
def test__share_match_for_ip_no_match(self, ip, shares):
def side_effect(arg):
if arg == 'fake_ip':
return 'openstack'
return None
self.mock_object(self.driver, '_get_vserver_for_ip',
mock.Mock(side_effect=side_effect))
mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
retval = self.driver._share_match_for_ip(ip, shares)
self.assertIsNone(retval)
self.assertEqual(1, mock_debug_log.call_count)
def test__share_match_for_ip(self):
shares = ['fip:/fsh1']
self.mock_object(self.driver, '_get_vserver_for_ip',
mock.Mock(return_value='openstack'))
mock_debug_log = self.mock_object(nfs_cmode.LOG, 'debug')
retval = self.driver._share_match_for_ip('fip', shares)
self.assertEqual('fip:/fsh1', retval)
self.assertEqual(1, mock_debug_log.call_count)
def test__get_vserver_for_ip_ignores_zapi_exception(self):
self.driver.zapi_client = mock.Mock()
self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
side_effect=exception.NotFound)
vserver = self.driver._get_vserver_for_ip('FAKE_IP')
self.assertIsNone(vserver)
def test__get_vserver_for_ip(self):
self.driver.zapi_client = mock.Mock()
self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
return_value=fake.get_fake_ifs())
vserver = self.driver._get_vserver_for_ip('FAKE_IP')
self.assertIsNone(vserver)
def test_check_for_setup_error(self):
super_check_for_setup_error = self.mock_object(
nfs_base.NetAppNfsDriver, 'check_for_setup_error')
@ -290,7 +377,10 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.mock_object(na_utils,
'get_valid_qos_policy_group_info',
mock.Mock(return_value='fake_qos_policy_group_info'))
self.driver.zapi_client = mock.Mock(side_effect=Exception)
self.mock_object(
self.driver.zapi_client,
'mark_qos_policy_group_for_deletion',
mock.Mock(side_effect=exception.NetAppDriverException))
self.driver.delete_volume(fake_volume)
@ -312,17 +402,23 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock_filer_delete.assert_called_once_with(fake.NFS_VOLUME)
self.assertEqual(0, mock_super_delete.call_count)
def test_delete_backing_file_for_volume_exception_path(self):
@ddt.data(True, False)
def test_delete_backing_file_for_volume_exception_path(self, super_exc):
mock_exception_log = self.mock_object(nfs_cmode.LOG, 'exception')
exception_call_count = 2 if super_exc else 1
mock_filer_delete = self.mock_object(self.driver,
'_delete_volume_on_filer')
mock_filer_delete.side_effect = [Exception]
mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
'delete_volume')
if super_exc:
mock_super_delete.side_effect = [Exception]
self.driver._delete_backing_file_for_volume(fake.NFS_VOLUME)
mock_filer_delete.assert_called_once_with(fake.NFS_VOLUME)
mock_super_delete.assert_called_once_with(fake.NFS_VOLUME)
self.assertEqual(exception_call_count, mock_exception_log.call_count)
def test_delete_volume_on_filer(self):
mock_get_vs_ip = self.mock_object(self.driver, '_get_export_ip_path')
@ -356,17 +452,23 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
mock_filer_delete.assert_called_once_with(fake.test_snapshot)
self.assertEqual(0, mock_super_delete.call_count)
def test_delete_backing_file_for_snapshot_exception_path(self):
@ddt.data(True, False)
def test_delete_backing_file_for_snapshot_exception_path(self, super_exc):
mock_exception_log = self.mock_object(nfs_cmode.LOG, 'exception')
exception_call_count = 2 if super_exc else 1
mock_filer_delete = self.mock_object(
self.driver, '_delete_snapshot_on_filer')
mock_filer_delete.side_effect = [Exception]
mock_super_delete = self.mock_object(nfs_base.NetAppNfsDriver,
'delete_snapshot')
if super_exc:
mock_super_delete.side_effect = [Exception]
self.driver._delete_backing_file_for_snapshot(fake.test_snapshot)
mock_filer_delete.assert_called_once_with(fake.test_snapshot)
mock_super_delete.assert_called_once_with(fake.test_snapshot)
self.assertEqual(exception_call_count, mock_exception_log.call_count)
def test_delete_snapshot_on_filer(self):
mock_get_vs_ip = self.mock_object(self.driver, '_get_export_ip_path')
@ -547,6 +649,164 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
fake.FLEXVOL, fake.FLEXVOL, 'fake_clone', fake.VSERVER_NAME,
is_snapshot=is_snapshot)
def test__clone_backing_file_for_volume(self):
body = fake.get_fake_net_interface_get_iter_response()
self.driver.zapi_client.get_if_info_by_ip = mock.Mock(
return_value=[netapp_api.NaElement(body)])
self.driver.zapi_client.get_vol_by_junc_vserver = mock.Mock(
return_value='nfsvol')
self.mock_object(self.driver, '_get_export_ip_path',
mock.Mock(return_value=('127.0.0.1', 'fakepath')))
retval = self.driver._clone_backing_file_for_volume(
'vol', 'clone', 'vol_id', share='share', is_snapshot=True)
self.assertIsNone(retval)
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):
self.mock_object(nfs_cmode.LOG, 'debug')
drv = self.driver
context = object()
volume = {'id': 'vol_id', 'name': 'name'}
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=[])
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())
drv._discover_file_till_timeout = mock.Mock()
# Verify the original error is propagated
self.assertRaises(OSError, drv._copy_from_img_service,
context, volume, image_service, image_id)
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(
self, mock_qemu_img_info):
drv = self.driver
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.show.return_value = {'size': 1, 'disk_format': 'raw'}
drv._check_get_nfs_path_segs =\
mock.Mock(return_value=('ip1', '/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_provider_location = mock.Mock(return_value='share')
drv._execute = mock.Mock()
drv._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
drv._discover_file_till_timeout = mock.Mock(return_value=True)
img_inf = mock.Mock()
img_inf.file_format = 'raw'
mock_qemu_img_info.return_value = img_inf
drv._check_share_can_hold_size = mock.Mock()
drv._move_nfs_file = mock.Mock(return_value=True)
drv._delete_file_at_path = mock.Mock()
drv._clone_file_dst_exists = mock.Mock()
drv._post_clone_image = mock.Mock()
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_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, 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(
self, mock_exists, mock_qemu_img_info, mock_cvrt_image):
drv = self.driver
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.show.return_value = {'size': 1,
'disk_format': 'qcow2'}
drv._check_get_nfs_path_segs =\
mock.Mock(return_value=('ip1', '/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_provider_location = mock.Mock(return_value='share')
drv._execute = mock.Mock()
drv._get_mount_point_for_share = mock.Mock(return_value='mnt_point')
img_inf = mock.Mock()
img_inf.file_format = 'raw'
mock_qemu_img_info.return_value = img_inf
drv._check_share_can_hold_size = mock.Mock()
drv._move_nfs_file = mock.Mock(return_value=True)
drv._delete_file_at_path = mock.Mock()
drv._clone_file_dst_exists = mock.Mock()
drv._post_clone_image = mock.Mock()
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_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)
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):
drv = self.driver
volume = {'id': 'vol_id', 'name': 'name', 'size': 1}
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,
'get_valid_qos_policy_group_info')
@ -782,6 +1042,95 @@ class NetAppCmodeNfsDriverTestCase(test.TestCase):
self.driver._get_host_ip.assert_called_once_with(fake.VOLUME_ID)
self.driver._get_export_path.assert_called_once_with(fake.VOLUME_ID)
def test_copy_image_to_volume_copyoffload_non_cached_ssc_update(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'
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')])
drv._copy_from_cache = mock.Mock(return_value=True)
drv.copy_image_to_volume(context, volume, image_service, image_id)
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):
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=False)
drv._copy_from_img_service = mock.Mock()
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)
def test_copy_image_to_volume_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'
drv.zapi_client = mock.Mock()
drv.zapi_client.get_ontapi_version = mock.Mock(return_value=(1, 20))
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)
self.assertIsNone(retval)
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'
source_path = '/openstack/img-cache-imgid'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff