cinder/cinder/tests/volume/drivers/netapp/dataontap/test_block_base.py

444 lines
21 KiB
Python

# Copyright (c) 2014 Alex Meade. All rights reserved.
# Copyright (c) 2014 Clinton Knight. All rights reserved.
# Copyright (c) 2014 Andrew Kerr. All rights reserved.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
Mock unit tests for the NetApp block storage library
"""
import uuid
import mock
from cinder import exception
from cinder import test
from cinder.tests.volume.drivers.netapp.dataontap import fakes as fake
from cinder.volume.drivers.netapp.dataontap import block_base
from cinder.volume.drivers.netapp.dataontap.client import api as netapp_api
from cinder.volume.drivers.netapp import utils as na_utils
class NetAppBlockStorageLibraryTestCase(test.TestCase):
def setUp(self):
super(NetAppBlockStorageLibraryTestCase, self).setUp()
kwargs = {'configuration': mock.Mock()}
self.library = block_base.NetAppBlockStorageLibrary(
'driver', 'protocol', **kwargs)
self.library.zapi_client = mock.Mock()
self.zapi_client = self.library.zapi_client
self.mock_request = mock.Mock()
def tearDown(self):
super(NetAppBlockStorageLibraryTestCase, self).tearDown()
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr',
mock.Mock(return_value={'Volume': 'vol1'}))
def test_get_pool(self):
pool = self.library.get_pool({'name': 'volume-fake-uuid'})
self.assertEqual(pool, 'vol1')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr',
mock.Mock(return_value=None))
def test_get_pool_no_metadata(self):
pool = self.library.get_pool({'name': 'volume-fake-uuid'})
self.assertEqual(pool, None)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr',
mock.Mock(return_value=dict()))
def test_get_pool_volume_unknown(self):
pool = self.library.get_pool({'name': 'volume-fake-uuid'})
self.assertEqual(pool, None)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun_handle', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_add_lun_to_table', mock.Mock())
@mock.patch.object(na_utils, 'get_volume_extra_specs',
mock.Mock(return_value=None))
@mock.patch.object(block_base, 'LOG', mock.Mock())
def test_create_volume(self):
self.library.zapi_client.get_lun_by_args.return_value = ['lun']
self.library.create_volume({'name': 'lun1', 'size': 100,
'id': uuid.uuid4(),
'host': 'hostname@backend#vol1'})
self.library._create_lun.assert_called_once_with(
'vol1', 'lun1', 107374182400, mock.ANY, None)
self.assertEqual(0, block_base.LOG.warning.call_count)
def test_create_volume_no_pool_provided_by_scheduler(self):
self.assertRaises(exception.InvalidHost, self.library.create_volume,
{'name': 'lun1', 'size': 100,
'id': uuid.uuid4(),
'host': 'hostname@backend'}) # missing pool
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_or_create_igroup')
def test_map_lun(self, mock_get_or_create_igroup, mock_get_lun_attr):
os = 'linux'
protocol = 'fcp'
mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
self.zapi_client.map_lun.return_value = '1'
lun_id = self.library._map_lun('fake_volume',
fake.FC_FORMATTED_INITIATORS,
protocol, None)
self.assertEqual(lun_id, '1')
mock_get_or_create_igroup.assert_called_once_with(
fake.FC_FORMATTED_INITIATORS, protocol, os)
self.zapi_client.map_lun.assert_called_once_with(
fake.LUN1, fake.IGROUP1_NAME, lun_id=None)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_or_create_igroup')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_find_mapped_lun_igroup')
def test_map_lun_preexisting(self, mock_find_mapped_lun_igroup,
mock_get_or_create_igroup, mock_get_lun_attr):
os = 'linux'
protocol = 'fcp'
mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
mock_find_mapped_lun_igroup.return_value = (fake.IGROUP1_NAME, '2')
self.zapi_client.map_lun.side_effect = netapp_api.NaApiError
lun_id = self.library._map_lun(
'fake_volume', fake.FC_FORMATTED_INITIATORS, protocol, None)
self.assertEqual(lun_id, '2')
mock_find_mapped_lun_igroup.assert_called_once_with(
fake.LUN1, fake.FC_FORMATTED_INITIATORS)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_or_create_igroup')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_find_mapped_lun_igroup')
def test_map_lun_api_error(self, mock_find_mapped_lun_igroup,
mock_get_or_create_igroup, mock_get_lun_attr):
os = 'linux'
protocol = 'fcp'
mock_get_lun_attr.return_value = {'Path': fake.LUN1, 'OsType': os}
mock_get_or_create_igroup.return_value = fake.IGROUP1_NAME
mock_find_mapped_lun_igroup.return_value = (None, None)
self.zapi_client.map_lun.side_effect = netapp_api.NaApiError
self.assertRaises(netapp_api.NaApiError, self.library._map_lun,
'fake_volume', fake.FC_FORMATTED_INITIATORS,
protocol, None)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_find_mapped_lun_igroup')
def test_unmap_lun(self, mock_find_mapped_lun_igroup):
mock_find_mapped_lun_igroup.return_value = (fake.IGROUP1_NAME, 1)
self.library._unmap_lun(fake.LUN1, fake.FC_FORMATTED_INITIATORS)
self.zapi_client.unmap_lun.assert_called_once_with(fake.LUN1,
fake.IGROUP1_NAME)
def test_find_mapped_lun_igroup(self):
self.assertRaises(NotImplementedError,
self.library._find_mapped_lun_igroup,
fake.LUN1,
fake.FC_FORMATTED_INITIATORS)
def test_has_luns_mapped_to_initiators(self):
self.zapi_client.has_luns_mapped_to_initiators.return_value = True
self.assertTrue(self.library._has_luns_mapped_to_initiators(
fake.FC_FORMATTED_INITIATORS))
self.zapi_client.has_luns_mapped_to_initiators.assert_called_once_with(
fake.FC_FORMATTED_INITIATORS)
def test_get_or_create_igroup_preexisting(self):
self.zapi_client.get_igroup_by_initiators.return_value = [fake.IGROUP1]
igroup_name = self.library._get_or_create_igroup(
fake.FC_FORMATTED_INITIATORS, 'fcp', 'linux')
self.assertEqual(igroup_name, fake.IGROUP1_NAME)
self.zapi_client.get_igroup_by_initiators.assert_called_once_with(
fake.FC_FORMATTED_INITIATORS)
@mock.patch.object(uuid, 'uuid4', mock.Mock(return_value=fake.UUID1))
def test_get_or_create_igroup_none_preexisting(self):
self.zapi_client.get_igroup_by_initiators.return_value = []
igroup_name = self.library._get_or_create_igroup(
fake.FC_FORMATTED_INITIATORS, 'fcp', 'linux')
self.assertEqual(igroup_name, 'openstack-' + fake.UUID1)
self.zapi_client.create_igroup.assert_called_once_with(
igroup_name, 'fcp', 'linux')
self.assertEqual(len(fake.FC_FORMATTED_INITIATORS),
self.zapi_client.add_igroup_initiator.call_count)
def test_get_fc_target_wwpns(self):
self.assertRaises(NotImplementedError,
self.library._get_fc_target_wwpns)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_build_initiator_target_map')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_map_lun')
def test_initialize_connection_fc(self, mock_map_lun,
mock_build_initiator_target_map):
self.maxDiff = None
mock_map_lun.return_value = '1'
mock_build_initiator_target_map.return_value = (fake.FC_TARGET_WWPNS,
fake.FC_I_T_MAP, 4)
target_info = self.library.initialize_connection_fc(fake.FC_VOLUME,
fake.FC_CONNECTOR)
self.assertDictEqual(target_info, fake.FC_TARGET_INFO)
mock_map_lun.assert_called_once_with(
'fake_volume', fake.FC_FORMATTED_INITIATORS, 'fcp', None)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_build_initiator_target_map')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_map_lun')
def test_initialize_connection_fc_no_wwpns(
self, mock_map_lun, mock_build_initiator_target_map):
mock_map_lun.return_value = '1'
mock_build_initiator_target_map.return_value = (None, None, 0)
self.assertRaises(exception.VolumeBackendAPIException,
self.library.initialize_connection_fc,
fake.FC_VOLUME,
fake.FC_CONNECTOR)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_has_luns_mapped_to_initiators')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_unmap_lun')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr')
def test_terminate_connection_fc(self, mock_get_lun_attr, mock_unmap_lun,
mock_has_luns_mapped_to_initiators):
mock_get_lun_attr.return_value = {'Path': fake.LUN1}
mock_unmap_lun.return_value = None
mock_has_luns_mapped_to_initiators.return_value = True
target_info = self.library.terminate_connection_fc(fake.FC_VOLUME,
fake.FC_CONNECTOR)
self.assertDictEqual(target_info, fake.FC_TARGET_INFO_EMPTY)
mock_unmap_lun.assert_called_once_with(fake.LUN1,
fake.FC_FORMATTED_INITIATORS)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_build_initiator_target_map')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_has_luns_mapped_to_initiators')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_unmap_lun')
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_lun_attr')
def test_terminate_connection_fc_no_more_luns(
self, mock_get_lun_attr, mock_unmap_lun,
mock_has_luns_mapped_to_initiators,
mock_build_initiator_target_map):
mock_get_lun_attr.return_value = {'Path': fake.LUN1}
mock_unmap_lun.return_value = None
mock_has_luns_mapped_to_initiators.return_value = False
mock_build_initiator_target_map.return_value = (fake.FC_TARGET_WWPNS,
fake.FC_I_T_MAP, 4)
target_info = self.library.terminate_connection_fc(fake.FC_VOLUME,
fake.FC_CONNECTOR)
self.assertDictEqual(target_info, fake.FC_TARGET_INFO_UNMAP)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_fc_target_wwpns')
def test_build_initiator_target_map_no_lookup_service(
self, mock_get_fc_target_wwpns):
self.library.lookup_service = None
mock_get_fc_target_wwpns.return_value = fake.FC_FORMATTED_TARGET_WWPNS
(target_wwpns, init_targ_map, num_paths) = \
self.library._build_initiator_target_map(fake.FC_CONNECTOR)
self.assertSetEqual(set(fake.FC_TARGET_WWPNS), set(target_wwpns))
self.assertDictEqual(fake.FC_I_T_MAP_COMPLETE, init_targ_map)
self.assertEqual(0, num_paths)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_fc_target_wwpns')
def test_build_initiator_target_map_with_lookup_service(
self, mock_get_fc_target_wwpns):
self.library.lookup_service = mock.Mock()
self.library.lookup_service.get_device_mapping_from_network.\
return_value = fake.FC_FABRIC_MAP
mock_get_fc_target_wwpns.return_value = fake.FC_FORMATTED_TARGET_WWPNS
(target_wwpns, init_targ_map, num_paths) = \
self.library._build_initiator_target_map(fake.FC_CONNECTOR)
self.assertSetEqual(set(fake.FC_TARGET_WWPNS), set(target_wwpns))
self.assertDictEqual(fake.FC_I_T_MAP, init_targ_map)
self.assertEqual(4, num_paths)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun_handle', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_add_lun_to_table', mock.Mock())
@mock.patch.object(na_utils, 'LOG', mock.Mock())
@mock.patch.object(na_utils, 'get_volume_extra_specs',
mock.Mock(return_value={'netapp:raid_type': 'raid4'}))
def test_create_volume_obsolete_extra_spec(self):
self.library.zapi_client.get_lun_by_args.return_value = ['lun']
self.library.create_volume({'name': 'lun1', 'size': 100,
'id': uuid.uuid4(),
'host': 'hostname@backend#vol1'})
warn_msg = 'Extra spec netapp:raid_type is obsolete. ' \
'Use netapp_raid_type instead.'
na_utils.LOG.warning.assert_called_once_with(warn_msg)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_create_lun_handle', mock.Mock())
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_add_lun_to_table', mock.Mock())
@mock.patch.object(na_utils, 'LOG', mock.Mock())
@mock.patch.object(na_utils, 'get_volume_extra_specs',
mock.Mock(return_value={'netapp_thick_provisioned':
'true'}))
def test_create_volume_deprecated_extra_spec(self):
self.library.zapi_client.get_lun_by_args.return_value = ['lun']
self.library.create_volume({'name': 'lun1', 'size': 100,
'id': uuid.uuid4(),
'host': 'hostname@backend#vol1'})
warn_msg = 'Extra spec netapp_thick_provisioned is deprecated. ' \
'Use netapp_thin_provisioned instead.'
na_utils.LOG.warning.assert_called_once_with(warn_msg)
@mock.patch.object(na_utils, 'check_flags')
def test_do_setup(self, mock_check_flags):
self.library.do_setup(mock.Mock())
self.assertTrue(mock_check_flags.called)
def test_get_existing_vol_manage_missing_id_path(self):
self.assertRaises(exception.ManageExistingInvalidReference,
self.library._get_existing_vol_with_manage_ref,
{})
def test_get_existing_vol_manage_not_found(self):
self.zapi_client.get_lun_by_args.return_value = []
self.assertRaises(exception.ManageExistingInvalidReference,
self.library._get_existing_vol_with_manage_ref,
{'source-id': 'src_id',
'source-name': 'lun_path'})
self.assertEqual(1, self.zapi_client.get_lun_by_args.call_count)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_extract_lun_info',
mock.Mock(return_value=block_base.NetAppLun(
'lun0', 'lun0', '3', {'UUID': 'src_id'})))
def test_get_existing_vol_manage_lun(self):
self.zapi_client.get_lun_by_args.return_value = ['lun0', 'lun1']
lun = self.library._get_existing_vol_with_manage_ref(
{'source-id': 'src_id', 'path': 'lun_path'})
self.assertEqual(1, self.zapi_client.get_lun_by_args.call_count)
self.library._extract_lun_info.assert_called_once_with('lun0')
self.assertEqual('lun0', lun.name)
@mock.patch.object(block_base.NetAppBlockStorageLibrary,
'_get_existing_vol_with_manage_ref',
mock.Mock(return_value=block_base.NetAppLun(
'handle', 'name', '1073742824', {})))
def test_manage_existing_get_size(self):
size = self.library.manage_existing_get_size(
{'id': 'vol_id'}, {'ref': 'ref'})
self.assertEqual(2, size)
self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
{'ref': 'ref'})
@mock.patch.object(block_base.LOG, 'info')
def test_unmanage(self, log):
mock_lun = block_base.NetAppLun('handle', 'name', '1',
{'Path': 'p', 'UUID': 'uuid'})
self.library._get_lun_from_table = mock.Mock(return_value=mock_lun)
self.library.unmanage({'name': 'vol'})
self.library._get_lun_from_table.assert_called_once_with('vol')
self.assertEqual(1, log.call_count)
def test_manage_existing_lun_same_name(self):
mock_lun = block_base.NetAppLun('handle', 'name', '1',
{'Path': '/vol/vol1/name'})
self.library._get_existing_vol_with_manage_ref = mock.Mock(
return_value=mock_lun)
self.library._check_volume_type_for_lun = mock.Mock()
self.library._add_lun_to_table = mock.Mock()
self.zapi_client.move_lun = mock.Mock()
self.library.manage_existing({'name': 'name'}, {'ref': 'ref'})
self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
{'ref': 'ref'})
self.assertEqual(1, self.library._check_volume_type_for_lun.call_count)
self.assertEqual(1, self.library._add_lun_to_table.call_count)
self.assertEqual(0, self.zapi_client.move_lun.call_count)
def test_manage_existing_lun_new_path(self):
mock_lun = block_base.NetAppLun(
'handle', 'name', '1', {'Path': '/vol/vol1/name'})
self.library._get_existing_vol_with_manage_ref = mock.Mock(
return_value=mock_lun)
self.library._check_volume_type_for_lun = mock.Mock()
self.library._add_lun_to_table = mock.Mock()
self.zapi_client.move_lun = mock.Mock()
self.library.manage_existing({'name': 'volume'}, {'ref': 'ref'})
self.assertEqual(
2, self.library._get_existing_vol_with_manage_ref.call_count)
self.assertEqual(1, self.library._check_volume_type_for_lun.call_count)
self.assertEqual(1, self.library._add_lun_to_table.call_count)
self.zapi_client.move_lun.assert_called_once_with(
'/vol/vol1/name', '/vol/vol1/volume')
def test_check_vol_type_for_lun(self):
self.assertRaises(NotImplementedError,
self.library._check_volume_type_for_lun,
'vol', 'lun', 'existing_ref')
def test_is_lun_valid_on_storage(self):
self.assertTrue(self.library._is_lun_valid_on_storage('lun'))