NetApp E-Series: Refactor class structure for FC

This patch moves classes to mimic the NetApp ONTAP drivers class
structure by creating a library module, making the iSCSI driver
a thin layer. This way the E-Series FC driver can be added in a
similar manner.

Change-Id: I8b4ed6a7b2d43cd93da5c340646405e3041a312a
This commit is contained in:
Alex Meade 2015-04-27 21:19:36 -04:00
parent 2448e04159
commit b4740677cc
6 changed files with 374 additions and 232 deletions

View File

@ -32,7 +32,7 @@ from cinder import test
from cinder.volume import configuration as conf
from cinder.volume.drivers.netapp import common
from cinder.volume.drivers.netapp.eseries import client
from cinder.volume.drivers.netapp.eseries import iscsi
from cinder.volume.drivers.netapp.eseries import library
from cinder.volume.drivers.netapp.eseries import utils
from cinder.volume.drivers.netapp import options
import cinder.volume.drivers.netapp.utils as na_utils
@ -671,6 +671,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
self.mock_object(na_utils, 'OpenStackInfo')
configuration = self._set_config(create_configuration())
self.driver = common.NetAppDriver(configuration=configuration)
self.library = self.driver.library
self.mock_object(requests, 'Session', FakeEseriesHTTPSession)
self.driver.do_setup(context='context')
self.driver.check_for_setup_error()
@ -695,7 +696,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration.netapp_controller_ips = '127.0.0.1,127.0.0.3'
driver = common.NetAppDriver(configuration=configuration)
driver.do_setup(context='context')
self.assertEqual(driver._client.get_system_id(),
self.assertEqual(driver.library._client.get_system_id(),
'1fa6efb5-f07b-4de4-9f0e-52e5f7ff5d1b')
def test_check_system_pwd_not_sync(self):
@ -705,8 +706,8 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
return {'status': 'passwordoutofsync'}
return {'status': 'needsAttention'}
self.driver._client.list_storage_system = mock.Mock(wraps=list_system)
result = self.driver._check_storage_system()
self.library._client.list_storage_system = mock.Mock(wraps=list_system)
result = self.library._check_storage_system()
self.assertTrue(result)
def test_connect(self):
@ -720,10 +721,10 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
self.driver.get_volume_stats(refresh=False)
def test_get_pool(self):
self.mock_object(self.driver, '_get_volume',
self.mock_object(self.library, '_get_volume',
mock.Mock(return_value={
'volumeGroupRef': 'fake_ref'}))
self.mock_object(self.driver._client, "get_storage_pool",
self.mock_object(self.library._client, "get_storage_pool",
mock.Mock(return_value={'volumeGroupRef': 'fake_ref',
'label': 'ddp1'}))
@ -732,21 +733,23 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
self.assertEqual(pool, 'ddp1')
def test_get_pool_no_pools(self):
self.mock_object(self.driver, '_get_volume',
self.mock_object(self.library, '_get_volume',
mock.Mock(return_value={
'volumeGroupRef': 'fake_ref'}))
self.mock_object(self.driver._client, "get_storage_pool",
self.mock_object(self.library._client, "get_storage_pool",
mock.Mock(return_value=None))
pool = self.driver.get_pool({'name_id': 'fake-uuid'})
self.assertEqual(pool, None)
@mock.patch.object(iscsi.NetAppEseriesISCSIDriver, '_create_volume',
@mock.patch.object(library.NetAppESeriesLibrary, '_create_volume',
mock.Mock())
def test_create_volume(self):
self.driver.create_volume(self.volume)
self.driver._create_volume.assert_called_with(
self.library._create_volume.assert_called_with(
'DDP', self.fake_eseries_volume_label, self.volume['size'])
def test_create_volume_no_pool_provided_by_scheduler(self):
@ -765,10 +768,12 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
fake_list_pools.return_value = fake_pools
wrong_eseries_pool_label = 'hostname@backend'
self.assertRaises(exception.NetAppDriverException,
self.driver._create_volume, wrong_eseries_pool_label,
self.fake_eseries_volume_label, self.fake_size_gb)
self.library._create_volume,
wrong_eseries_pool_label,
self.fake_eseries_volume_label,
self.fake_size_gb)
@mock.patch.object(iscsi.LOG, 'info')
@mock.patch.object(library.LOG, 'info')
@mock.patch.object(client.RestClient, 'list_storage_pools')
@mock.patch.object(client.RestClient, 'create_volume',
mock.MagicMock(return_value='CorrectVolume'))
@ -779,7 +784,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
fake_pool['raidLevel'] = 'raidDiskPool'
fake_pools = [fake_pool]
storage_pools.return_value = fake_pools
storage_vol = self.driver._create_volume(
storage_vol = self.library._create_volume(
self.fake_eseries_pool_label,
self.fake_eseries_volume_label,
self.fake_size_gb)
@ -791,7 +796,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
@mock.patch.object(client.RestClient, 'create_volume',
mock.MagicMock(
side_effect=exception.NetAppDriverException))
@mock.patch.object(iscsi.LOG, 'info', mock.Mock())
@mock.patch.object(library.LOG, 'info', mock.Mock())
def test_create_volume_check_exception(self, fake_list_pools):
fake_pool = {}
fake_pool['label'] = self.fake_eseries_pool_label
@ -800,7 +805,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
fake_pools = [fake_pool]
fake_list_pools.return_value = fake_pools
self.assertRaises(exception.NetAppDriverException,
self.driver._create_volume,
self.library._create_volume,
self.fake_eseries_pool_label,
self.fake_eseries_volume_label, self.fake_size_gb)
@ -809,9 +814,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
vol_nomatch = {'id': 'vol_id', 'currentManager': 'ctrl3'}
portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
{'controller': 'ctrl1', 'iqn': 'iqn1'}]
portal = self.driver._get_iscsi_portal_for_vol(volume, portals)
portal = self.library._get_iscsi_portal_for_vol(volume, portals)
self.assertEqual(portal, {'controller': 'ctrl1', 'iqn': 'iqn1'})
portal = self.driver._get_iscsi_portal_for_vol(vol_nomatch, portals)
portal = self.library._get_iscsi_portal_for_vol(vol_nomatch, portals)
self.assertEqual(portal, {'controller': 'ctrl2', 'iqn': 'iqn2'})
def test_portal_for_vol_any_false(self):
@ -819,7 +824,7 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
portals = [{'controller': 'ctrl2', 'iqn': 'iqn2'},
{'controller': 'ctrl1', 'iqn': 'iqn1'}]
self.assertRaises(exception.NetAppDriverException,
self.driver._get_iscsi_portal_for_vol,
self.library._get_iscsi_portal_for_vol,
vol_nomatch, portals, False)
def test_setup_error_unsupported_host_type(self):
@ -827,20 +832,20 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration.netapp_host_type = 'garbage'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NetAppDriverException,
driver.check_for_setup_error)
driver.library.check_for_setup_error)
def test_check_host_type_default(self):
configuration = self._set_config(create_configuration())
driver = common.NetAppDriver(configuration=configuration)
driver._check_host_type()
self.assertEqual('LnxALUA', driver.host_type)
driver.library._check_host_type()
self.assertEqual('LnxALUA', driver.library.host_type)
def test_do_setup_all_default(self):
configuration = self._set_config(create_configuration())
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system = mock.Mock()
driver.library._check_mode_get_or_register_storage_system = mock.Mock()
driver.do_setup(context='context')
url = urllib.parse.urlparse(driver._client._endpoint)
url = urllib.parse.urlparse(driver.library._client._endpoint)
port = url.port
scheme = url.scheme
self.assertEqual(8080, port)
@ -850,9 +855,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration = self._set_config(create_configuration())
configuration.netapp_transport_type = 'http'
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system = mock.Mock()
driver.library._check_mode_get_or_register_storage_system = mock.Mock()
driver.do_setup(context='context')
url = urllib.parse.urlparse(driver._client._endpoint)
url = urllib.parse.urlparse(driver.library._client._endpoint)
port = url.port
scheme = url.scheme
self.assertEqual(8080, port)
@ -862,9 +867,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration = self._set_config(create_configuration())
configuration.netapp_transport_type = 'https'
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system = mock.Mock()
driver.library._check_mode_get_or_register_storage_system = mock.Mock()
driver.do_setup(context='context')
url = urllib.parse.urlparse(driver._client._endpoint)
url = urllib.parse.urlparse(driver.library._client._endpoint)
port = url.port
scheme = url.scheme
self.assertEqual(8443, port)
@ -874,9 +879,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration = self._set_config(create_configuration())
configuration.netapp_server_port = 81
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system = mock.Mock()
driver.library._check_mode_get_or_register_storage_system = mock.Mock()
driver.do_setup(context='context')
url = urllib.parse.urlparse(driver._client._endpoint)
url = urllib.parse.urlparse(driver.library._client._endpoint)
port = url.port
scheme = url.scheme
self.assertEqual(81, port)
@ -887,9 +892,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration.netapp_transport_type = 'https'
configuration.netapp_server_port = 446
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system = mock.Mock()
driver.library._check_mode_get_or_register_storage_system = mock.Mock()
driver.do_setup(context='context')
url = urllib.parse.urlparse(driver._client._endpoint)
url = urllib.parse.urlparse(driver.library._client._endpoint)
port = url.port
scheme = url.scheme
self.assertEqual(446, port)
@ -899,13 +904,13 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '127.0.0.1'
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system
driver.library._check_mode_get_or_register_storage_system
def test_setup_good_controller_ips(self):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '127.0.0.2,127.0.0.1'
driver = common.NetAppDriver(configuration=configuration)
driver._check_mode_get_or_register_storage_system
driver.library._check_mode_get_or_register_storage_system
def test_setup_missing_controller_ip(self):
configuration = self._set_config(create_configuration())
@ -918,33 +923,37 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '987.65.43.21'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NoValidHost,
driver._check_mode_get_or_register_storage_system)
self.assertRaises(
exception.NoValidHost,
driver.library._check_mode_get_or_register_storage_system)
def test_setup_error_invalid_first_controller_ip(self):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '987.65.43.21,127.0.0.1'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NoValidHost,
driver._check_mode_get_or_register_storage_system)
self.assertRaises(
exception.NoValidHost,
driver.library._check_mode_get_or_register_storage_system)
def test_setup_error_invalid_second_controller_ip(self):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '127.0.0.1,987.65.43.21'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NoValidHost,
driver._check_mode_get_or_register_storage_system)
self.assertRaises(
exception.NoValidHost,
driver.library._check_mode_get_or_register_storage_system)
def test_setup_error_invalid_both_controller_ips(self):
configuration = self._set_config(create_configuration())
configuration.netapp_controller_ips = '564.124.1231.1,987.65.43.21'
driver = common.NetAppDriver(configuration=configuration)
self.assertRaises(exception.NoValidHost,
driver._check_mode_get_or_register_storage_system)
self.assertRaises(
exception.NoValidHost,
driver.library._check_mode_get_or_register_storage_system)
def test_get_vol_with_label_wwn_missing(self):
self.assertRaises(exception.InvalidInput,
self.driver._get_volume_with_label_wwn,
self.library._get_volume_with_label_wwn,
None, None)
def test_get_vol_with_label_wwn_found(self):
@ -954,10 +963,11 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
{'volumeRef': '2', 'volumeUse': 'standardVolume',
'label': 'l2', 'volumeGroupRef': 'g2',
'worldWideName': 'w2ghyu'}]
self.driver._get_storage_pools = mock.Mock(return_value=['g2', 'g3'])
self.driver._client.list_volumes = mock.Mock(return_value=fake_vl_list)
vol = self.driver._get_volume_with_label_wwn('l2', 'w2:gh:yu')
self.assertEqual(1, self.driver._client.list_volumes.call_count)
self.library._get_storage_pools = mock.Mock(return_value=['g2', 'g3'])
self.library._client.list_volumes = mock.Mock(
return_value=fake_vl_list)
vol = self.library._get_volume_with_label_wwn('l2', 'w2:gh:yu')
self.assertEqual(1, self.library._client.list_volumes.call_count)
self.assertEqual('2', vol['volumeRef'])
def test_get_vol_with_label_wwn_unmatched(self):
@ -967,23 +977,24 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
{'volumeRef': '2', 'volumeUse': 'standardVolume',
'label': 'l2', 'volumeGroupRef': 'g2',
'worldWideName': 'w2ghyu'}]
self.driver._get_storage_pools = mock.Mock(return_value=['g2', 'g3'])
self.driver._client.list_volumes = mock.Mock(return_value=fake_vl_list)
self.assertRaises(KeyError, self.driver._get_volume_with_label_wwn,
self.library._get_storage_pools = mock.Mock(return_value=['g2', 'g3'])
self.library._client.list_volumes = mock.Mock(
return_value=fake_vl_list)
self.assertRaises(KeyError, self.library._get_volume_with_label_wwn,
'l2', 'abcdef')
self.assertEqual(1, self.driver._client.list_volumes.call_count)
self.assertEqual(1, self.library._client.list_volumes.call_count)
def test_manage_existing_get_size(self):
self.driver._get_existing_vol_with_manage_ref = mock.Mock(
self.library._get_existing_vol_with_manage_ref = mock.Mock(
return_value=self.fake_ret_vol)
size = self.driver.manage_existing_get_size(self.volume, self.fake_ref)
self.assertEqual(3, size)
self.driver._get_existing_vol_with_manage_ref.assert_called_once_with(
self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
self.volume, self.fake_ref)
def test_get_exist_vol_source_name_missing(self):
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver._get_existing_vol_with_manage_ref,
self.library._get_existing_vol_with_manage_ref,
self.volume, {'id': '1234'})
def test_get_exist_vol_source_not_found(self):
@ -991,53 +1002,53 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
d = {'id': '1'}
return d[v_id]
self.driver._get_volume_with_label_wwn = mock.Mock(wraps=_get_volume)
self.library._get_volume_with_label_wwn = mock.Mock(wraps=_get_volume)
self.assertRaises(exception.ManageExistingInvalidReference,
self.driver._get_existing_vol_with_manage_ref,
self.library._get_existing_vol_with_manage_ref,
{'id': 'id2'}, {'source-name': 'name2'})
self.driver._get_volume_with_label_wwn.assert_called_once_with(
self.library._get_volume_with_label_wwn.assert_called_once_with(
'name2', None)
def test_get_exist_vol_with_manage_ref(self):
fake_ret_vol = {'id': 'right'}
self.driver._get_volume_with_label_wwn = mock.Mock(
self.library._get_volume_with_label_wwn = mock.Mock(
return_value=fake_ret_vol)
actual_vol = self.driver._get_existing_vol_with_manage_ref(
actual_vol = self.library._get_existing_vol_with_manage_ref(
{'id': 'id2'}, {'source-name': 'name2'})
self.driver._get_volume_with_label_wwn.assert_called_once_with(
self.library._get_volume_with_label_wwn.assert_called_once_with(
'name2', None)
self.assertEqual(fake_ret_vol, actual_vol)
@mock.patch.object(utils, 'convert_uuid_to_es_fmt')
def test_manage_existing_same_label(self, mock_convert_es_fmt):
self.driver._get_existing_vol_with_manage_ref = mock.Mock(
self.library._get_existing_vol_with_manage_ref = mock.Mock(
return_value=self.fake_ret_vol)
mock_convert_es_fmt.return_value = 'label'
self.driver.manage_existing(self.volume, self.fake_ref)
self.driver._get_existing_vol_with_manage_ref.assert_called_once_with(
self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
self.volume, self.fake_ref)
mock_convert_es_fmt.assert_called_once_with(
'114774fb-e15a-4fae-8ee2-c9723e3645ef')
@mock.patch.object(utils, 'convert_uuid_to_es_fmt')
def test_manage_existing_new(self, mock_convert_es_fmt):
self.driver._get_existing_vol_with_manage_ref = mock.Mock(
self.library._get_existing_vol_with_manage_ref = mock.Mock(
return_value=self.fake_ret_vol)
mock_convert_es_fmt.return_value = 'vol_label'
self.driver._client.update_volume = mock.Mock(
self.library._client.update_volume = mock.Mock(
return_value={'id': 'update', 'worldWideName': 'wwn'})
self.driver.manage_existing(self.volume, self.fake_ref)
self.driver._get_existing_vol_with_manage_ref.assert_called_once_with(
self.library._get_existing_vol_with_manage_ref.assert_called_once_with(
self.volume, self.fake_ref)
mock_convert_es_fmt.assert_called_once_with(
'114774fb-e15a-4fae-8ee2-c9723e3645ef')
self.driver._client.update_volume.assert_called_once_with(
self.library._client.update_volume.assert_called_once_with(
'vol_id', 'vol_label')
@mock.patch.object(iscsi.LOG, 'info')
@mock.patch.object(library.LOG, 'info')
def test_unmanage(self, log_info):
self.driver._get_volume = mock.Mock(return_value=self.fake_ret_vol)
self.library._get_volume = mock.Mock(return_value=self.fake_ret_vol)
self.driver.unmanage(self.volume)
self.driver._get_volume.assert_called_once_with(
self.library._get_volume.assert_called_once_with(
'114774fb-e15a-4fae-8ee2-c9723e3645ef')
self.assertEqual(1, log_info.call_count)

View File

@ -0,0 +1,29 @@
# Copyright (c) 2015 Alex Meade. 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.
import mock
from cinder import test
import cinder.volume.drivers.netapp.eseries.iscsi_driver as iscsi
from cinder.volume.drivers.netapp import utils as na_utils
class NetAppESeriesISCSIDriverTestCase(test.TestCase):
@mock.patch.object(na_utils, 'validate_instantiation')
def test_instantiation(self, mock_validate_instantiation):
iscsi.NetAppEseriesISCSIDriver(configuration=mock.Mock())
self.assertTrue(mock_validate_instantiation.called)

View File

@ -14,9 +14,6 @@
# 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 E-series iscsi driver
"""
import copy
@ -30,7 +27,7 @@ from cinder.tests.unit.volume.drivers.netapp.eseries import fakes as \
eseries_fakes
from cinder.volume.drivers.netapp.eseries import client as es_client
from cinder.volume.drivers.netapp.eseries import host_mapper
from cinder.volume.drivers.netapp.eseries import iscsi as es_iscsi
from cinder.volume.drivers.netapp.eseries import library
from cinder.volume.drivers.netapp.eseries import utils
from cinder.volume.drivers.netapp import utils as na_utils
@ -48,24 +45,24 @@ def get_fake_volume():
}
class NetAppEseriesISCSIDriverTestCase(test.TestCase):
class NetAppEseriesLibraryTestCase(test.TestCase):
def setUp(self):
super(NetAppEseriesISCSIDriverTestCase, self).setUp()
super(NetAppEseriesLibraryTestCase, self).setUp()
kwargs = {'configuration':
eseries_fakes.create_configuration_eseries()}
self.driver = es_iscsi.NetAppEseriesISCSIDriver(**kwargs)
self.driver._client = eseries_fakes.FakeEseriesClient()
self.driver.check_for_setup_error()
self.library = library.NetAppESeriesLibrary('FAKE', **kwargs)
self.library._client = eseries_fakes.FakeEseriesClient()
self.library.check_for_setup_error()
def test_do_setup(self):
self.mock_object(es_iscsi.NetAppEseriesISCSIDriver,
self.mock_object(self.library,
'_check_mode_get_or_register_storage_system')
self.mock_object(es_client, 'RestClient',
eseries_fakes.FakeEseriesClient)
mock_check_flags = self.mock_object(na_utils, 'check_flags')
self.driver.do_setup(mock.Mock())
self.library.do_setup(mock.Mock())
self.assertTrue(mock_check_flags.called)
@ -73,21 +70,21 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'driveMediaType': 'ssd'}]
self.driver._get_storage_pools = mock.Mock(return_value=['test_vg1'])
self.driver._client.list_storage_pools = mock.Mock(return_value=[])
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._get_storage_pools = mock.Mock(return_value=['test_vg1'])
self.library._client.list_storage_pools = mock.Mock(return_value=[])
self.library._client.list_drives = mock.Mock(return_value=drives)
self.driver._update_ssc_info()
self.library._update_ssc_info()
self.assertEqual({'test_vg1': {'netapp_disk_type': 'SSD'}},
self.driver._ssc_stats)
self.library._ssc_stats)
def test_update_ssc_disk_types_ssd(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'driveMediaType': 'ssd'}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'SSD'}},
ssc_stats)
@ -95,9 +92,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_scsi(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': 'scsi'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'SCSI'}},
ssc_stats)
@ -105,9 +102,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_fcal(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': 'fibre'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'FCAL'}},
ssc_stats)
@ -115,9 +112,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_sata(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': 'sata'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'SATA'}},
ssc_stats)
@ -125,9 +122,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_sas(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': 'sas'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'SAS'}},
ssc_stats)
@ -135,9 +132,9 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_unknown(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': 'unknown'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'unknown'}},
ssc_stats)
@ -145,54 +142,54 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_types_undefined(self):
drives = [{'currentVolumeGroupRef': 'test_vg1',
'interfaceType': {'driveType': '__UNDEFINED'}}]
self.driver._client.list_drives = mock.Mock(return_value=drives)
self.library._client.list_drives = mock.Mock(return_value=drives)
ssc_stats = self.driver._update_ssc_disk_types(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_types(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_type': 'unknown'}},
ssc_stats)
def test_update_ssc_disk_encryption_SecType_enabled(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'enabled'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_encryption': 'true'}},
ssc_stats)
def test_update_ssc_disk_encryption_SecType_unknown(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'unknown'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_encryption': 'false'}},
ssc_stats)
def test_update_ssc_disk_encryption_SecType_none(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'none'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_encryption': 'false'}},
ssc_stats)
def test_update_ssc_disk_encryption_SecType_capable(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'capable'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1'])
self.assertEqual({'test_vg1': {'netapp_disk_encryption': 'false'}},
ssc_stats)
def test_update_ssc_disk_encryption_SecType_garbage(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'garbage'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1'])
self.assertRaises(TypeError, 'test_vg1',
{'netapp_disk_encryption': 'false'}, ssc_stats)
@ -200,102 +197,104 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
def test_update_ssc_disk_encryption_multiple(self):
pools = [{'volumeGroupRef': 'test_vg1', 'securityType': 'none'},
{'volumeGroupRef': 'test_vg2', 'securityType': 'enabled'}]
self.driver._client.list_storage_pools = mock.Mock(return_value=pools)
self.library._client.list_storage_pools = mock.Mock(return_value=pools)
ssc_stats = self.driver._update_ssc_disk_encryption(['test_vg1',
'test_vg2'])
ssc_stats = self.library._update_ssc_disk_encryption(['test_vg1',
'test_vg2'])
self.assertEqual({'test_vg1': {'netapp_disk_encryption': 'false'},
'test_vg2': {'netapp_disk_encryption': 'true'}},
ssc_stats)
def test_terminate_connection_no_hosts(self):
def test_terminate_connection_iscsi_no_hosts(self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(self.driver._client, 'list_hosts',
self.mock_object(self.library._client, 'list_hosts',
mock.Mock(return_value=[]))
self.assertRaises(exception.NotFound,
self.driver.terminate_connection,
self.library.terminate_connection_iscsi,
get_fake_volume(),
connector)
def test_terminate_connection_volume_not_mapped(self):
def test_terminate_connection_iscsi_volume_not_mapped(self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
err = self.assertRaises(exception.NetAppDriverException,
self.driver.terminate_connection,
self.library.terminate_connection_iscsi,
get_fake_volume(),
connector)
self.assertIn("not currently mapped to host", six.text_type(err))
def test_terminate_connection_volume_mapped(self):
def test_terminate_connection_iscsi_volume_mapped(self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
fake_eseries_volume = copy.deepcopy(eseries_fakes.VOLUME)
fake_eseries_volume['listOfMappings'] = [
eseries_fakes.VOLUME_MAPPING
]
self.mock_object(self.driver._client, 'list_volumes',
self.mock_object(self.library._client, 'list_volumes',
mock.Mock(return_value=[fake_eseries_volume]))
self.mock_object(host_mapper, 'unmap_volume_from_host')
self.driver.terminate_connection(get_fake_volume(), connector)
self.library.terminate_connection_iscsi(get_fake_volume(), connector)
self.assertTrue(host_mapper.unmap_volume_from_host.called)
def test_terminate_connection_volume_not_mapped_initiator_does_not_exist(
def test_terminate_connection_iscsi_not_mapped_initiator_does_not_exist(
self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(self.driver._client, 'list_hosts',
self.mock_object(self.library._client, 'list_hosts',
mock.Mock(return_value=[eseries_fakes.HOST_2]))
self.assertRaises(exception.NotFound,
self.driver.terminate_connection,
self.library.terminate_connection_iscsi,
get_fake_volume(),
connector)
def test_initialize_connection_volume_not_mapped(self):
def test_initialize_connection_iscsi_volume_not_mapped(self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(self.driver._client, 'get_volume_mappings',
self.mock_object(self.library._client, 'get_volume_mappings',
mock.Mock(return_value=[]))
self.mock_object(host_mapper, 'map_volume_to_single_host',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.initialize_connection_iscsi(get_fake_volume(), connector)
self.assertTrue(self.driver._client.get_volume_mappings.called)
self.assertTrue(self.library._client.get_volume_mappings.called)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
def test_initialize_connection_volume_not_mapped_host_does_not_exist(self):
def test_initialize_connection_iscsi_volume_not_mapped_host_does_not_exist(
self):
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(self.driver._client, 'get_volume_mappings',
self.mock_object(self.library._client, 'get_volume_mappings',
mock.Mock(return_value=[]))
self.mock_object(self.driver._client, 'list_hosts',
self.mock_object(self.library._client, 'list_hosts',
mock.Mock(return_value=[]))
self.mock_object(self.driver._client, 'create_host_with_port',
self.mock_object(self.library._client, 'create_host_with_port',
mock.Mock(return_value=eseries_fakes.HOST))
self.mock_object(host_mapper, 'map_volume_to_single_host',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.initialize_connection_iscsi(get_fake_volume(), connector)
self.assertTrue(self.driver._client.get_volume_mappings.called)
self.assertTrue(self.driver._client.list_hosts.called)
self.assertTrue(self.driver._client.create_host_with_port.called)
self.assertTrue(self.library._client.get_volume_mappings.called)
self.assertTrue(self.library._client.list_hosts.called)
self.assertTrue(self.library._client.create_host_with_port.called)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
def test_initialize_connection_volume_already_mapped_to_target_host(self):
def test_initialize_connection_iscsi_volume_already_mapped_to_target_host(
self):
"""Should be a no-op"""
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(host_mapper, 'map_volume_to_single_host',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.initialize_connection_iscsi(get_fake_volume(), connector)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
def test_initialize_connection_volume_mapped_to_another_host(self):
def test_initialize_connection_iscsi_volume_mapped_to_another_host(self):
"""Should raise error saying multiattach not enabled"""
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
fake_mapping_to_other_host = copy.deepcopy(
@ -307,38 +306,38 @@ class NetAppEseriesISCSIDriverTestCase(test.TestCase):
side_effect=exception.NetAppDriverException))
self.assertRaises(exception.NetAppDriverException,
self.driver.initialize_connection,
self.library.initialize_connection_iscsi,
get_fake_volume(), connector)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
class NetAppEseriesISCSIDriverMultiAttachTestCase(test.TestCase):
class NetAppEseriesLibraryMultiAttachTestCase(test.TestCase):
"""Test driver behavior when the netapp_enable_multiattach
configuration option is True.
"""
def setUp(self):
super(NetAppEseriesISCSIDriverMultiAttachTestCase, self).setUp()
super(NetAppEseriesLibraryMultiAttachTestCase, self).setUp()
config = eseries_fakes.create_configuration_eseries()
config.netapp_enable_multiattach = True
kwargs = {'configuration': config}
self.driver = es_iscsi.NetAppEseriesISCSIDriver(**kwargs)
self.driver._client = eseries_fakes.FakeEseriesClient()
self.driver.check_for_setup_error()
self.library = library.NetAppESeriesLibrary("FAKE", **kwargs)
self.library._client = eseries_fakes.FakeEseriesClient()
self.library.check_for_setup_error()
def test_do_setup_host_group_already_exists(self):
mock_check_flags = self.mock_object(na_utils, 'check_flags')
self.mock_object(es_iscsi.NetAppEseriesISCSIDriver,
self.mock_object(self.library,
'_check_mode_get_or_register_storage_system')
fake_rest_client = eseries_fakes.FakeEseriesClient()
self.mock_object(self.driver, '_create_rest_client',
self.mock_object(self.library, '_create_rest_client',
mock.Mock(return_value=fake_rest_client))
mock_create = self.mock_object(fake_rest_client, 'create_host_group')
self.driver.do_setup(mock.Mock())
self.library.do_setup(mock.Mock())
self.assertTrue(mock_check_flags.called)
self.assertFalse(mock_create.call_count)
@ -346,178 +345,180 @@ class NetAppEseriesISCSIDriverMultiAttachTestCase(test.TestCase):
def test_do_setup_host_group_does_not_exist(self):
mock_check_flags = self.mock_object(na_utils, 'check_flags')
fake_rest_client = eseries_fakes.FakeEseriesClient()
self.mock_object(self.driver, '_create_rest_client',
self.mock_object(self.library, '_create_rest_client',
mock.Mock(return_value=fake_rest_client))
mock_get_host_group = self.mock_object(
fake_rest_client, "get_host_group_by_name",
mock.Mock(side_effect=exception.NotFound))
self.mock_object(es_iscsi.NetAppEseriesISCSIDriver,
self.mock_object(self.library,
'_check_mode_get_or_register_storage_system')
self.driver.do_setup(mock.Mock())
self.library.do_setup(mock.Mock())
self.assertTrue(mock_check_flags.called)
self.assertTrue(mock_get_host_group.call_count)
def test_create_volume(self):
self.driver._client.create_volume = mock.Mock(
self.library._client.create_volume = mock.Mock(
return_value=eseries_fakes.VOLUME)
self.driver.create_volume(get_fake_volume())
self.assertTrue(self.driver._client.create_volume.call_count)
self.library.create_volume(get_fake_volume())
self.assertTrue(self.library._client.create_volume.call_count)
def test_create_volume_too_many_volumes(self):
self.driver._client.list_volumes = mock.Mock(
self.library._client.list_volumes = mock.Mock(
return_value=[eseries_fakes.VOLUME for __ in
range(utils.MAX_LUNS_PER_HOST_GROUP + 1)])
self.driver._client.create_volume = mock.Mock(
self.library._client.create_volume = mock.Mock(
return_value=eseries_fakes.VOLUME)
self.assertRaises(exception.NetAppDriverException,
self.driver.create_volume,
self.library.create_volume,
get_fake_volume())
self.assertFalse(self.driver._client.create_volume.call_count)
self.assertFalse(self.library._client.create_volume.call_count)
def test_create_volume_from_snapshot(self):
fake_eseries_volume = copy.deepcopy(eseries_fakes.VOLUME)
self.mock_object(self.driver, "_schedule_and_create_volume",
self.mock_object(self.library, "_schedule_and_create_volume",
mock.Mock(return_value=fake_eseries_volume))
self.mock_object(self.driver, "_create_snapshot_volume",
self.mock_object(self.library, "_create_snapshot_volume",
mock.Mock(return_value=fake_eseries_volume))
self.mock_object(self.driver._client, "delete_snapshot_volume")
self.mock_object(self.library._client, "delete_snapshot_volume")
self.driver.create_volume_from_snapshot(
self.library.create_volume_from_snapshot(
get_fake_volume(), fake_snapshot.fake_snapshot_obj(None))
self.assertEqual(
1, self.driver._schedule_and_create_volume.call_count)
self.assertEqual(1, self.driver._create_snapshot_volume.call_count)
1, self.library._schedule_and_create_volume.call_count)
self.assertEqual(1, self.library._create_snapshot_volume.call_count)
self.assertEqual(
1, self.driver._client.delete_snapshot_volume.call_count)
1, self.library._client.delete_snapshot_volume.call_count)
def test_create_volume_from_snapshot_create_fails(self):
fake_dest_eseries_volume = copy.deepcopy(eseries_fakes.VOLUME)
self.mock_object(self.driver, "_schedule_and_create_volume",
self.mock_object(self.library, "_schedule_and_create_volume",
mock.Mock(return_value=fake_dest_eseries_volume))
self.mock_object(self.driver, "_create_snapshot_volume",
self.mock_object(self.library, "_create_snapshot_volume",
mock.Mock(side_effect=exception.NetAppDriverException)
)
self.mock_object(self.driver._client, "delete_snapshot_volume")
self.mock_object(self.driver._client, "delete_volume")
self.mock_object(self.library._client, "delete_snapshot_volume")
self.mock_object(self.library._client, "delete_volume")
self.assertRaises(exception.NetAppDriverException,
self.driver.create_volume_from_snapshot,
self.library.create_volume_from_snapshot,
get_fake_volume(),
fake_snapshot.fake_snapshot_obj(None))
self.assertEqual(
1, self.driver._schedule_and_create_volume.call_count)
self.assertEqual(1, self.driver._create_snapshot_volume.call_count)
1, self.library._schedule_and_create_volume.call_count)
self.assertEqual(1, self.library._create_snapshot_volume.call_count)
self.assertEqual(
0, self.driver._client.delete_snapshot_volume.call_count)
0, self.library._client.delete_snapshot_volume.call_count)
# Ensure the volume we were going to copy to is cleaned up
self.driver._client.delete_volume.assert_called_once_with(
self.library._client.delete_volume.assert_called_once_with(
fake_dest_eseries_volume['volumeRef'])
def test_create_volume_from_snapshot_copy_job_fails(self):
fake_dest_eseries_volume = copy.deepcopy(eseries_fakes.VOLUME)
self.mock_object(self.driver, "_schedule_and_create_volume",
self.mock_object(self.library, "_schedule_and_create_volume",
mock.Mock(return_value=fake_dest_eseries_volume))
self.mock_object(self.driver, "_create_snapshot_volume",
self.mock_object(self.library, "_create_snapshot_volume",
mock.Mock(return_value=fake_dest_eseries_volume))
self.mock_object(self.driver._client, "delete_snapshot_volume")
self.mock_object(self.driver._client, "delete_volume")
self.mock_object(self.library._client, "delete_snapshot_volume")
self.mock_object(self.library._client, "delete_volume")
fake_failed_volume_copy_job = copy.deepcopy(
eseries_fakes.VOLUME_COPY_JOB)
fake_failed_volume_copy_job['status'] = 'failed'
self.mock_object(self.driver._client,
self.mock_object(self.library._client,
"create_volume_copy_job",
mock.Mock(return_value=fake_failed_volume_copy_job))
self.mock_object(self.driver._client,
self.mock_object(self.library._client,
"list_vol_copy_job",
mock.Mock(return_value=fake_failed_volume_copy_job))
self.assertRaises(exception.NetAppDriverException,
self.driver.create_volume_from_snapshot,
self.library.create_volume_from_snapshot,
get_fake_volume(),
fake_snapshot.fake_snapshot_obj(None))
self.assertEqual(
1, self.driver._schedule_and_create_volume.call_count)
self.assertEqual(1, self.driver._create_snapshot_volume.call_count)
1, self.library._schedule_and_create_volume.call_count)
self.assertEqual(1, self.library._create_snapshot_volume.call_count)
self.assertEqual(
1, self.driver._client.delete_snapshot_volume.call_count)
1, self.library._client.delete_snapshot_volume.call_count)
# Ensure the volume we were going to copy to is cleaned up
self.driver._client.delete_volume.assert_called_once_with(
self.library._client.delete_volume.assert_called_once_with(
fake_dest_eseries_volume['volumeRef'])
def test_create_volume_from_snapshot_fail_to_delete_snapshot_volume(self):
fake_dest_eseries_volume = copy.deepcopy(eseries_fakes.VOLUME)
fake_dest_eseries_volume['volumeRef'] = 'fake_volume_ref'
self.mock_object(self.driver, "_schedule_and_create_volume",
self.mock_object(self.library, "_schedule_and_create_volume",
mock.Mock(return_value=fake_dest_eseries_volume))
self.mock_object(self.driver, "_create_snapshot_volume",
self.mock_object(self.library, "_create_snapshot_volume",
mock.Mock(return_value=copy.deepcopy(
eseries_fakes.VOLUME)))
self.mock_object(self.driver._client, "delete_snapshot_volume",
self.mock_object(self.library._client, "delete_snapshot_volume",
mock.Mock(side_effect=exception.NetAppDriverException)
)
self.mock_object(self.driver._client, "delete_volume")
self.mock_object(self.library._client, "delete_volume")
self.driver.create_volume_from_snapshot(
self.library.create_volume_from_snapshot(
get_fake_volume(), fake_snapshot.fake_snapshot_obj(None))
self.assertEqual(
1, self.driver._schedule_and_create_volume.call_count)
self.assertEqual(1, self.driver._create_snapshot_volume.call_count)
1, self.library._schedule_and_create_volume.call_count)
self.assertEqual(1, self.library._create_snapshot_volume.call_count)
self.assertEqual(
1, self.driver._client.delete_snapshot_volume.call_count)
1, self.library._client.delete_snapshot_volume.call_count)
# Ensure the volume we created is not cleaned up
self.assertEqual(0, self.driver._client.delete_volume.call_count)
self.assertEqual(0, self.library._client.delete_volume.call_count)
def test_initialize_connection_volume_not_mapped(self):
"""Map the volume directly to destination host.
"""
connector = {'initiator': eseries_fakes.INITIATOR_NAME_2}
self.mock_object(self.driver._client, 'get_volume_mappings',
def test_map_volume_to_host_volume_not_mapped(self):
"""Map the volume directly to destination host."""
self.mock_object(self.library._client, 'get_volume_mappings',
mock.Mock(return_value=[]))
self.mock_object(host_mapper, 'map_volume_to_single_host',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.map_volume_to_host(get_fake_volume(),
eseries_fakes.VOLUME,
eseries_fakes.INITIATOR_NAME_2)
self.assertTrue(self.driver._client.get_volume_mappings.called)
self.assertTrue(self.library._client.get_volume_mappings.called)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
def test_initialize_connection_volume_not_mapped_host_does_not_exist(self):
def test_map_volume_to_host_volume_not_mapped_host_does_not_exist(self):
"""Should create the host map directly to the host."""
connector = {'initiator': eseries_fakes.INITIATOR_NAME_2}
self.mock_object(self.driver._client, 'list_hosts',
self.mock_object(self.library._client, 'list_hosts',
mock.Mock(return_value=[]))
self.mock_object(self.driver._client, 'create_host_with_port',
self.mock_object(self.library._client, 'create_host_with_port',
mock.Mock(
return_value=eseries_fakes.HOST_2))
self.mock_object(self.driver._client, 'get_volume_mappings',
self.mock_object(self.library._client, 'get_volume_mappings',
mock.Mock(return_value=[]))
self.mock_object(host_mapper, 'map_volume_to_single_host',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.map_volume_to_host(get_fake_volume(),
eseries_fakes.VOLUME,
eseries_fakes.INITIATOR_NAME_2)
self.assertTrue(self.driver._client.create_host_with_port.called)
self.assertTrue(self.driver._client.get_volume_mappings.called)
self.assertTrue(self.library._client.create_host_with_port.called)
self.assertTrue(self.library._client.get_volume_mappings.called)
self.assertTrue(host_mapper.map_volume_to_single_host.called)
def test_initialize_connection_volume_already_mapped(self):
def test_map_volume_to_host_volume_already_mapped(self):
"""Should be a no-op."""
connector = {'initiator': eseries_fakes.INITIATOR_NAME}
self.mock_object(host_mapper, 'map_volume_to_multiple_hosts',
mock.Mock(
return_value=eseries_fakes.VOLUME_MAPPING))
self.driver.initialize_connection(get_fake_volume(), connector)
self.library.map_volume_to_host(get_fake_volume(),
eseries_fakes.VOLUME,
eseries_fakes.INITIATOR_NAME)
self.assertTrue(host_mapper.map_volume_to_multiple_hosts.called)

View File

@ -49,7 +49,7 @@ NETAPP_UNIFIED_DRIVER_REGISTRY = {
},
'eseries':
{
'iscsi': ESERIES_PATH + '.iscsi.NetAppEseriesISCSIDriver'
'iscsi': ESERIES_PATH + '.iscsi_driver.NetAppEseriesISCSIDriver'
}}

View File

@ -0,0 +1,97 @@
# Copyright (c) 2014 NetApp, Inc. All Rights Reserved.
# Copyright (c) 2015 Alex Meade. All Rights Reserved.
# Copyright (c) 2015 Rushil Chugh. All Rights Reserved.
# Copyright (c) 2015 Navneet Singh. 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.
"""
iSCSI driver for NetApp E-series storage systems.
"""
from oslo_log import log as logging
from cinder.volume import driver
from cinder.volume.drivers.netapp.eseries import library
from cinder.volume.drivers.netapp import utils as na_utils
LOG = logging.getLogger(__name__)
class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
DRIVER_NAME = 'NetApp_iSCSI_ESeries'
def __init__(self, *args, **kwargs):
super(NetAppEseriesISCSIDriver, self).__init__(*args, **kwargs)
na_utils.validate_instantiation(**kwargs)
self.library = library.NetAppESeriesLibrary(self.DRIVER_NAME,
'iSCSI', **kwargs)
def do_setup(self, context):
self.library.do_setup(context)
def check_for_setup_error(self):
self.library.check_for_setup_error()
def create_volume(self, volume):
self.library.create_volume(volume)
def create_volume_from_snapshot(self, volume, snapshot):
self.library.create_volume_from_snapshot(volume, snapshot)
def create_cloned_volume(self, volume, src_vref):
self.library.create_cloned_volume(volume, src_vref)
def delete_volume(self, volume):
self.library.delete_volume(volume)
def create_snapshot(self, snapshot):
self.library.create_snapshot(snapshot)
def delete_snapshot(self, snapshot):
self.library.delete_snapshot(snapshot)
def get_volume_stats(self, refresh=False):
return self.library.get_volume_stats(refresh)
def extend_volume(self, volume, new_size):
self.library.extend_volume(volume, new_size)
def ensure_export(self, context, volume):
return self.library.ensure_export(context, volume)
def create_export(self, context, volume):
return self.library.create_export(context, volume)
def remove_export(self, context, volume):
self.library.remove_export(context, volume)
def manage_existing(self, volume, existing_ref):
return self.library.manage_existing(volume, existing_ref)
def manage_existing_get_size(self, volume, existing_ref):
return self.library.manage_existing_get_size(volume, existing_ref)
def unmanage(self, volume):
return self.library.unmanage(volume)
def initialize_connection(self, volume, connector):
return self.library.initialize_connection_iscsi(volume, connector)
def terminate_connection(self, volume, connector, **kwargs):
return self.library.terminate_connection_iscsi(volume, connector,
**kwargs)
def get_pool(self, volume):
return self.library.get_pool(volume)

View File

@ -14,9 +14,6 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
iSCSI driver for NetApp E-series storage systems.
"""
import copy
import math
@ -34,7 +31,6 @@ from cinder import exception
from cinder.i18n import _, _LE, _LI, _LW
from cinder.openstack.common import loopingcall
from cinder import utils as cinder_utils
from cinder.volume import driver
from cinder.volume.drivers.netapp.eseries import client
from cinder.volume.drivers.netapp.eseries import exception as eseries_exc
from cinder.volume.drivers.netapp.eseries import host_mapper
@ -46,7 +42,6 @@ from cinder.volume import utils as volume_utils
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
CONF.register_opts(na_opts.netapp_basicauth_opts)
CONF.register_opts(na_opts.netapp_connection_opts)
@ -55,7 +50,7 @@ CONF.register_opts(na_opts.netapp_transport_opts)
CONF.register_opts(na_opts.netapp_san_opts)
class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
class NetAppESeriesLibrary(object):
"""Executes commands relating to Volumes."""
VERSION = "1.0.0"
@ -97,9 +92,9 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
DEFAULT_HOST_TYPE = 'linux_dm_mp'
def __init__(self, *args, **kwargs):
super(NetAppEseriesISCSIDriver, self).__init__(*args, **kwargs)
na_utils.validate_instantiation(**kwargs)
def __init__(self, driver_name, driver_protocol="iSCSI",
configuration=None, **kwargs):
self.configuration = configuration
self.configuration.append_config_values(na_opts.netapp_basicauth_opts)
self.configuration.append_config_values(
na_opts.netapp_connection_opts)
@ -108,6 +103,9 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
self.configuration.append_config_values(na_opts.netapp_san_opts)
self._backend_name = self.configuration.safe_get(
"volume_backend_name") or "NetApp_ESeries"
self.driver_name = driver_name
self.driver_protocol = driver_protocol
self._stats = {}
self._ssc_stats = {}
def do_setup(self, context):
@ -457,7 +455,8 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
def create_cloned_volume(self, volume, src_vref):
"""Creates a clone of the specified volume."""
snapshot = {'id': uuid.uuid4(), 'volume_id': src_vref['id']}
snapshot = {'id': uuid.uuid4(), 'volume_id': src_vref['id'],
'volume': src_vref}
self.create_snapshot(snapshot)
try:
self.create_volume_from_snapshot(volume, snapshot)
@ -481,7 +480,7 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
"""Creates a snapshot."""
snap_grp, snap_image = None, None
snapshot_name = utils.convert_uuid_to_es_fmt(snapshot['id'])
os_vol = self.db.volume_get(self.context, snapshot['volume_id'])
os_vol = snapshot['volume']
vol = self._get_volume(os_vol['name_id'])
vol_size_gb = int(vol['totalSizeInBytes']) / units.Gi
pools = self._get_sorted_available_storage_pools(vol_size_gb)
@ -517,12 +516,10 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
"""Removes an export for a volume."""
pass
def initialize_connection(self, volume, connector):
"""Allow connection to connector and return connection info."""
initiator_name = connector['initiator']
eseries_vol = self._get_volume(volume['name_id'])
def map_volume_to_host(self, volume, eseries_volume, initiator_name):
"""Ensures the specified initiator has access to the volume."""
existing_maps = host_mapper.get_host_mapping_for_vol_frm_array(
self._client, eseries_vol)
self._client, eseries_volume)
host = self._get_or_create_host(initiator_name, self.host_type)
# There can only be one or zero mappings on a volume in E-Series
current_map = existing_maps[0] if existing_maps else None
@ -531,13 +528,20 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
self._ensure_multi_attach_host_group_exists()
mapping = host_mapper.map_volume_to_multiple_hosts(self._client,
volume,
eseries_vol,
eseries_volume,
host,
current_map)
else:
mapping = host_mapper.map_volume_to_single_host(
self._client, volume, eseries_vol, host, current_map,
self._client, volume, eseries_volume, host, current_map,
self.configuration.netapp_enable_multiattach)
return mapping
def initialize_connection_iscsi(self, volume, connector):
"""Allow connection to connector and return connection info."""
initiator_name = connector['initiator']
eseries_vol = self._get_volume(volume['name_id'])
mapping = self.map_volume_to_host(volume, eseries_vol, initiator_name)
lun_id = mapping['lun']
msg_fmt = {'id': volume['id'], 'initiator_name': initiator_name}
@ -644,7 +648,7 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
return ht
raise exception.NotFound(_("Host type %s not supported.") % host_type)
def terminate_connection(self, volume, connector, **kwargs):
def terminate_connection_iscsi(self, volume, connector, **kwargs):
"""Disallow connection from connector."""
eseries_vol = self._get_volume(volume['name_id'])
initiator = connector['initiator']
@ -675,7 +679,7 @@ class NetAppEseriesISCSIDriver(driver.ISCSIDriver):
data["volume_backend_name"] = self._backend_name
data["vendor_name"] = "NetApp"
data["driver_version"] = self.VERSION
data["storage_protocol"] = "iSCSI"
data["storage_protocol"] = self.driver_protocol
data["pools"] = []
for storage_pool in self._get_storage_pools():