Merge "NEC driver: add automatic configuration of SAN access control."
This commit is contained in:
commit
31f6aff00f
cinder
releasenotes/notes
@ -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…
x
Reference in New Issue
Block a user