Implement match-set type 3PAR FC VLUN creation

Creating match-set type FC VLUN, instead of host sees type.
Passing node-slot-port details while creating a VLUN.
This patch fixes dangling lun entry left when both ISCSI and FC
attaches are made on the same compute host, after removing all
attachments. Updated version number to 3.0.8.
Updated broken unit test cases.
Adding release note.

Closes-Bug: #1577993
Change-Id: I927638584093130b0e94c9cdd8074b3617baa366
This commit is contained in:
Jay Mehta 2016-04-21 16:01:07 -07:00
parent 42db20e90a
commit 0912153358
3 changed files with 129 additions and 27 deletions

View File

@ -121,11 +121,13 @@ class HPE3PARBaseDriver(object):
VOLUME_ID_SNAP = '761fc5e5-5191-4ec7-aeba-33e36de44156'
FAKE_DESC = 'test description name'
FAKE_FC_PORTS = [{'portPos': {'node': 7, 'slot': 1, 'cardPort': 1},
'type': 1,
'portWWN': '0987654321234',
'protocol': 1,
'mode': 2,
'linkState': 4},
{'portPos': {'node': 6, 'slot': 1, 'cardPort': 1},
'type': 1,
'portWWN': '123456789000987',
'protocol': 1,
'mode': 2,
@ -334,6 +336,7 @@ class HPE3PARBaseDriver(object):
'PORT_STATE_READY': 4,
'PORT_PROTO_ISCSI': 2,
'PORT_PROTO_FC': 1,
'PORT_TYPE_HOST': 1,
'TASK_DONE': TASK_DONE,
'TASK_ACTIVE': TASK_ACTIVE,
'HOST_EDIT_ADD': 1,
@ -4487,16 +4490,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 1,
'slot': 2},
'portPos': {'cardPort': 1, 'node': 7,
'slot': 1},
'vendor': None,
'wwn': self.wwn[0]},
{'driverVersion': None,
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 0,
'slot': 2},
'portPos': {'cardPort': 1, 'node': 6,
'slot': 1},
'vendor': None,
'wwn': self.wwn[1]}]}]
mock_client.queryHost.return_value = {
@ -4509,6 +4512,13 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
hpeexceptions.HTTPNotFound('fake'),
[{'active': True,
'volumeName': self.VOLUME_3PAR_NAME,
'portPos': {'node': 7, 'slot': 1, 'cardPort': 1},
'remoteName': self.wwn[1],
'lun': 90, 'type': 0}],
[{'active': True,
'volumeName': self.VOLUME_3PAR_NAME,
'portPos': {'node': 6, 'slot': 1, 'cardPort': 1},
'remoteName': self.wwn[0],
'lun': 90, 'type': 0}]]
location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" %
@ -4517,6 +4527,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
'host': self.FAKE_HOST,
'nsp': 'something'})
mock_client.createVLUN.return_value = location
expected_properties = {
'driver_volume_type': 'fibre_channel',
'data': {
'encrypted': False,
'target_lun': 90,
'target_wwn': ['0987654321234', '123456789000987'],
'target_discovered': True,
'initiator_target_map':
{'123456789012345': ['123456789000987'],
'123456789054321': ['0987654321234']}}}
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
@ -4534,11 +4554,20 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
mock.call.getHost(self.FAKE_HOST),
mock.call.getPorts(),
mock.call.getHostVLUNs(self.FAKE_HOST),
mock.call.getPorts(),
mock.call.createVLUN(
self.VOLUME_3PAR_NAME,
auto=True,
hostname=self.FAKE_HOST,
lun=None),
lun=None,
portPos={'node': 7, 'slot': 1, 'cardPort': 1}),
mock.call.getHostVLUNs(self.FAKE_HOST),
mock.call.createVLUN(
self.VOLUME_3PAR_NAME,
auto=False,
hostname=self.FAKE_HOST,
lun=90,
portPos={'node': 6, 'slot': 1, 'cardPort': 1}),
mock.call.getHostVLUNs(self.FAKE_HOST)]
mock_client.assert_has_calls(
@ -4546,7 +4575,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
expected +
self.standard_logout)
self.assertDictMatch(self.properties, result)
self.assertDictMatch(expected_properties, result)
@mock.patch('cinder.zonemanager.utils.create_lookup_service')
def test_initialize_connection_with_lookup_single_nsp(self, mock_lookup):
@ -4587,7 +4616,7 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
[{'active': True,
'volumeName': self.VOLUME_3PAR_NAME,
'lun': 90, 'type': 0,
'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}, }]]
'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}}]]
location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" %
{'volume_name': self.VOLUME_3PAR_NAME,
@ -4655,16 +4684,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 1,
'slot': 2},
'portPos': {'cardPort': 1, 'node': 7,
'slot': 1},
'vendor': None,
'wwn': self.wwn[0]},
{'driverVersion': None,
'firmwareVersion': None,
'hostSpeed': 0,
'model': None,
'portPos': {'cardPort': 1, 'node': 0,
'slot': 2},
'portPos': {'cardPort': 1, 'node': 6,
'slot': 1},
'vendor': None,
'wwn': self.wwn[1]}]}]
mock_client.queryHost.return_value = {
@ -4677,6 +4706,13 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
hpeexceptions.HTTPNotFound('fake'),
[{'active': True,
'volumeName': self.VOLUME_3PAR_NAME,
'lun': 90, 'type': 0,
'remoteName': self.wwn[1],
'portPos': {'cardPort': 1, 'node': 7, 'slot': 1}}],
[{'active': True,
'volumeName': self.VOLUME_3PAR_NAME,
'portPos': {'node': 6, 'slot': 1, 'cardPort': 1},
'remoteName': self.wwn[0],
'lun': 90, 'type': 0}]]
location = ("%(volume_name)s,%(lun_id)s,%(host)s,%(nsp)s" %
@ -4685,6 +4721,16 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
'host': self.FAKE_HOST,
'nsp': 'something'})
mock_client.createVLUN.return_value = location
expected_properties = {
'driver_volume_type': 'fibre_channel',
'data': {
'encrypted': True,
'target_lun': 90,
'target_wwn': ['0987654321234', '123456789000987'],
'target_discovered': True,
'initiator_target_map':
{'123456789012345': ['123456789000987'],
'123456789054321': ['0987654321234']}}}
with mock.patch.object(hpecommon.HPE3PARCommon,
'_create_client') as mock_create_client:
@ -4702,11 +4748,20 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
mock.call.getHost(self.FAKE_HOST),
mock.call.getPorts(),
mock.call.getHostVLUNs(self.FAKE_HOST),
mock.call.getPorts(),
mock.call.createVLUN(
self.VOLUME_3PAR_NAME,
auto=True,
hostname=self.FAKE_HOST,
lun=None),
lun=None,
portPos={'node': 7, 'slot': 1, 'cardPort': 1}),
mock.call.getHostVLUNs(self.FAKE_HOST),
mock.call.createVLUN(
self.VOLUME_3PAR_NAME,
auto=False,
hostname=self.FAKE_HOST,
lun=90,
portPos={'node': 6, 'slot': 1, 'cardPort': 1}),
mock.call.getHostVLUNs(self.FAKE_HOST)]
mock_client.assert_has_calls(
@ -4714,8 +4769,6 @@ class TestHPE3PARFCDriver(HPE3PARBaseDriver, test.TestCase):
expected +
self.standard_logout)
expected_properties = self.properties
expected_properties['data']['encrypted'] = True
self.assertDictMatch(expected_properties, result)
def test_terminate_connection(self):

