Merge "NEC driver: add automatic configuration of SAN access control."

This commit is contained in:
Zuul 2017-12-29 00:21:52 +00:00 committed by Gerrit Code Review
commit 31f6aff00f
5 changed files with 152 additions and 16 deletions

View File

@ -1048,25 +1048,54 @@ class NonDisruptiveBackup_test(volume_helper.MStorageDSVDriver,
self._validate_ld_exist(
self.lds, self.vol.id, self._properties['ld_name_format'])
@mock.patch('cinder.volume.drivers.nec.cli.MStorageISMCLI._execute',
patch_execute)
@mock.patch('cinder.volume.drivers.nec.cli.MStorageISMCLI.'
'view_all', new=mock.Mock())
def test_validate_iscsildset_exist(self):
connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"}
ldset = self._validate_iscsildset_exist(self.ldsets, connector)
self.assertEqual('LX:OpenStack0', ldset['ldsetname'])
connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255XX"}
with self.assertRaisesRegexp(exception.NotFound,
'Appropriate Logical Disk Set'
' could not be found.'):
self._validate_iscsildset_exist(self.ldsets, connector)
connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f232XX"}
mock_data = {'ldsetname': 'LX:redhatd1d8e8f23',
'protocol': 'iSCSI',
'portal_list': ['1.1.1.1:3260', '2.2.2.2:3260'],
'lds': {},
'initiator_list':
['iqn.1994-05.com.redhat:d1d8e8f232XX']}
mock_ldset = {}
mock_ldset['LX:redhatd1d8e8f23'] = mock_data
mock_configs = mock.Mock()
self.configs = mock_configs
self.configs.return_value = None, None, mock_ldset, None, None, None
ldset = self._validate_iscsildset_exist(self.ldsets, connector)
self.assertEqual('LX:redhatd1d8e8f23', ldset['ldsetname'])
self.assertEqual('iqn.1994-05.com.redhat:d1d8e8f232XX',
ldset['initiator_list'][0])
@mock.patch('cinder.volume.drivers.nec.cli.MStorageISMCLI._execute',
patch_execute)
@mock.patch('cinder.volume.drivers.nec.cli.MStorageISMCLI.'
'view_all', new=mock.Mock())
def test_validate_fcldset_exist(self):
connector = {'wwpns': ["10000090FAA0786A", "10000090FAA0786B"]}
ldset = self._validate_fcldset_exist(self.ldsets, connector)
self.assertEqual('LX:OpenStack1', ldset['ldsetname'])
connector = {'wwpns': ["10000090FAA0786X", "10000090FAA0786Y"]}
with self.assertRaisesRegexp(exception.NotFound,
'Appropriate Logical Disk Set'
' could not be found.'):
self._validate_fcldset_exist(self.ldsets, connector)
mock_data = {'ldsetname': 'LX:10000090FAA0786X',
'lds': {},
'protocol': 'FC',
'wwpn': ["1000-0090-FAA0-786X", "1000-0090-FAA0-786Y"],
'port': []}
mock_ldset = {}
mock_ldset['LX:10000090FAA0786X'] = mock_data
mock_configs = mock.Mock()
self.configs = mock_configs
self.configs.return_value = None, None, mock_ldset, None, None, None
ldset = self._validate_fcldset_exist(self.ldsets, connector)
self.assertEqual('LX:10000090FAA0786X', ldset['ldsetname'])
self.assertEqual('1000-0090-FAA0-786X', ldset['wwpn'][0])
self.assertEqual('1000-0090-FAA0-786Y', ldset['wwpn'][1])
def test_enumerate_iscsi_portals(self):
connector = {'initiator': "iqn.1994-05.com.redhat:d1d8e8f23255"}

View File

@ -31,7 +31,7 @@ from cinder import ssh_utils
LOG = logging.getLogger(__name__)
retry_msgids = ['iSM31005', 'iSM31015', 'iSM42408', 'iSM42412']
retry_msgids = ['iSM31005', 'iSM31015', 'iSM42408', 'iSM42412', 'iSM19411']
class MStorageISMCLI(object):
@ -227,6 +227,41 @@ class MStorageISMCLI(object):
% {'ldn': ldn, 'capacity': capacity})
self._execute(cmd)
def addldset_fc(self, ldsetname, connector):
"""Create new FC LD Set."""
cmd = 'iSMcfg addldset -ldset LX:%s -type fc' % ldsetname
out, err, status = self._execute(cmd, [0], False)
if status != 0:
return False
for wwpn in connector['wwpns']:
length = len(wwpn)
setwwpn = '-'.join([wwpn[i:i + 4]
for i in range(0, length, 4)])
setwwpn = setwwpn.upper()
cmd = ('iSMcfg addldsetpath -ldset LX:%(name)s -path %(path)s'
% {'name': ldsetname, 'path': setwwpn})
out, err, status = self._execute(cmd, [0], False)
if status != 0:
return False
return True
def addldset_iscsi(self, ldsetname, connector):
"""Create new iSCSI LD Set."""
cmd = ('iSMcfg addldset -ldset LX:%s -multitarget on'
' -type iscsi' % ldsetname)
out, err, status = self._execute(cmd, [0], False)
if status != 0:
return False
cmd = ('iSMcfg addldsetinitiator'
' -ldset LX:%(name)s -initiatorname %(initiator)s'
% {'name': ldsetname, 'initiator': connector['initiator']})
out, err, status = self._execute(cmd, [0], False)
if status != 0:
return False
return True
def addldsetld(self, ldset, ldname, lun=None):
"""Add an LD to specified LD Set."""
if lun is None:
@ -611,6 +646,14 @@ class MStorageISMCLI(object):
% {'lvname': lvname})
self._execute(cmd)
def cvbind(self, poolnumber, cvnumber):
"""Create Control Volume."""
cmd = ('iSMcfg ldbind -poolnumber %(poolnumber)d '
'-ldattr cv -ldn %(cvnumber)d'
% {'poolnumber': poolnumber,
'cvnumber': cvnumber})
self._execute(cmd)
class UnpairWait(object):

