From: Alex Meade Date: Tue, 28 Apr 2015 01:19:36 +0000 (-0400) Subject: NetApp E-Series: Refactor class structure for FC X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=b4740677cce2a4be5ade6c6ab72e37055fd4f2f6;p=openstack-build%2Fcinder-build.git 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 --- diff --git a/cinder/tests/unit/test_netapp_eseries_iscsi.py b/cinder/tests/unit/test_netapp_eseries_iscsi.py index 8c0225cf8..52477f18a 100644 --- a/cinder/tests/unit/test_netapp_eseries_iscsi.py +++ b/cinder/tests/unit/test_netapp_eseries_iscsi.py @@ -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) diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi_driver.py b/cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi_driver.py new file mode 100644 index 000000000..42e1e6375 --- /dev/null +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi_driver.py @@ -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) diff --git a/cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi.py b/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py similarity index 61% rename from cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi.py rename to cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py index fac76dec9..eb2652e60 100644 --- a/cinder/tests/unit/volume/drivers/netapp/eseries/test_iscsi.py +++ b/cinder/tests/unit/volume/drivers/netapp/eseries/test_library.py @@ -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) diff --git a/cinder/volume/drivers/netapp/common.py b/cinder/volume/drivers/netapp/common.py index c08932eee..90480993b 100644 --- a/cinder/volume/drivers/netapp/common.py +++ b/cinder/volume/drivers/netapp/common.py @@ -49,7 +49,7 @@ NETAPP_UNIFIED_DRIVER_REGISTRY = { }, 'eseries': { - 'iscsi': ESERIES_PATH + '.iscsi.NetAppEseriesISCSIDriver' + 'iscsi': ESERIES_PATH + '.iscsi_driver.NetAppEseriesISCSIDriver' }} diff --git a/cinder/volume/drivers/netapp/eseries/iscsi_driver.py b/cinder/volume/drivers/netapp/eseries/iscsi_driver.py new file mode 100644 index 000000000..3de100b71 --- /dev/null +++ b/cinder/volume/drivers/netapp/eseries/iscsi_driver.py @@ -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) diff --git a/cinder/volume/drivers/netapp/eseries/iscsi.py b/cinder/volume/drivers/netapp/eseries/library.py similarity index 97% rename from cinder/volume/drivers/netapp/eseries/iscsi.py rename to cinder/volume/drivers/netapp/eseries/library.py index d4a288ff8..ff8ef8454 100644 --- a/cinder/volume/drivers/netapp/eseries/iscsi.py +++ b/cinder/volume/drivers/netapp/eseries/library.py @@ -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():