Merge "NEC Driver: allow more than 4 iSCSI portals"

This commit is contained in:
Zuul 2019-09-19 18:35:13 +00:00 committed by Gerrit Code Review
commit 551f2ecb57
7 changed files with 298 additions and 417 deletions

View File

@ -343,6 +343,11 @@ xml_out = '''
<UNIT name="LUN(h)">0000</UNIT>
<UNIT name="LDN(h)">0000</UNIT>
</SECTION>
<SECTION name="Target Information For Multi-Target Mode">
<UNIT name="Target Name">iqn.2001-03.target0001</UNIT>
<UNIT name="LUN(h)">0001</UNIT>
<UNIT name="LDN(h)">0006</UNIT>
</SECTION>
</OBJECT>
</CHAPTER>
<RETURN_MSG>Command Completed Successfully!!</RETURN_MSG>
@ -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)

View File

@ -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):

View File

@ -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,

View File

@ -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

View File

@ -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:

View File

@ -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)

View File

@ -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.