View File

@ -96,6 +96,12 @@ mstorage_opts = [
cfg.IntOpt('nec_iscsi_portals_per_cont',
default=1,
help='Number of iSCSI portals.'),
cfg.BoolOpt('nec_auto_accesscontrol',
default=True,
help='Configure access control automatically.'),
cfg.StrOpt('nec_cv_ldname_format',
default='LX:__ControlVolume_%xh',
help='M-Series Storage Control Volume name format.'),
]
FLAGS.register_opts(mstorage_opts, group=configuration.SHARED_CONF_GROUP)
@ -147,7 +153,7 @@ def convert_to_id(value62):
class MStorageVolumeCommon(object):
"""M-Series Storage volume common class."""
VERSION = '1.9.2'
VERSION = '1.10.1'
WIKI_NAME = 'NEC_Cinder_CI'
def do_setup(self, context):
@ -250,7 +256,9 @@ class MStorageVolumeCommon(object):
confobj.safe_get('nec_ssh_pool_port_number'),
'diskarray_name': confobj.safe_get('nec_diskarray_name'),
'queryconfig_view': confobj.safe_get('nec_queryconfig_view'),
'portal_number': confobj.safe_get('nec_iscsi_portals_per_cont')
'portal_number': confobj.safe_get('nec_iscsi_portals_per_cont'),
'auto_accesscontrol': confobj.safe_get('nec_auto_accesscontrol'),
'cv_name_format': confobj.safe_get('nec_cv_ldname_format')
}
def _set_properties(self):

View File

