diff --git a/cinder/tests/unit/volume/drivers/nec/test_volume.py b/cinder/tests/unit/volume/drivers/nec/test_volume.py index a322991226a..aff3043e936 100644 --- a/cinder/tests/unit/volume/drivers/nec/test_volume.py +++ b/cinder/tests/unit/volume/drivers/nec/test_volume.py @@ -343,6 +343,11 @@ xml_out = ''' 0000 0000 +
+ iqn.2001-03.target0001 + 0001 + 0006 +
Command Completed Successfully!! @@ -359,14 +364,20 @@ class DummyVolume(object): self.id = volid self.size = volsize self.status = None - self.migration_status = None - self.volume_id = None self.volume_type_id = None self.attach_status = None self.volume_attachment = None self.provider_location = None +class DummySnapshot(object): + + def __init__(self, snapid): + super(DummySnapshot, self).__init__() + self.id = snapid + self.volume_id = None + + @ddt.ddt class VolumeIDConvertTest(volume_helper.MStorageDSVDriver, test.TestCase): @@ -375,13 +386,12 @@ class VolumeIDConvertTest(volume_helper.MStorageDSVDriver, test.TestCase): self.mock_object(self, '_create_ismview_dir') self._set_config(conf.Configuration(None), 'dummy', 'dummy') self.do_setup(None) - self.vol = DummyVolume(constants.VOLUME_ID) @ddt.data(("AAAAAAAA", "LX:37mA82"), ("BBBBBBBB", "LX:3R9ZwR")) @ddt.unpack def test_volumeid_should_change_62scale(self, volid, ldname): - self.vol.id = volid - actual = self._convert_id2name(self.vol) + vol = DummyVolume(volid) + actual = self._convert_id2name(vol) self.assertEqual(ldname, actual, "ID:%(volid)s should be change to %(ldname)s" % {'volid': volid, 'ldname': ldname}) @@ -389,21 +399,21 @@ class VolumeIDConvertTest(volume_helper.MStorageDSVDriver, test.TestCase): @ddt.data(("AAAAAAAA", "LX:37mA82"), ("BBBBBBBB", "LX:3R9ZwR")) @ddt.unpack def test_snap_volumeid_should_change_62scale_andpostfix(self, - volid, + snapid, ldname): - self.vol.id = volid - actual = self._convert_id2snapname(self.vol) + snap = DummySnapshot(snapid) + actual = self._convert_id2snapname(snap) self.assertEqual(ldname, actual, - "ID:%(volid)s should be change to %(ldname)s" % - {'volid': volid, 'ldname': ldname}) + "ID:%(snapid)s should be change to %(ldname)s" % + {'snapid': snapid, 'ldname': ldname}) @ddt.data(("AAAAAAAA", "LX:37mA82_m"), ("BBBBBBBB", "LX:3R9ZwR_m")) @ddt.unpack def test_ddrsnap_volumeid_should_change_62scale_and_m(self, volid, ldname): - self.vol.id = volid - actual = self._convert_id2migratename(self.vol) + vol = DummyVolume(volid) + actual = self._convert_id2migratename(vol) self.assertEqual(ldname, actual, "ID:%(volid)s should be change to %(ldname)s" % {'volid': volid, 'ldname': ldname}) @@ -439,7 +449,6 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): for var in range(0, 1025): pool_data['ld_list'].append(volume) self.test_pools = [pool_data] - self.vol = DummyVolume(constants.VOLUME_ID, 10) def test_getxml(self): self.assertIsNotNone(self.xml, "iSMview xml should not be None") @@ -449,15 +458,16 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.assertEqual(2, ldn, "selected ldn should be XXX") def test_selectpool_for_normalvolume(self): - pool = self._select_leastused_poolnumber(self.vol, + vol = DummyVolume(constants.VOLUME_ID, 10) + pool = self._select_leastused_poolnumber(vol, self.pools, self.xml) self.assertEqual(1, pool, "selected pool should be 1") # config:pool_pools=[1] - self.vol.size = 999999999999 + vol.size = 999999999999 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_leastused_poolnumber(self.vol, + pool = self._select_leastused_poolnumber(vol, self.pools, self.xml) @@ -465,24 +475,25 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.assertEqual(1, self._return_poolnumber(self.test_pools)) def test_selectpool_for_migratevolume(self): - self.vol.id = "46045673-41e7-44a7-9333-02f07feab04b" + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b") + self.VERSION = '9.99.9' dummyhost = {} dummyhost['capabilities'] = self._update_volume_status() - pool = self._select_migrate_poolnumber(self.vol, + pool = self._select_migrate_poolnumber(vol, self.pools, self.xml, dummyhost) self.assertEqual(1, pool, "selected pool should be 1") - self.vol.id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" - pool = self._select_migrate_poolnumber(self.vol, + vol.id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" + pool = self._select_migrate_poolnumber(vol, self.pools, self.xml, dummyhost) self.assertEqual(-1, pool, "selected pool is the same pool(return -1)") - self.vol.size = 999999999999 + vol.size = 999999999999 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_migrate_poolnumber(self.vol, + pool = self._select_migrate_poolnumber(vol, self.pools, self.xml, dummyhost) @@ -490,7 +501,8 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): def test_selectpool_for_snapvolume(self): savePool1 = self.pools[1]['free'] self.pools[1]['free'] = 0 - pool = self._select_dsv_poolnumber(self.vol, self.pools) + vol = DummyVolume(constants.VOLUME_ID, 10) + pool = self._select_dsv_poolnumber(vol, self.pools) self.assertEqual(2, pool, "selected pool should be 2") # config:pool_backup_pools=[2] self.pools[1]['free'] = savePool1 @@ -502,17 +514,18 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.pools[3]['free'] = 0 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_dsv_poolnumber(self.vol, self.pools) + pool = self._select_dsv_poolnumber(vol, self.pools) self.pools[2]['free'] = savePool2 self.pools[3]['free'] = savePool3 - self.vol.size = 999999999999 - pool = self._select_dsv_poolnumber(self.vol, self.pools) + vol.size = 999999999999 + pool = self._select_dsv_poolnumber(vol, self.pools) self.assertEqual(2, pool, "selected pool should be 2") # config:pool_backup_pools=[2] def test_selectpool_for_ddrvolume(self): - pool = self._select_ddr_poolnumber(self.vol, + vol = DummyVolume(constants.VOLUME_ID, 10) + pool = self._select_ddr_poolnumber(vol, self.pools, self.xml, 10) @@ -525,23 +538,24 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.pools[3]['free'] = 0 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_ddr_poolnumber(self.vol, + pool = self._select_ddr_poolnumber(vol, self.pools, self.xml, 10) self.pools[2]['free'] = savePool2 self.pools[3]['free'] = savePool3 - self.vol.size = 999999999999 + vol.size = 999999999999 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_ddr_poolnumber(self.vol, + pool = self._select_ddr_poolnumber(vol, self.pools, self.xml, 999999999999) def test_selectpool_for_volddrvolume(self): - pool = self._select_volddr_poolnumber(self.vol, + vol = DummyVolume(constants.VOLUME_ID, 10) + pool = self._select_volddr_poolnumber(vol, self.pools, self.xml, 10) @@ -554,17 +568,17 @@ class NominatePoolLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.pools[1]['free'] = 0 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_volddr_poolnumber(self.vol, + pool = self._select_volddr_poolnumber(vol, self.pools, self.xml, 10) self.pools[0]['free'] = savePool0 self.pools[1]['free'] = savePool1 - self.vol.size = 999999999999 + vol.size = 999999999999 with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'No available pools found.'): - pool = self._select_volddr_poolnumber(self.vol, + pool = self._select_volddr_poolnumber(vol, self.pools, self.xml, 999999999999) @@ -610,35 +624,36 @@ class VolumeCreateTest(volume_helper.MStorageDSVDriver, test.TestCase): self.mock_object(self._cli, 'view_all', return_value=xml_out) self.do_setup(None) self.xml = xml_out - self.vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 1) def test_validate_migrate_volume(self): - self.vol.status = 'available' - self._validate_migrate_volume(self.vol, self.xml) + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 1) + vol.status = 'available' + self._validate_migrate_volume(vol, self.xml) - self.vol.status = 'creating' + vol.status = 'creating' with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'Specified Logical Disk' ' LX:287RbQoP7VdwR1WsPC2fZT' ' is not available.'): - self._validate_migrate_volume(self.vol, self.xml) + self._validate_migrate_volume(vol, self.xml) - self.vol.id = "AAAAAAAA" - self.vol.status = 'available' + vol.id = "AAAAAAAA" + vol.status = 'available' with self.assertRaisesRegex(exception.NotFound, 'Logical Disk `LX:37mA82`' ' could not be found.'): - self._validate_migrate_volume(self.vol, self.xml) + self._validate_migrate_volume(vol, self.xml) def test_extend_volume(self): - self.vol.status = 'available' - self.extend_volume(self.vol, 10) + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 1) + vol.status = 'available' + self.extend_volume(vol, 10) - self.vol.id = "00046058-d38e-7f60-67b7-59ed65e54225" # RV + vol.id = "00046058-d38e-7f60-67b7-59ed65e54225" # RV with self.assertRaisesRegex(exception.VolumeBackendAPIException, 'RPL Attribute Error. ' 'RPL Attribute = RV.'): - self.extend_volume(self.vol, 10) + self.extend_volume(vol, 10) class BindLDTest(volume_helper.MStorageDSVDriver, test.TestCase): @@ -652,27 +667,28 @@ class BindLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.mock_object(self._cli, 'view_all', return_value=xml_out) self.do_setup(None) self.mock_object(self, '_bind_ld', return_value=(0, 0, 0)) - self.vol = DummyVolume(constants.VOLUME_ID, 1) def test_bindld_CreateVolume(self): - self.vol.migration_status = "success" - self.create_volume(self.vol) + vol = DummyVolume(constants.VOLUME_ID, 1) + vol.migration_status = "success" + self.create_volume(vol) self._bind_ld.assert_called_once_with( - self.vol, self.vol.size, None, + vol, vol.size, None, self._convert_id2name, self._select_leastused_poolnumber) def test_bindld_CreateCloneVolume(self): - self.vol.migration_status = "success" - self.src = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 1) + vol = DummyVolume(constants.VOLUME_ID, 1) + vol.migration_status = "success" + src = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 1) self.mock_object(self._cli, 'query_BV_SV_status', return_value='snap/active') self.mock_object(self._cli, 'query_MV_RV_name', return_value='separated') self.mock_object(self._cli, 'backup_restore') - self.create_cloned_volume(self.vol, self.src) + self.create_cloned_volume(vol, src) self._bind_ld.assert_called_once_with( - self.vol, self.vol.size, None, + vol, vol.size, None, self._convert_id2name, self._select_leastused_poolnumber) @@ -682,16 +698,16 @@ class BindLDTest(volume_helper.MStorageDSVDriver, test.TestCase): self.assertEqual(60, cli.get_sleep_time_for_clone(19)) def test_delete_volume(self): - self.vol.id = "46045673-41e7-44a7-9333-02f07feab04b" - detached = self._detach_from_all(self.vol) + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b") + detached = self._detach_from_all(vol) self.assertTrue(detached) - self.vol.id = constants.VOLUME_ID - detached = self._detach_from_all(self.vol) + vol.id = constants.VOLUME_ID + detached = self._detach_from_all(vol) self.assertFalse(detached) - self.vol.id = constants.VOLUME2_ID + vol.id = constants.VOLUME2_ID with mock.patch.object(self, '_detach_from_all') as detach_mock: - self.delete_volume(self.vol) - detach_mock.assert_called_once_with(self.vol) + self.delete_volume(vol) + detach_mock.assert_called_once_with(vol) class BindLDTest_Snap(volume_helper.MStorageDSVDriver, test.TestCase): @@ -706,25 +722,25 @@ class BindLDTest_Snap(volume_helper.MStorageDSVDriver, test.TestCase): self.do_setup(None) self.mock_object(self, '_bind_ld', return_value=(0, 0, 0)) self.mock_object(self, '_create_snapshot') - self.vol = DummyVolume(constants.VOLUME_ID) - self.snap = DummyVolume(constants.SNAPSHOT_ID) def test_bindld_CreateSnapshot(self): - self.snap.volume_id = constants.VOLUME_ID - self.create_snapshot(self.snap) + snap = DummySnapshot(constants.SNAPSHOT_ID) + snap.volume_id = constants.VOLUME_ID + self.create_snapshot(snap) self._create_snapshot.assert_called_once_with( - self.snap, self._properties['diskarray_name']) + snap, self._properties['diskarray_name']) def test_bindld_CreateFromSnapshot(self): - self.vol.migration_status = "success" - self.snap.id = "63410c76-2f12-4473-873d-74a63dfcd3e2" - self.snap.volume_id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" + vol = DummyVolume(constants.VOLUME_ID) + vol.migration_status = "success" + snap = DummySnapshot("63410c76-2f12-4473-873d-74a63dfcd3e2") + snap.volume_id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" self.mock_object(self._cli, 'query_BV_SV_status', return_value='snap/active') self.mock_object(self._cli, 'backup_restore') - self.create_volume_from_snapshot(self.vol, self.snap) + self.create_volume_from_snapshot(vol, snap) self._bind_ld.assert_called_once_with( - self.vol, 1, None, + vol, 1, None, self._convert_id2name, self._select_volddr_poolnumber, 1) @@ -739,50 +755,57 @@ class ExportTest(volume_helper.MStorageDSVDriver, test.TestCase): return_value=('success', 0, 0)) self.mock_object(self._cli, 'view_all', return_value=xml_out) self.do_setup(None) - self.vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b", 10) - - def test_iscsi_portal(self): - connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"} - self.iscsi_do_export(None, self.vol, connector, - self._properties['diskarray_name']) - - def test_fc_do_export(self): - connector = {'wwpns': ["10000090FAA0786A", "10000090FAA0786B"]} - self.fc_do_export(None, self.vol, connector) def test_iscsi_initialize_connection(self): - loc = "127.0.0.1:3260:1 iqn.2010-10.org.openstack:volume-00000001 88" - self.vol.provider_location = loc + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b") connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255", 'multipath': False} - info = self._iscsi_initialize_connection(self.vol, connector) + info = self.iscsi_initialize_connection(vol, connector) self.assertEqual('iscsi', info['driver_volume_type']) - self.assertEqual('iqn.2010-10.org.openstack:volume-00000001', - info['data']['target_iqn']) - self.assertEqual('127.0.0.1:3260', info['data']['target_portal']) - self.assertEqual(88, info['data']['target_lun']) + self.assertEqual('iqn.2001-03.target0000', info['data']['target_iqn']) + self.assertIn(info['data']['target_portal'], + ['192.168.1.90:3260', '192.168.1.91:3260', + '192.168.2.92:3260', '192.168.2.93:3260']) + self.assertEqual(0, info['data']['target_lun']) + + vol.id = "87d8d42f-7550-4f43-9a2b-fe722bf86941" + with self.assertRaisesRegex(exception.NotFound, + 'Logical Disk `LX:48L3QCi4npuqxPX0Lyeu8H`' + ' could not be found.'): + self.iscsi_initialize_connection(vol, connector) def test_iscsi_multipath_initialize_connection(self): - self.vol.id = "46045673-41e7-44a7-9333-02f07feab04b" - loc = ("1.1.1.1:3260;2.2.2.2:3260,1 " - "iqn.2010-10.org.openstack:volume-00000001 88") - self.vol.provider_location = loc + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b") connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255", 'multipath': True} - info = self._iscsi_initialize_connection(self.vol, connector) + info = self.iscsi_initialize_connection(vol, connector) self.assertEqual('iscsi', info['driver_volume_type']) - self.assertEqual('iqn.2010-10.org.openstack:volume-00000001', + self.assertEqual('iqn.2001-03.target0000', info['data']['target_iqn']) - self.assertEqual('1.1.1.1:3260', info['data']['target_portal']) - self.assertEqual(88, info['data']['target_lun']) - self.assertEqual('iqn.2010-10.org.openstack:volume-00000001', + self.assertIn(info['data']['target_portal'], + ['192.168.1.90:3260', '192.168.1.91:3260', + '192.168.2.92:3260', '192.168.2.93:3260']) + self.assertEqual(0, info['data']['target_lun']) + self.assertEqual('iqn.2001-03.target0000', info['data']['target_iqns'][0]) - self.assertEqual('iqn.2010-10.org.openstack:volume-00000001', + self.assertEqual('iqn.2001-03.target0000', info['data']['target_iqns'][1]) - self.assertEqual('1.1.1.1:3260', info['data']['target_portals'][0]) - self.assertEqual('2.2.2.2:3260', info['data']['target_portals'][1]) - self.assertEqual(88, info['data']['target_luns'][0]) - self.assertEqual(88, info['data']['target_luns'][1]) + self.assertEqual('iqn.2001-03.target0000', + info['data']['target_iqns'][2]) + self.assertEqual('iqn.2001-03.target0000', + info['data']['target_iqns'][3]) + self.assertEqual(info['data']['target_portals'][0], + '192.168.1.90:3260') + self.assertEqual(info['data']['target_portals'][1], + '192.168.1.91:3260') + self.assertEqual(info['data']['target_portals'][2], + '192.168.2.92:3260') + self.assertEqual(info['data']['target_portals'][3], + '192.168.2.93:3260') + self.assertEqual(0, info['data']['target_luns'][0]) + self.assertEqual(0, info['data']['target_luns'][1]) + self.assertEqual(0, info['data']['target_luns'][2]) + self.assertEqual(0, info['data']['target_luns'][3]) def test_iscsi_terminate_connection(self): ctx = context.RequestContext('admin', 'fake', True) @@ -1019,25 +1042,6 @@ class ExportTest(volume_helper.MStorageDSVDriver, test.TestCase): ret = self._is_multi_attachment(vol, connector) self.assertFalse(ret) - def test_iscsi_portal_with_controller_node_name(self): - self.vol.status = 'downloading' - connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"} - self._properties['ldset_controller_node_name'] = 'LX:OpenStack1' - self._properties['portal_number'] = 2 - location = self.iscsi_do_export(None, self.vol, connector, - self._properties['diskarray_name']) - self.assertEqual('192.168.1.90:3260;192.168.1.91:3260;' - '192.168.2.92:3260;192.168.2.93:3260' - ',1 iqn.2001-03.target0000 0', - location['provider_location']) - - def test_fc_do_export_with_controller_node_name(self): - self.vol.status = 'downloading' - connector = {'wwpns': ["10000090FAA0786A", "10000090FAA0786B"]} - self._properties['ldset_controller_node_name'] = 'LX:OpenStack0' - location = self.fc_do_export(None, self.vol, connector) - self.assertIsNone(location) - class DeleteDSVVolume_test(volume_helper.MStorageDSVDriver, test.TestCase): @@ -1050,13 +1054,13 @@ class DeleteDSVVolume_test(volume_helper.MStorageDSVDriver, return_value=('success', 0, 0)) self.mock_object(self._cli, 'view_all', return_value=xml_out) self.do_setup(None) - self.vol = DummyVolume(constants.SNAPSHOT_ID) - self.vol.volume_id = constants.VOLUME_ID def test_delete_snapshot(self): self.mock_object(self._cli, 'query_BV_SV_status', return_value='snap/active') - ret = self.delete_snapshot(self.vol) + snap = DummySnapshot(constants.SNAPSHOT_ID) + snap.volume_id = constants.VOLUME_ID + ret = self.delete_snapshot(snap) self.assertIsNone(ret) @@ -1070,8 +1074,9 @@ class NonDisruptiveBackup_test(volume_helper.MStorageDSVDriver, self.mock_object(self._cli, '_execute', return_value=('success', 0, 0)) self.mock_object(self._cli, 'view_all', return_value=xml_out) + self.mock_object(self._cli, 'query_BV_SV_status', + return_value='snap/active') self.do_setup(None) - self.vol = DummyVolume('46045673-41e7-44a7-9333-02f07feab04b') self.xml = xml_out (self.pools, self.lds, @@ -1081,15 +1086,16 @@ class NonDisruptiveBackup_test(volume_helper.MStorageDSVDriver, self.max_ld_count) = self.configs(self.xml) def test_validate_ld_exist(self): + vol = DummyVolume("46045673-41e7-44a7-9333-02f07feab04b") ldname = self._validate_ld_exist( - self.lds, self.vol.id, self._properties['ld_name_format']) + self.lds, vol.id, self._properties['ld_name_format']) self.assertEqual('LX:287RbQoP7VdwR1WsPC2fZT', ldname) - self.vol.id = "00000000-0000-0000-0000-6b6d96553b4b" + vol.id = "00000000-0000-0000-0000-6b6d96553b4b" with self.assertRaisesRegex(exception.NotFound, 'Logical Disk `LX:XXXXXXXX`' ' could not be found.'): self._validate_ld_exist( - self.lds, self.vol.id, self._properties['ld_name_format']) + self.lds, vol.id, self._properties['ld_name_format']) def test_validate_iscsildset_exist(self): connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"} @@ -1137,7 +1143,6 @@ class NonDisruptiveBackup_test(volume_helper.MStorageDSVDriver, connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"} ldset = self._validate_iscsildset_exist(self.ldsets, connector) self.assertEqual('LX:OpenStack0', ldset['ldsetname']) - self._properties['portal_number'] = 2 portal = self._enumerate_iscsi_portals(self.hostports, ldset) self.assertEqual('192.168.1.90:3260', portal[0]) self.assertEqual('192.168.1.91:3260', portal[1]) @@ -1145,50 +1150,52 @@ class NonDisruptiveBackup_test(volume_helper.MStorageDSVDriver, self.assertEqual('192.168.2.93:3260', portal[3]) def test_initialize_connection_snapshot(self): - connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"} - loc = "127.0.0.1:3260:1 iqn.2010-10.org.openstack:volume-00000001 88" - self.vol.provider_location = loc - ret = self.iscsi_initialize_connection_snapshot(self.vol, connector) + snap = DummySnapshot('46045673-41e7-44a7-9333-02f07feab04b') + snap.volume_id = "92dbc7f4-dbc3-4a87-aef4-d5a2ada3a9af" + connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255", + 'multipath': True} + ret = self.iscsi_initialize_connection_snapshot(snap, connector) self.assertIsNotNone(ret) self.assertEqual('iscsi', ret['driver_volume_type']) connector = {'wwpns': ["10000090FAA0786A", "10000090FAA0786B"]} - ret = self.fc_initialize_connection_snapshot(self.vol, connector) + ret = self.fc_initialize_connection_snapshot(snap, connector) self.assertIsNotNone(ret) self.assertEqual('fibre_channel', ret['driver_volume_type']) def test_terminate_connection_snapshot(self): ctx = context.RequestContext('admin', 'fake', True) - vol = fake_volume_obj(ctx, id="46045673-41e7-44a7-9333-02f07feab04b") + snap = fake_volume_obj(ctx, id="46045673-41e7-44a7-9333-02f07feab04b") connector = {'initiator': 'iqn.1994-05.com.redhat:d1d8e8f23255', 'host': 'DummyHost'} attachment = { 'id': constants.ATTACHMENT_ID, - 'volume_id': vol.id, + 'volume_id': snap.id, 'connector': connector } attach_object = volume_attachment.VolumeAttachment(**attachment) attachment = volume_attachment.VolumeAttachmentList( objects=[attach_object]) - vol.volume_attachment = attachment - self.iscsi_terminate_connection_snapshot(vol, connector) + snap.volume_attachment = attachment + self.iscsi_terminate_connection_snapshot(snap, connector) connector = {'wwpns': ["10000090FAA0786A", "10000090FAA0786B"], 'host': 'DummyHost'} attachment = { 'id': constants.ATTACHMENT_ID, - 'volume_id': vol.id, + 'volume_id': snap.id, 'connector': connector } attach_object = volume_attachment.VolumeAttachment(**attachment) attachment = volume_attachment.VolumeAttachmentList( objects=[attach_object]) - vol.volume_attachment = attachment - ret = self.fc_terminate_connection_snapshot(vol, connector) + snap.volume_attachment = attachment + ret = self.fc_terminate_connection_snapshot(snap, connector) self.assertEqual('fibre_channel', ret['driver_volume_type']) def test_remove_export_snapshot(self): - self.remove_export_snapshot(None, self.vol) + snap = DummySnapshot('46045673-41e7-44a7-9333-02f07feab04b') + self.remove_export_snapshot(None, snap) def test_backup_use_temp_snapshot(self): ret = self.backup_use_temp_snapshot() @@ -1204,6 +1211,7 @@ class VolumeStats_test(volume_helper.MStorageDSVDriver, test.TestCase): self._properties['cli_fip'] = '10.0.0.1' self._properties['pool_pools'] = {0, 1} self._properties['pool_backup_pools'] = {2, 3} + self.VERSION = '9.99.9' def test_update_volume_status(self): self.mock_object(volume_common.MStorageVolumeCommon, 'parse_xml', @@ -1270,12 +1278,12 @@ class Migrate_test(volume_helper.MStorageDSVDriver, test.TestCase): return_value=('success', 0, 0)) self.mock_object(self._cli, 'view_all', return_value=xml_out) self.do_setup(None) - self.newvol = DummyVolume(constants.VOLUME_ID) - self.sourcevol = DummyVolume(constants.VOLUME2_ID) def test_update_migrate_volume(self): - update_data = self.update_migrated_volume(None, self.sourcevol, - self.newvol, 'available') + newvol = DummyVolume(constants.VOLUME_ID) + sourcevol = DummyVolume(constants.VOLUME2_ID) + update_data = self.update_migrated_volume(None, sourcevol, + newvol, 'available') self.assertIsNone(update_data['_name_id']) self.assertIsNone(update_data['provider_location']) @@ -1290,7 +1298,6 @@ class ManageUnmanage_test(volume_helper.MStorageDSVDriver, test.TestCase): self.do_setup(None) self._properties['pool_pools'] = {0} self._properties['pool_backup_pools'] = {1} - self.newvol = DummyVolume(constants.VOLUME_ID) def test_is_manageable_volume(self): ld_ok_iv = {'pool_num': 0, 'RPL Attribute': 'IV', 'Purpose': '---'} @@ -1335,22 +1342,24 @@ class ManageUnmanage_test(volume_helper.MStorageDSVDriver, test.TestCase): current_volumes = [] volumes = self.get_manageable_volumes(current_volumes, None, 100, 0, ['reference'], ['dec']) - self.manage_existing(self.newvol, volumes[4]['reference']) + newvol = DummyVolume(constants.VOLUME_ID) + self.manage_existing(newvol, volumes[4]['reference']) self._cli.changeldname.assert_called_once_with( None, 'LX:vD03hJCiHvGpvP4iSevKk', ' :20000009910200140009') with self.assertRaisesRegex(exception.ManageExistingInvalidReference, 'Specified resource is already in-use.'): - self.manage_existing(self.newvol, volumes[3]['reference']) + self.manage_existing(newvol, volumes[3]['reference']) volume = {'source-name': 'LX:yEUHrXa5AHMjOZZLb93eP'} with self.assertRaisesRegex(exception.ManageExistingVolumeTypeMismatch, 'Volume type is unmatched.'): - self.manage_existing(self.newvol, volume) + self.manage_existing(newvol, volume) def test_manage_existing_get_size(self): current_volumes = [] volumes = self.get_manageable_volumes(current_volumes, None, 100, 0, ['reference'], ['dec']) - size_in_gb = self.manage_existing_get_size(self.newvol, + newvol = DummyVolume(constants.VOLUME_ID) + size_in_gb = self.manage_existing_get_size(newvol, volumes[3]['reference']) self.assertEqual(10, size_in_gb) @@ -1365,8 +1374,6 @@ class ManageUnmanage_Snap_test(volume_helper.MStorageDSVDriver, test.TestCase): self.do_setup(None) self._properties['pool_pools'] = {0} self._properties['pool_backup_pools'] = {1} - self.newsnap = DummyVolume('46045673-41e7-44a7-9333-02f07feab04b') - self.newsnap.volume_id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" def test_is_manageable_snapshot(self): ld_ok_sv1 = {'pool_num': 1, 'RPL Attribute': 'SV', 'Purpose': 'INV'} @@ -1400,23 +1407,25 @@ class ManageUnmanage_Snap_test(volume_helper.MStorageDSVDriver, test.TestCase): current_snapshots = [] snaps = self.get_manageable_snapshots(current_snapshots, None, 100, 0, ['reference'], ['asc']) - self.manage_existing_snapshot(self.newsnap, snaps[0]['reference']) + newsnap = DummySnapshot('46045673-41e7-44a7-9333-02f07feab04b') + newsnap.volume_id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" + self.manage_existing_snapshot(newsnap, snaps[0]['reference']) self._cli.changeldname.assert_called_once_with( None, 'LX:287RbQoP7VdwR1WsPC2fZT', 'LX:4T7JpyqI3UuPlKeT9D3VQF') - self.newsnap.volume_id = "AAAAAAAA" + newsnap.volume_id = "AAAAAAAA" with self.assertRaisesRegex(exception.ManageExistingInvalidReference, 'Snapshot source is unmatch.'): - self.manage_existing_snapshot(self.newsnap, snaps[0]['reference']) + self.manage_existing_snapshot(newsnap, snaps[0]['reference']) self._cli.get_bvname.return_value = "2000000991020012000C" - self.newsnap.volume_id = "00046058-d38e-7f60-67b7-59ed6422520c" + newsnap.volume_id = "00046058-d38e-7f60-67b7-59ed6422520c" snap = {'source-name': ' :2000000991020012000B'} with self.assertRaisesRegex(exception.ManageExistingVolumeTypeMismatch, 'Volume type is unmatched.'): - self.manage_existing_snapshot(self.newsnap, snap) + self.manage_existing_snapshot(newsnap, snap) def test_manage_existing_snapshot_get_size(self): self.mock_object(self._cli, 'get_bvname', @@ -1424,7 +1433,9 @@ class ManageUnmanage_Snap_test(volume_helper.MStorageDSVDriver, test.TestCase): current_snapshots = [] snaps = self.get_manageable_snapshots(current_snapshots, None, 100, 0, ['reference'], ['asc']) + newsnap = DummySnapshot('46045673-41e7-44a7-9333-02f07feab04b') + newsnap.volume_id = "1febb976-86d0-42ed-9bc0-4aa3e158f27d" size_in_gb = self.manage_existing_snapshot_get_size( - self.newsnap, + newsnap, snaps[0]['reference']) self.assertEqual(6, size_in_gb) diff --git a/cinder/volume/drivers/nec/cli.py b/cinder/volume/drivers/nec/cli.py index e726bb137da..6aa612314ad 100644 --- a/cinder/volume/drivers/nec/cli.py +++ b/cinder/volume/drivers/nec/cli.py @@ -149,22 +149,22 @@ class MStorageISMCLI(object): stdin, stdout, stderr = ssh.exec_command(command) stdin.close() channel = stdout.channel - _out, _err = [], [] + tmpout, tmperr = b'', b'' while 1: select.select([channel], [], []) if channel.recv_ready(): - _out.append(channel.recv(4096)) + tmpout += channel.recv(4096) continue if channel.recv_stderr_ready(): - _err.append(channel.recv_stderr(4096)) + tmperr += channel.recv_stderr(4096) continue if channel.exit_status_ready(): status = channel.recv_exit_status() break LOG.debug('`%(command)s` done. status=%(status)d.', {'command': command, 'status': status}) - out = self._join_and_convert_str(_out) - err = self._join_and_convert_str(_err) + out = utils.convert_str(tmpout) + err = utils.convert_str(tmperr) if expected_status is not None and status not in expected_status: LOG.debug('`%(command)s` failed. status=%(status)d, ' 'out="%(out)s", err="%(err)s".', @@ -673,14 +673,6 @@ class MStorageISMCLI(object): 'cvnumber': cvnumber}) self._execute(cmd) - def _join_and_convert_str(self, src_list): - if len(src_list) == 0: - return '' - if isinstance(src_list[0], bytes): - return utils.convert_str(b''.join(src_list)) - else: - return ''.join(src_list) - class UnpairWait(object): diff --git a/cinder/volume/drivers/nec/volume.py b/cinder/volume/drivers/nec/volume.py index a077e6b30da..5f9b5f1f5c6 100644 --- a/cinder/volume/drivers/nec/volume.py +++ b/cinder/volume/drivers/nec/volume.py @@ -47,9 +47,12 @@ class MStorageISCSIDriver(volume_helper.MStorageDSVDriver, Fixed bug #1777385: driver removed access permission from the destination node after live-migraion. Fixed bug #1778669: LUNs of detached volumes are never reused. + 1.11.1 - Add support pytyon 3. + Add support for multi-attach. + Add support of more than 4 iSCSI portals for a node. """ - VERSION = '1.10.3' + VERSION = '1.11.1' CI_WIKI_NAME = 'NEC_Cinder_CI' def __init__(self, *args, **kwargs): @@ -61,9 +64,6 @@ class MStorageISCSIDriver(volume_helper.MStorageDSVDriver, def get_driver_options(): return volume_common.mstorage_opts - def create_export(self, context, volume, connector): - return self.iscsi_do_export(context, volume, connector) - def ensure_export(self, context, volume): pass @@ -76,9 +76,6 @@ class MStorageISCSIDriver(volume_helper.MStorageDSVDriver, def terminate_connection(self, volume, connector, **kwargs): return self.iscsi_terminate_connection(volume, connector) - def create_export_snapshot(self, context, snapshot, connector): - return self.iscsi_do_export_snapshot(context, snapshot, connector) - def initialize_connection_snapshot(self, snapshot, connector, **kwargs): return self.iscsi_initialize_connection_snapshot(snapshot, connector, @@ -114,9 +111,12 @@ class MStorageFCDriver(volume_helper.MStorageDSVDriver, Fixed bug #1777385: driver removed access permission from the destination node after live-migraion. Fixed bug #1778669: LUNs of detached volumes are never reused. + 1.11.1 - Add support pytyon 3. + Add support for multi-attach. + Add support of more than 4 iSCSI portals for a node. """ - VERSION = '1.10.3' + VERSION = '1.11.1' CI_WIKI_NAME = 'NEC_Cinder_CI' def __init__(self, *args, **kwargs): @@ -128,9 +128,6 @@ class MStorageFCDriver(volume_helper.MStorageDSVDriver, def get_driver_options(): return volume_common.mstorage_opts - def create_export(self, context, volume, connector): - return self.fc_do_export(context, volume, connector) - def ensure_export(self, context, volume): pass @@ -147,9 +144,6 @@ class MStorageFCDriver(volume_helper.MStorageDSVDriver, fczm_utils.remove_fc_zone(conn_info) return conn_info - def create_export_snapshot(self, context, snapshot, connector): - return self.fc_do_export_snapshot(context, snapshot, connector) - def initialize_connection_snapshot(self, snapshot, connector, **kwargs): return self.fc_initialize_connection_snapshot(snapshot, connector, diff --git a/cinder/volume/drivers/nec/volume_common.py b/cinder/volume/drivers/nec/volume_common.py index 3c2b142deda..37144a01f51 100644 --- a/cinder/volume/drivers/nec/volume_common.py +++ b/cinder/volume/drivers/nec/volume_common.py @@ -94,8 +94,12 @@ mstorage_opts = [ default=False, help='Use legacy iSMCLI command.'), cfg.IntOpt('nec_iscsi_portals_per_cont', - default=1, - help='Number of iSCSI portals.'), + default=0, + deprecated_for_removal=True, + help='Max number of iSCSI portals per controller. ' + '0 => unlimited. ' + 'This option is deprecated and may ' + 'be removed in the next release.'), cfg.BoolOpt('nec_auto_accesscontrol', default=True, help='Configure access control automatically.'), @@ -153,9 +157,6 @@ def convert_to_id(value62): class MStorageVolumeCommon(object): """M-Series Storage volume common class.""" - VERSION = '1.10.2' - WIKI_NAME = 'NEC_Cinder_CI' - def do_setup(self, context): self._context = context diff --git a/cinder/volume/drivers/nec/volume_helper.py b/cinder/volume/drivers/nec/volume_helper.py index 5ed12e18e55..2f5dedb70d9 100644 --- a/cinder/volume/drivers/nec/volume_helper.py +++ b/cinder/volume/drivers/nec/volume_helper.py @@ -274,30 +274,30 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): return ldset def _enumerate_iscsi_portals(self, hostports, ldset, prefered_director=0): - nominated = [] + portals = [] for director in [prefered_director, 1 - prefered_director]: if director not in hostports: continue - dirportal = [] + dirportals = [] for port in hostports[director]: if not port['protocol'].lower() == 'iscsi': continue for portal in ldset['portal_list']: if portal.startswith(port['ip'] + ':'): - dirportal.append(portal) + dirportals.append(portal) break if (self._properties['portal_number'] > 0 and - len(dirportal) > self._properties['portal_number']): - nominated.extend( - dirportal[0:self._properties['portal_number']]) + len(dirportals) > self._properties['portal_number']): + portals.extend( + dirportals[0:self._properties['portal_number']]) else: - nominated.extend(dirportal) + portals.extend(dirportals) - if len(nominated) == 0: + if len(portals) == 0: raise exception.NotFound( _('No portal matches to any host ports.')) - return nominated + return portals def create_volume(self, volume): msgparm = ('Volume ID = %(id)s, Size = %(size)dGB' @@ -708,121 +708,15 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): target_lun += 1 return target_lun - def iscsi_do_export(self, _ctx, volume, connector, ensure=False): - msgparm = ('Volume ID = %(id)s, ' - 'Initiator Name = %(initiator)s' - % {'id': volume.id, - 'initiator': connector['initiator']}) - try: - ret = self._iscsi_do_export(_ctx, volume, connector, ensure, - self._properties['diskarray_name']) - LOG.info('Created iSCSI Export (%s)', msgparm) - return ret - except exception.CinderException as e: - with excutils.save_and_reraise_exception(): - LOG.warning('Failed to Create iSCSI Export ' - '(%(msgparm)s) (%(exception)s)', - {'msgparm': msgparm, 'exception': e}) + def create_export(self, context, volume, connector): + pass + + def create_export_snapshot(self, context, snapshot, connector): + pass @coordination.synchronized('mstorage_bind_execute_{diskarray_name}') - def _iscsi_do_export(self, _ctx, volume, connector, ensure, - diskarray_name): - LOG.debug('_iscsi_do_export' - '(Volume ID = %(id)s, connector = %(connector)s) Start.', - {'id': volume.id, 'connector': connector}) - - xml = self._cli.view_all(self._properties['ismview_path']) - pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( - self.configs(xml)) - - # find LD Set. - ldset = self._validate_iscsildset_exist( - ldsets, connector) - ldname = self.get_ldname( - volume.id, self._properties['ld_name_format']) - - # add LD to LD set. - if ldname not in lds: - msg = _('Logical Disk `%s` could not be found.') % ldname - raise exception.NotFound(msg) - ld = lds[ldname] - - if ld['ldn'] not in ldset['lds']: - # assign the LD to LD Set. - self._cli.addldsetld(ldset['ldsetname'], ldname, - self._get_free_lun(ldset)) - # update local info. - xml = self._cli.view_all(self._properties['ismview_path']) - pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( - self.configs(xml)) - ldset = self._validate_iscsildset_exist(ldsets, connector) - LOG.debug('Add LD `%(ld)s` to LD Set `%(ldset)s`.', - {'ld': ldname, 'ldset': ldset['ldsetname']}) - - # enumerate portals for iscsi multipath. - prefered_director = ld['pool_num'] % 2 - nominated = self._enumerate_iscsi_portals(hostports, ldset, - prefered_director) - location = ('%(list)s,1 %(iqn)s %(lun)d' - % {'list': ';'.join(nominated), - 'iqn': ldset['lds'][ld['ldn']]['iqn'], - 'lun': ldset['lds'][ld['ldn']]['lun']}) - - LOG.debug('%(ensure)sexport LD `%(name)s` via `%(location)s`.', - {'ensure': 'ensure_' if ensure else '', - 'name': ldname, - 'location': location}) - return {'provider_location': location} - - def fc_do_export(self, _ctx, volume, connector, ensure=False): - msgparm = ('Volume ID = %(id)s, ' - 'Initiator WWPNs = %(wwpns)s' - % {'id': volume.id, - 'wwpns': connector['wwpns']}) - try: - ret = self._fc_do_export(_ctx, volume, connector, ensure, - self._properties['diskarray_name']) - LOG.info('Created FC Export (%s)', msgparm) - return ret - except exception.CinderException as e: - with excutils.save_and_reraise_exception(): - LOG.warning('Failed to Create FC Export ' - '(%(msgparm)s) (%(exception)s)', - {'msgparm': msgparm, 'exception': e}) - - @coordination.synchronized('mstorage_bind_execute_{diskarray_name}') - def _fc_do_export(self, _ctx, volume, connector, ensure, diskarray_name): - LOG.debug('_fc_do_export' - '(Volume ID = %(id)s, connector = %(connector)s) Start.', - {'id': volume.id, 'connector': connector}) - xml = self._cli.view_all(self._properties['ismview_path']) - pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( - self.configs(xml)) - - # get target LD Set. - ldset = self._validate_fcldset_exist(ldsets, connector) - ldname = self.get_ldname(volume.id, self._properties['ld_name_format']) - - # add LD to LD set. - if ldname not in lds: - msg = _('Logical Disk `%s` could not be found.') % ldname - raise exception.NotFound(msg) - ld = lds[ldname] - - if ld['ldn'] not in ldset['lds']: - # assign the LD to LD Set. - self._cli.addldsetld(ldset['ldsetname'], ldname, - self._get_free_lun(ldset)) - LOG.debug('Add LD `%(ld)s` to LD Set `%(ldset)s`.', - {'ld': ldname, 'ldset': ldset['ldsetname']}) - - LOG.debug('%(ensure)sexport LD `%(ld)s`.', - {'ensure': 'ensure_' if ensure else '', - 'ld': ldname}) - - @coordination.synchronized('mstorage_bind_execute_{diskarray_name}') - def _create_snapshot_and_link(self, context, snapshot, connector, - diskarray_name, validate_ldset_exist): + def _create_snapshot_and_link(self, snapshot, connector, diskarray_name, + validate_ldset_exist): xml = self._cli.view_all(self._properties['ismview_path']) pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( self.configs(xml)) @@ -864,78 +758,6 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): {'ld': lvname, 'ldset': ldset['ldsetname']}) return lvname - def iscsi_do_export_snapshot(self, context, snapshot, connector): - """Exports the snapshot.""" - msgparm = 'Snapshot ID = %s' % snapshot.id - try: - ret = self._iscsi_do_export_snapshot( - context, snapshot, connector, - self._properties['diskarray_name']) - LOG.info('Create Export Snapshot (%s)', msgparm) - return ret - except exception.CinderException as e: - with excutils.save_and_reraise_exception(): - LOG.warning('Failed to Create Export Snapshot ' - '(%(msgparm)s) (%(exception)s)', - {'msgparm': msgparm, 'exception': e}) - - def _iscsi_do_export_snapshot(self, context, snapshot, connector, - diskarray_name): - LOG.debug('_iscsi_do_export_snapshot(Snapshot ID = %s) Start.', - snapshot.id) - - lvname = ( - self._create_snapshot_and_link(context, snapshot, connector, - diskarray_name, - self._validate_iscsildset_exist)) - - xml = self._cli.view_all(self._properties['ismview_path']) - pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( - self.configs(xml)) - ld = lds[lvname] - ldset = self._validate_iscsildset_exist(ldsets, connector) - - LOG.debug('enumerate portals for iscsi multipath.') - prefered_director = ld['pool_num'] % 2 - nominated = self._enumerate_iscsi_portals(hostports, ldset, - prefered_director) - location = ('%(list)s,1 %(iqn)s %(lun)d' - % {'list': ';'.join(nominated), - 'iqn': ldset['lds'][ld['ldn']]['iqn'], - 'lun': ldset['lds'][ld['ldn']]['lun']}) - - LOG.debug('create_export_snapshot location:(%s)', location) - return {'provider_location': location} - - def fc_do_export_snapshot(self, context, snapshot, connector, - ensure=False): - msgparm = ('Volume ID = %(id)s, ' - 'Initiator WWPNs = %(wwpns)s' - % {'id': snapshot.id, - 'wwpns': connector['wwpns']}) - try: - ret = self._fc_do_export_snapshot( - context, snapshot, connector, ensure, - self._properties['diskarray_name']) - LOG.info('Created FC Export snapshot(%s)', msgparm) - return ret - except exception.CinderException as e: - with excutils.save_and_reraise_exception(): - LOG.warning('Failed to Create FC Export snapshot' - '(%(msgparm)s) (%(exception)s)', - {'msgparm': msgparm, 'exception': e}) - - def _fc_do_export_snapshot(self, context, snapshot, connector, ensure, - diskarray_name): - LOG.debug('_fc_do_export_snapshot(Snapshot ID = %s) Start.', - snapshot.id) - lvname = self._create_snapshot_and_link(context, snapshot, connector, - diskarray_name, - self._validate_fcldset_exist) - LOG.debug('%(ensure)sexport LD `%(ld)s`.', - {'ensure': 'ensure_' if ensure else '', - 'ld': lvname}) - def remove_export(self, context, volume): pass @@ -1055,6 +877,28 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): LOG.debug('_remove_export_snapshot(Snapshot ID = %s) End.', snapshot.id) + @coordination.synchronized('mstorage_bind_execute_{diskarray_name}') + def _export_volume(self, volume, connector, diskarray_name, + validate_exist): + xml = self._cli.view_all(self._properties['ismview_path']) + pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( + self.configs(xml)) + ldset = validate_exist(ldsets, connector) + ldname = self.get_ldname( + volume.id, self._properties['ld_name_format']) + if ldname not in lds: + msg = _('Logical Disk `%s` could not be found.') % ldname + raise exception.NotFound(msg) + ld = lds[ldname] + if ld['ldn'] not in ldset['lds']: + self._cli.addldsetld(ldset['ldsetname'], ldname, + self._get_free_lun(ldset)) + # update local info. + LOG.debug('Add LD `%(ld)s` to LD Set `%(ldset)s`.', + {'ld': ldname, 'ldset': ldset['ldsetname']}) + + return ldname + def iscsi_initialize_connection(self, volume, connector): msgparm = ('Volume ID = %(id)s, Connector = %(connector)s' % {'id': volume.id, 'connector': connector}) @@ -1069,7 +913,8 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): '(%(msgparm)s) (%(exception)s)', {'msgparm': msgparm, 'exception': e}) - def _iscsi_initialize_connection(self, volume, connector): + def _iscsi_initialize_connection(self, volume, connector, + is_snapshot=False): """Initializes the connection and returns connection info. The iscsi driver returns a driver_volume_type of 'iscsi'. @@ -1089,27 +934,48 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): """ LOG.debug('_iscsi_initialize_connection' - '(Volume ID = %(id)s, connector = %(connector)s) Start.', - {'id': volume.id, 'connector': connector}) + '(Volume ID = %(id)s, connector = %(connector)s, ' + 'snapshot = %(snapshot)s) Start.', + {'id': volume.id, 'connector': connector, + 'snapshot': is_snapshot}) + + # configure access control + if is_snapshot: + ldname = self._create_snapshot_and_link( + volume, connector, + self._properties['diskarray_name'], + self._validate_iscsildset_exist) + else: + ldname = self._export_volume(volume, connector, + self._properties['diskarray_name'], + self._validate_iscsildset_exist) + + xml = self._cli.view_all(self._properties['ismview_path']) + pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( + self.configs(xml)) + + # enumerate portals for iscsi multipath. + ld = lds[ldname] + ldset = self._validate_iscsildset_exist(ldsets, connector) + prefered_director = ld['pool_num'] % 2 + portals = self._enumerate_iscsi_portals(hostports, ldset, + prefered_director) - provider_location = volume.provider_location - provider_location = provider_location.split() info = {'driver_volume_type': 'iscsi', 'data': {'target_portal': - provider_location[0][0:-2].split(";")[0], - 'target_iqn': provider_location[1], - 'target_lun': int(provider_location[2]), + portals[int(volume.id[:1], 16) % len(portals)], + 'target_iqn': ldset['lds'][ld['ldn']]['iqn'], + 'target_lun': ldset['lds'][ld['ldn']]['lun'], 'target_discovered': False, 'volume_id': volume.id} } if connector.get('multipath'): - portals_len = len(provider_location[0][0:-2].split(";")) - info['data'].update({'target_portals': - provider_location[0][0:-2].split(";"), - 'target_iqns': [provider_location[1]] * - portals_len, - 'target_luns': [int(provider_location[2])] * - portals_len}) + portals_len = len(portals) + info['data'].update({'target_portals': portals, + 'target_iqns': [ldset['lds'][ld['ldn']] + ['iqn']] * portals_len, + 'target_luns': [ldset['lds'][ld['ldn']] + ['lun']] * portals_len}) LOG.debug('_iscsi_initialize_connection' '(Volume ID = %(id)s, connector = %(connector)s, ' 'info = %(info)s) End.', @@ -1133,7 +999,8 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): % {'id': snapshot.id, 'connector': connector}) try: - ret = self._iscsi_initialize_connection(snapshot, connector) + ret = self._iscsi_initialize_connection(snapshot, connector, + is_snapshot=True) LOG.info('Initialized iSCSI Connection snapshot(%s)', msgparm) return ret except exception.CinderException as e: @@ -1217,7 +1084,7 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): '(%(msgparm)s) (%(exception)s)', {'msgparm': msgparm, 'exception': e}) - def _fc_initialize_connection(self, volume, connector): + def _fc_initialize_connection(self, volume, connector, is_snapshot=False): """Initializes the connection and returns connection info. The driver returns a driver_volume_type of 'fibre_channel'. @@ -1249,15 +1116,27 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): """ LOG.debug('_fc_initialize_connection' - '(Volume ID = %(id)s, connector = %(connector)s) Start.', - {'id': volume.id, 'connector': connector}) + '(Volume ID = %(id)s, connector = %(connector)s, ' + 'snapshot = %(snapshot)s) Start.', + {'id': volume.id, 'connector': connector, + 'snapshot': is_snapshot}) + if is_snapshot: + ldname = self._create_snapshot_and_link( + volume, connector, + self._properties['diskarray_name'], + self._validate_fcldset_exist) + else: + ldname = self._export_volume(volume, connector, + self._properties['diskarray_name'], + self._validate_fcldset_exist) + + # update local info. xml = self._cli.view_all(self._properties['ismview_path']) pools, lds, ldsets, used_ldns, hostports, max_ld_count = ( self.configs(xml)) # get target wwpns and initiator/target map. - fc_ports = [] for director, hostport in hostports.items(): for port in hostport: @@ -1266,16 +1145,9 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): target_wwns, init_targ_map = ( self._build_initiator_target_map(connector, fc_ports)) + # get link volume number ldname = self.get_ldname( volume.id, self._properties['ld_name_format']) - - # get lun. - if ldname not in lds: - msg = (_('Logical Disk %(ld)s has unbound already. ' - 'volume_id = %(id)s.') % - {'ld': ldname, 'id': volume.id}) - LOG.error(msg) - raise exception.NotFound(msg) lvname = ldname + '_l' if lvname in lds: ldn = lds[lvname]['ldn'] @@ -1307,7 +1179,8 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): % {'id': snapshot.id, 'connector': connector}) try: - ret = self._fc_initialize_connection(snapshot, connector) + ret = self._fc_initialize_connection(snapshot, connector, + is_snapshot=True) LOG.info('Initialized FC Connection snapshot(%s)', msgparm) return ret except exception.CinderException as e: @@ -1451,7 +1324,8 @@ class MStorageDriver(volume_common.MStorageVolumeCommon): data['multiattach'] = True data['location_info'] = (self._properties['cli_fip'] + ":" + (','.join(map(str, - self._properties['pool_pools'])))) + self._properties['pool_pools'] + )))) # Get xml data from file and parse. try: diff --git a/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst b/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst index ed8bbdd2b1b..3504a675ddd 100644 --- a/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst +++ b/doc/source/configuration/block-storage/drivers/nec-storage-m-series-driver.rst @@ -86,8 +86,6 @@ For details of each command, see the NEC Storage Manager Command Reference #. Set IP addresses of each iSCSI port. (iSMcfg setiscsiport) #. Create LD Sets for each node. (iSMcfg addldset) - #. Delete some iSCSI portal settings of each LD Sets to set to - ``nec_iscsi_portals_per_cont`` parameter. (iSMcfg delldsetportal) #. Register initiator names of each node to the corresponding LD Set. (iSMcfg addldsetinitiator) diff --git a/releasenotes/notes/nec-allow-more-than-4iSCSI-portals-8342defe64491f81.yaml b/releasenotes/notes/nec-allow-more-than-4iSCSI-portals-8342defe64491f81.yaml new file mode 100644 index 00000000000..a9458b18773 --- /dev/null +++ b/releasenotes/notes/nec-allow-more-than-4iSCSI-portals-8342defe64491f81.yaml @@ -0,0 +1,11 @@ +--- +upgrade: + - | + NEC Driver: Added support of more than 4 iSCSI portals + for a node. +deprecations: + - | + NEC Driver: Deprecated ``nec_iscsi_portals_per_cont`` + config option. The option was used to limit number of + portals and is no longer needed. +