NEC driver: add automatic configuration of SAN access control.
NEC driver user has to register WWPNs or an initiator name of every node to storage. This is inconvenient for the user. This patch enables NEC driver to configure SAN access control automatically. Change-Id: I92b42600b71fbdfe1b84046c59ab485f333be889 Closes-Bug: #1737452
This commit is contained in:
parent
3b86eb7a82
commit
d4dd162bcd
@ -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"}
|
||||
|
@ -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):
|
||||
|
||||
|
@ -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):
|
||||
|
@ -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:
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
upgrade:
|
||||
Added automatic configuration of SAN access control for the NEC
|
||||
volume driver.
|
Loading…
Reference in New Issue
Block a user