@ -217,8 +217,24 @@ class MStorageDriver(volume_common.MStorageVolumeCommon):
ldset = tldset
break
if ldset is None:
msg = _('Appropriate Logical Disk Set could not be found.')
raise exception.NotFound(msg)
if self._properties['auto_accesscontrol']:
authname = connector['initiator'].strip()
authname = authname.replace((":"), "")
authname = authname.replace(("."), "")
new_ldsetname = authname[-16:]
ret = self._cli.addldset_iscsi(new_ldsetname, connector)
if ret is False:
msg = _('Appropriate Logical Disk Set'
' could not be found.')
raise exception.NotFound(msg)
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)
else:
msg = _('Appropriate Logical Disk Set could not be found.')
raise exception.NotFound(msg)
if len(ldset['portal_list']) < 1:
msg = (_('Logical Disk Set `%s` has no portal.') %
ldset['ldsetname'])
@ -240,8 +256,21 @@ class MStorageDriver(volume_common.MStorageVolumeCommon):
if ldset is not None:
break
if ldset is None:
msg = _('Appropriate Logical Disk Set could not be found.')
raise exception.NotFound(msg)
if self._properties['auto_accesscontrol']:
new_ldsetname = connector['wwpns'][0][:16]
ret = self._cli.addldset_fc(new_ldsetname, connector)
if ret is False:
msg = _('Appropriate Logical Disk Set'
' could not be found.')
raise exception.NotFound(msg)
xml = self._cli.view_all(self._properties['ismview_path'])
pools, lds, ldsets, used_ldns, hostports, max_ld_count = (
self.configs(xml))
ldset = self._validate_fcldset_exist(ldsets, connector)
else:
msg = _('Appropriate Logical Disk Set could not be found.')
raise exception.NotFound(msg)
return ldset
def _enumerate_iscsi_portals(self, hostports, ldset, prefered_director=0):
@ -819,6 +848,16 @@ class MStorageDriver(volume_common.MStorageVolumeCommon):
lvldn = self._select_ldnumber(used_ldns, max_ld_count)
LOG.debug('configure backend.')
if not ldset['lds']:
LOG.debug('create and attach control volume.')
used_ldns.append(lvldn)
cvldn = self._select_ldnumber(used_ldns, max_ld_count)
self._cli.cvbind(lds[bvname]['pool_num'], cvldn)
self._cli.changeldname(cvldn,
self._properties['cv_name_format'] % cvldn)
self._cli.addldsetld(ldset['ldsetname'],
self._properties['cv_name_format'] % cvldn)
self._cli.lvbind(bvname, lvname[3:], lvldn)
self._cli.lvlink(svname[3:], lvname[3:])
self._cli.addldsetld(ldset['ldsetname'], lvname)
@ -882,6 +921,17 @@ class MStorageDriver(volume_common.MStorageVolumeCommon):
lvldn = self._select_ldnumber(used_ldns, max_ld_count)
LOG.debug('configure backend.')
lun0 = [ld for (ldn, ld) in ldset['lds'].items() if ld['lun'] == 0]
if not lun0:
LOG.debug('create and attach control volume.')
used_ldns.append(lvldn)
cvldn = self._select_ldnumber(used_ldns, max_ld_count)
self._cli.cvbind(lds[bvname]['pool_num'], cvldn)
self._cli.changeldname(cvldn,
self._properties['cv_name_format'] % cvldn)
self._cli.addldsetld(ldset['ldsetname'],
self._properties['cv_name_format'] % cvldn, 0)
self._cli.lvbind(bvname, lvname[3:], lvldn)
self._cli.lvlink(svname[3:], lvname[3:])
@ -889,6 +939,8 @@ class MStorageDriver(volume_common.MStorageVolumeCommon):
ldsetlds = ldset['lds']
for ld in ldsetlds.values():
luns.append(ld['lun'])
if 0 not in luns:
luns.append(0)
target_lun = 0
for lun in sorted(luns):
if target_lun < lun:

View File

@ -0,0 +1,4 @@
---
upgrade:
Added automatic configuration of SAN access control for the NEC
volume driver.