View File

@ -101,10 +101,12 @@ class HPE3PARFCDriver(driver.TransferVD,
3.0.5 - Optimize array ID retrieval
3.0.6 - Update replication to version 2.1
3.0.7 - Remove metadata that tracks the instance ID. bug #1572665
3.0.8 - NSP feature, creating FC Vlun as match set instead of
host sees. bug #1577993
"""
VERSION = "3.0.7"
VERSION = "3.0.8"
def __init__(self, *args, **kwargs):
super(HPE3PARFCDriver, self).__init__(*args, **kwargs)
@ -265,26 +267,69 @@ class HPE3PARFCDriver(driver.TransferVD,
try:
# we have to make sure we have a host
host = self._create_host(common, volume, connector)
target_wwns, init_targ_map, numPaths = \
self._build_initiator_target_map(common, connector)
# check if a VLUN already exists for this host
existing_vlun = common.find_existing_vlun(volume, host)
vlun = None
if existing_vlun is None:
# now that we have a host, create the VLUN
if self.lookup_service is not None and numPaths == 1:
nsp = None
active_fc_port_list = common.get_active_fc_target_ports()
for port in active_fc_port_list:
if port['portWWN'].lower() == target_wwns[0].lower():
nsp = port['nsp']
break
vlun = common.create_vlun(volume, host, nsp)
nsp = None
lun_id = None
active_fc_port_list = common.get_active_fc_target_ports()
if self.lookup_service:
if not init_targ_map:
msg = _("Setup is incomplete. Device mapping "
"not found from FC network. "
"Cannot perform VLUN creation.")
LOG.error(msg)
raise exception.FCSanLookupServiceException(msg)
for target_wwn in target_wwns:
for port in active_fc_port_list:
if port['portWWN'].lower() == target_wwn.lower():
nsp = port['nsp']
vlun = common.create_vlun(volume,
host,
nsp,
lun_id=lun_id)
if lun_id is None:
lun_id = vlun['lun']
break
else:
vlun = common.create_vlun(volume, host)
init_targ_map.clear()
del target_wwns[:]
host_connected_nsp = []
for fcpath in host['FCPaths']:
if 'portPos' in fcpath:
host_connected_nsp.append(
common.build_nsp(fcpath['portPos']))
for port in active_fc_port_list:
if (
port['type'] == common.client.PORT_TYPE_HOST and
port['nsp'] in host_connected_nsp
):
nsp = port['nsp']
vlun = common.create_vlun(volume,
host,
nsp,
lun_id=lun_id)
target_wwns.append(port['portWWN'])
if vlun['remoteName'] in init_targ_map:
init_targ_map[vlun['remoteName']].append(
port['portWWN'])
else:
init_targ_map[vlun['remoteName']] = [
port['portWWN']]
if lun_id is None:
lun_id = vlun['lun']
if lun_id is None:
# New vlun creation failed
msg = _('No new vlun(s) were created')
LOG.error(msg)
raise exception.VolumeDriverException(msg)
else:
vlun = existing_vlun
@ -296,7 +341,6 @@ class HPE3PARFCDriver(driver.TransferVD,
encryption_key_id = volume.get('encryption_key_id', None)
info['data']['encrypted'] = encryption_key_id is not None
return info
finally:
self._logout(common)

View File

@ -0,0 +1,5 @@
---
fixes:
- 3PAR driver creates FC VLUN of match-set type instead of host sees.
With match-set, the host will see the virtual volume on specified
NSP (Node-Slot-Port). This change in vlun type fixes bug 1577993.