"SP: A\n" +
"Port ID: 5\n" +
"Port WWN: iqn.1992-04.com.emc:cx.fnm00124000215.a5\n" +
- "iSCSI Alias: 0215.a5\n", 0)
+ "iSCSI Alias: 0215.a5\n" +
+ "SP: A\n" +
+ "Port ID: 0\n" +
+ "Port WWN: iqn.1992-04.com.emc:cx.fnm00124000215.a0\n" +
+ "iSCSI Alias: 0215.a0\n\n" +
+ "Virtual Port ID: 0\n" +
+ "VLAN ID: Disabled\n" +
+ "IP Address: 10.244.214.119\n\n" +
+ "SP: B\n" +
+ "Port ID: 2\n" +
+ "Port WWN: iqn.1992-04.com.emc:cx.fnm00124000215.b2\n" +
+ "iSCSI Alias: 0215.b2\n\n" +
+ "Virtual Port ID: 0\n" +
+ "VLAN ID: Disabled\n" +
+ "IP Address: 10.244.214.120\n\n", 0)
+
+ WHITE_LIST_PORTS = ("""SP: A
+Port ID: 0
+Port WWN: iqn.1992-04.com.emc:cx.fnmxxx.a0
+iSCSI Alias: 0235.a7
+
+Virtual Port ID: 0
+VLAN ID: Disabled
+IP Address: 192.168.3.52
+
+SP: A
+Port ID: 9
+Port WWN: iqn.1992-04.com.emc:cx.fnmxxx.a9
+iSCSI Alias: 0235.a9
+
+SP: A
+Port ID: 4
+Port WWN: iqn.1992-04.com.emc:cx.fnmxxx.a4
+iSCSI Alias: 0235.a4
+
+SP: B
+Port ID: 2
+Port WWN: iqn.1992-04.com.emc:cx.fnmxxx.b2
+iSCSI Alias: 0235.b6
+
+Virtual Port ID: 0
+VLAN ID: Disabled
+IP Address: 192.168.4.53
+""", 0)
iscsi_connection_info = \
{'data': {'target_discovered': True,
"50:06:01:62:08:60:01:95\n" +
"Link Status: Down\n" +
"Port Status: Online\n" +
- "Switch Present: NO\n", 0)
+ "Switch Present: NO\n" +
+ "\n" +
+ "SP Name: SP B\n" +
+ "SP Port ID: 2\n" +
+ "SP UID: 50:06:01:60:88:60:08:0F:"
+ "50:06:01:6A:08:60:08:0F\n" +
+ "Link Status: Up\n" +
+ "Port Status: Online\n" +
+ "Switch Present: YES\n" +
+ "Switch UID: 10:00:50:EB:1A:03:3F:59:"
+ "20:11:50:EB:1A:03:3F:59\n" +
+ "SP Source ID: 69888\n", 0)
FAKEHOST_PORTS = (
"Information about each HBA:\n" +
" Defined: YES\n" +
" Initiator Type: 3\n" +
" StorageGroup Name: fakehost\n\n" +
+ " SP Name: SP B\n" +
+ " SP Port ID: 2\n" +
+ " HBA Devicename:\n" +
+ " Trusted: NO\n" +
+ " Logged In: YES\n" +
+ " Defined: YES\n" +
+ " Initiator Type: 3\n" +
+ " StorageGroup Name: fakehost\n\n"
"Information about each SPPORT:\n" +
"\n" +
"SP Name: SP A\n" +
"50:06:01:62:08:60:01:95\n" +
"Link Status: Down\n" +
"Port Status: Online\n" +
- "Switch Present: NO\n", 0)
+ "Switch Present: NO\n" +
+ "\n" +
+ "SP Name: SP B\n" +
+ "SP Port ID: 2\n" +
+ "SP UID: 50:06:01:60:88:60:01:95:" +
+ "50:06:01:6A:08:60:08:0F\n" +
+ "Link Status: Up\n" +
+ "Port Status: Online\n" +
+ "Switch Present: YES\n" +
+ "Switch UID: 10:00:00:05:1E:72:EC:A6:" +
+ "20:46:00:05:1E:72:EC:A6\n" +
+ "SP Source ID: 272896\n", 0)
def LUN_PROPERTY(self, name, is_thin=False, has_snap=False, size=1,
state='Ready', faulted='false', operation='None',
'operation': operation,
'is_thin': 'Yes' if is_thin else 'No'}, 0)
+ def STORAGE_GROUP_ISCSI_FC_HBA(self, sgname):
+
+ return ("""\
+ Storage Group Name: %s
+ Storage Group UID: 54:46:57:0F:15:A2:E3:11:9A:8D:FF:E5:3A:03:FD:6D
+ HBA/SP Pairs:
+
+ HBA UID SP Name SPPort
+ ------- ------- ------
+ iqn.1993-08.org.debian:01:222 SP A 4
+ 22:34:56:78:90:12:34:56:12:34:56:78:90:12:34:56 SP B 2
+ 22:34:56:78:90:54:32:16:12:34:56:78:90:54:32:16 SP B 2
+
+ HLU/ALU Pairs:
+
+ HLU Number ALU Number
+ ---------- ----------
+ 1 1
+ Shareable: YES""" % sgname, 0)
+
def STORAGE_GROUP_NO_MAP(self, sgname):
return ("""\
Storage Group Name: %s
1 1
Shareable: YES""" % sgname, 0)
+ def STORAGE_GROUP_HAS_MAP_ISCSI(self, sgname):
+
+ return ("""\
+ Storage Group Name: %s
+ Storage Group UID: 54:46:57:0F:15:A2:E3:11:9A:8D:FF:E5:3A:03:FD:6D
+ HBA/SP Pairs:
+
+ HBA UID SP Name SPPort
+ ------- ------- ------
+ iqn.1993-08.org.debian:01:222 SP A 2
+ iqn.1993-08.org.debian:01:222 SP A 0
+ iqn.1993-08.org.debian:01:222 SP B 2
+
+ HLU/ALU Pairs:
+
+ HLU Number ALU Number
+ ---------- ----------
+ 1 1
+ Shareable: YES""" % sgname, 0)
+
def STORAGE_GROUP_HAS_MAP_MP(self, sgname):
return ("""\
return standard_default
def fake_command_execute_for_driver_setup(self, *command, **kwargv):
- if command == ('connection', '-getport', '-address', '-vlanid'):
+ if (command == ('connection', '-getport', '-address', '-vlanid') or
+ command == ('connection', '-getport', '-vlanid')):
return self.testData.ALL_PORTS
elif command == ('storagepool', '-list', '-state'):
return self.testData.POOL_GET_STATE_RESULT([
{'pool_name': self.testData.test_pool_name, 'state': "Ready"},
{'pool_name': "unit_test_pool2", 'state': "Ready"}])
+ if command == self.testData.GETFCPORT_CMD():
+ return self.testData.FC_PORTS
else:
return SUCCEED
'-hbauid', 'iqn.1993-08.org.debian:01:222',
'-sp', 'A', '-spport', 4, '-spvport', 0,
'-ip', '10.0.0.2', '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost', '-setpath',
+ '-hbauid', 'iqn.1993-08.org.debian:01:222',
+ '-sp', 'A', '-spport', 0, '-spvport', 0,
+ '-ip', '10.0.0.2', '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost', '-setpath',
+ '-hbauid', 'iqn.1993-08.org.debian:01:222',
+ '-sp', 'B', '-spport', 2, '-spvport', 0,
+ '-ip', '10.0.0.2', '-host', 'fakehost', '-o'),
mock.call('storagegroup', '-list', '-gname', 'fakehost',
poll=True),
mock.call('storagegroup', '-addhlu', '-hlu', 2, '-alu', 1,
'10.0.0.2'))]
fake_cli.assert_has_calls(expected)
+ @mock.patch('random.randint',
+ mock.Mock(return_value=0))
+ def test_initialize_connection_iscsi_white_list(self):
+ self.configuration.io_port_list = 'a-0-0,B-2-0'
+ test_volume = self.testData.test_volume.copy()
+ test_volume['provider_location'] = 'system^fakesn|type^lun|id^1'
+ # Test for auto registration
+ self.configuration.initiator_auto_registration = True
+ commands = [('storagegroup', '-list', '-gname', 'fakehost')]
+ results = [[("No group", 83),
+ self.testData.STORAGE_GROUP_HAS_MAP_ISCSI('fakehost')]]
+ fake_cli = self.driverSetup(commands, results)
+ self.driver.cli.iscsi_targets = {'A': [{'SP': 'A', 'Port ID': 0,
+ 'Virtual Port ID': 0,
+ 'Port WWN': 'fake_iqn',
+ 'IP Address': '192.168.1.1'}],
+ 'B': [{'SP': 'B', 'Port ID': 2,
+ 'Virtual Port ID': 0,
+ 'Port WWN': 'fake_iqn1',
+ 'IP Address': '192.168.1.2'}]}
+ self.driver.initialize_connection(
+ test_volume,
+ self.testData.connector)
+ expected = [mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=False),
+ mock.call('storagegroup', '-create', '-gname', 'fakehost'),
+ mock.call('storagegroup', '-gname', 'fakehost', '-setpath',
+ '-hbauid', 'iqn.1993-08.org.debian:01:222',
+ '-sp', 'A', '-spport', 0, '-spvport', 0,
+ '-ip', '10.0.0.2', '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost', '-setpath',
+ '-hbauid', 'iqn.1993-08.org.debian:01:222',
+ '-sp', 'B', '-spport', 2, '-spvport', 0,
+ '-ip', '10.0.0.2', '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=True),
+ mock.call('storagegroup', '-addhlu', '-hlu', 2, '-alu', 1,
+ '-gname', 'fakehost', '-o',
+ poll=False),
+ mock.call(*self.testData.LUN_PROPERTY_ALL_CMD('vol1'),
+ poll=False)]
+ fake_cli.assert_has_calls(expected)
+
+ @mock.patch('cinder.volume.drivers.emc.emc_vnx_cli.'
+ 'EMCVnxCliBase._build_pool_stats',
+ mock.Mock(return_value=None))
+ @mock.patch('cinder.volume.drivers.emc.emc_vnx_cli.'
+ 'CommandLineHelper.get_pool',
+ mock.Mock(return_value={'total_capacity_gb': 0.0,
+ 'free_capacity_gb': 0.0}))
+ def test_update_iscsi_io_ports(self):
+ self.configuration.io_port_list = 'a-0-0,B-2-0'
+ # Test for auto registration
+ self.configuration.initiator_auto_registration = True
+ commands = [self.testData.GETPORT_CMD()]
+ results = [self.testData.WHITE_LIST_PORTS]
+ fake_cli = self.driverSetup(commands, results)
+ self.driver.cli.update_volume_stats()
+ expected = [mock.call(*self.testData.GETPORT_CMD(), poll=False)]
+ fake_cli.assert_has_calls(expected)
+ io_ports = self.driver.cli.iscsi_targets
+ self.assertEqual((0, 'iqn.1992-04.com.emc:cx.fnmxxx.a0'),
+ (io_ports['A'][0]['Port ID'],
+ io_ports['A'][0]['Port WWN']))
+ self.assertEqual((2, 'iqn.1992-04.com.emc:cx.fnmxxx.b2'),
+ (io_ports['B'][0]['Port ID'],
+ io_ports['B'][0]['Port WWN']))
+
@mock.patch(
"oslo_concurrency.processutils.execute",
mock.Mock(
'90:12:34:56',
'-sp', 'A', '-spport', '0', '-ip', '10.0.0.2',
'-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:12:34:56:12:34:56:78:'
+ '90:12:34:56',
+ '-sp', 'B', '-spport', '2', '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
mock.call('storagegroup', '-gname', 'fakehost',
'-setpath', '-hbauid',
'22:34:56:78:90:54:32:16:12:34:56:78:'
'90:54:32:16',
'-sp', 'A', '-spport', '0', '-ip', '10.0.0.2',
'-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:54:32:16:12:34:56:78:'
+ '90:54:32:16',
+ '-sp', 'B', '-spport', '2', '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
mock.call('storagegroup', '-list', '-gname', 'fakehost',
poll=True),
mock.call('storagegroup', '-addhlu', '-hlu', 2, '-alu', 1,
mock.call('port', '-list', '-sp')]
fake_cli.assert_has_calls(expected)
+ @mock.patch('random.randint',
+ mock.Mock(return_value=0))
+ def test_initialize_connection_fc_white_list(self):
+ self.configuration.io_port_list = 'a-0,B-2'
+ test_volume = self.testData.test_volume.copy()
+ test_volume['provider_location'] = 'system^fakesn|type^lun|id^1'
+ self.configuration.initiator_auto_registration = True
+ commands = [('storagegroup', '-list', '-gname', 'fakehost'),
+ self.testData.GETFCPORT_CMD(),
+ ('port', '-list', '-gname', 'fakehost')]
+ results = [[("No group", 83),
+ self.testData.STORAGE_GROUP_HAS_MAP_ISCSI('fakehost')],
+ self.testData.FC_PORTS,
+ self.testData.FAKEHOST_PORTS]
+
+ fake_cli = self.driverSetup(commands, results)
+ data = self.driver.initialize_connection(
+ test_volume,
+ self.testData.connector)
+
+ expected = [mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=False),
+ mock.call('storagegroup', '-create', '-gname', 'fakehost'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:12:34:56:'
+ '12:34:56:78:90:12:34:56',
+ '-sp', 'A', '-spport', 0, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:12:34:56:'
+ '12:34:56:78:90:12:34:56',
+ '-sp', 'B', '-spport', 2, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:54:32:16:'
+ '12:34:56:78:90:54:32:16',
+ '-sp', 'A', '-spport', 0, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:54:32:16:'
+ '12:34:56:78:90:54:32:16',
+ '-sp', 'B', '-spport', 2, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=True),
+ mock.call('storagegroup', '-addhlu', '-hlu', 2, '-alu', 1,
+ '-gname', 'fakehost', '-o',
+ poll=False),
+ mock.call('port', '-list', '-gname', 'fakehost')]
+ fake_cli.assert_has_calls(expected)
+ self.assertEqual(['5006016A0860080F', '5006016008600195'],
+ data['data']['target_wwn'])
+
+ @mock.patch('random.randint',
+ mock.Mock(return_value=0))
+ def test_initialize_connection_fc_port_registered_wl(self):
+ self.configuration.io_port_list = 'a-0,B-2'
+ test_volume = self.testData.test_volume.copy()
+ test_volume['provider_location'] = 'system^fakesn|type^lun|id^1'
+ self.configuration.initiator_auto_registration = True
+ commands = [('storagegroup', '-list', '-gname', 'fakehost'),
+ self.testData.GETFCPORT_CMD(),
+ ('port', '-list', '-gname', 'fakehost')]
+ results = [self.testData.STORAGE_GROUP_ISCSI_FC_HBA('fakehost'),
+ self.testData.FC_PORTS,
+ self.testData.FAKEHOST_PORTS]
+
+ fake_cli = self.driverSetup(commands, results)
+ data = self.driver.initialize_connection(
+ test_volume,
+ self.testData.connector)
+
+ expected = [mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=False),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:12:34:56:'
+ '12:34:56:78:90:12:34:56',
+ '-sp', 'A', '-spport', 0, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-gname', 'fakehost',
+ '-setpath', '-hbauid',
+ '22:34:56:78:90:54:32:16:'
+ '12:34:56:78:90:54:32:16',
+ '-sp', 'A', '-spport', 0, '-ip', '10.0.0.2',
+ '-host', 'fakehost', '-o'),
+ mock.call('storagegroup', '-list', '-gname', 'fakehost',
+ poll=True),
+ mock.call('storagegroup', '-addhlu', '-hlu', 2, '-alu', 1,
+ '-gname', 'fakehost', '-o',
+ poll=False),
+ mock.call('port', '-list', '-gname', 'fakehost')]
+ fake_cli.assert_has_calls(expected)
+ self.assertEqual(['5006016A0860080F', '5006016008600195'],
+ data['data']['target_wwn'])
+
@mock.patch(
"cinder.zonemanager.fc_san_lookup_service.FCSanLookupService." +
"get_device_mapping_from_network",
default='',
help='Mapping between hostname and '
'its iSCSI initiator IP addresses.'),
+ cfg.StrOpt('io_port_list',
+ default='*',
+ help='Comma separated iSCSI or FC ports '
+ 'to be used in Nova or Cinder.'),
cfg.BoolOpt('initiator_auto_registration',
default=False,
help='Automatically register initiators. '
return data
- def get_status_up_ports(self, storage_group_name, poll=True):
+ def get_status_up_ports(self, storage_group_name, io_ports=None,
+ poll=True):
"""Function to get ports whose status are up."""
cmd_get_hba = ('storagegroup', '-list', '-gname', storage_group_name)
out, rc = self.command_execute(*cmd_get_hba, poll=poll)
if 0 != rc:
self._raise_cli_error(cmd_get_port, rc, out)
for i, sp in enumerate(sps):
+ if io_ports: # Skip ports which are not in io_ports
+ if (sp.split()[1], int(portid[i])) not in io_ports:
+ continue
wwn = self.get_port_wwn(sp, portid[i], out)
if (wwn is not None) and (wwn not in wwns):
LOG.debug('Add wwn:%(wwn)s for sg:%(sg)s.',
self._raise_cli_error(cmd_get_hba, rc, out)
return wwns
- def get_login_ports(self, storage_group_name, connector_wwpns):
-
+ def get_login_ports(self, storage_group_name, connector_wwpns,
+ io_ports=None):
cmd_list_hba = ('port', '-list', '-gname', storage_group_name)
out, rc = self.command_execute(*cmd_list_hba)
ports = []
'HBA Devicename:.*\n\s*' +
'Trusted:.*\n\s*' +
'Logged In:\s*YES\n')
+
for each in connector_hba_list:
ports.extend(re.findall(port_pat, each))
ports = list(set(ports))
+ if io_ports:
+ ports = filter(lambda po:
+ (po[0].split()[1], int(po[1])) in io_ports,
+ ports)
for each in ports:
wwn = self.get_port_wwn(each[0], each[1], allports)
if wwn:
return wwns
def get_port_wwn(self, sp, port_id, allports=None):
+ """Returns wwn via sp and port_id
+
+ :param sp: should be in this format 'SP A'
+ :param port_id: '0' or 0
+ """
wwn = None
if allports is None:
- cmd_get_port = ('port', '-list', '-sp')
- out, rc = self.command_execute(*cmd_get_port)
- if 0 != rc:
- self._raise_cli_error(cmd_get_port, rc, out)
- else:
- allports = out
+ allports, rc = self.get_port_output()
_re_port_wwn = re.compile('SP Name:\s*' + sp +
- '\nSP Port ID:\s*' + port_id +
+ '\nSP Port ID:\s*' + str(port_id) +
'\nSP UID:\s*((\w\w:){15}(\w\w))' +
'\nLink Status: Up' +
'\nPort Status: Online')
return wwn
def get_fc_targets(self):
- fc_getport = ('port', '-list', '-sp')
- out, rc = self.command_execute(*fc_getport)
- if rc != 0:
- self._raise_cli_error(fc_getport, rc, out)
-
+ out, rc = self.get_port_output()
fc_target_dict = {'A': [], 'B': []}
_fcport_pat = (r'SP Name: SP\s(\w)\s*'
'Port ID': sp_port_id})
return fc_target_dict
- def get_iscsi_targets(self, poll=True):
+ def get_port_output(self):
+ cmd_get_port = ('port', '-list', '-sp')
+ out, rc = self.command_execute(*cmd_get_port)
+ if 0 != rc:
+ self._raise_cli_error(cmd_get_port, rc, out)
+ return out, rc
+
+ def get_connection_getport_output(self):
+ connection_getport_cmd = ('connection', '-getport', '-vlanid')
+ out, rc = self.command_execute(*connection_getport_cmd)
+ if 0 != rc:
+ self._raise_cli_error(connection_getport_cmd, rc, out)
+ return out, rc
+
+ def _filter_iscsi_ports(self, all_ports, io_ports):
+ """Filter ports in white list from all iSCSI ports."""
+ new_iscsi_ports = {'A': [], 'B': []}
+ valid_ports = []
+ for sp in all_ports:
+ for port in all_ports[sp]:
+ port_tuple = (port['SP'],
+ port['Port ID'],
+ port['Virtual Port ID'])
+ if port_tuple in io_ports:
+ new_iscsi_ports[sp].append(port)
+ valid_ports.append(port_tuple)
+ if len(io_ports) != len(valid_ports):
+ invalid_port_set = set(io_ports) - set(valid_ports)
+ for invalid in invalid_port_set:
+ LOG.warning(_LW('Invalid iSCSI port %(sp)s-%(port)s-%(vlan)s '
+ 'found in io_port_list, will be ignored.'),
+ {'sp': invalid[0], 'port': invalid[1],
+ 'vlan': invalid[2]})
+ return new_iscsi_ports
+
+ def get_iscsi_targets(self, poll=False, io_ports=None):
cmd_getport = ('connection', '-getport', '-address', '-vlanid')
out, rc = self.command_execute(*cmd_getport, poll=poll)
if rc != 0:
'Port WWN': iqn,
'Virtual Port ID': vport_id,
'IP Address': ip_addr})
-
+ if io_ports:
+ return self._filter_iscsi_ports(iscsi_target_dict, io_ports)
return iscsi_target_dict
def get_registered_spport_set(self, initiator_iqn, sgname, sg_raw_out):
conf_pools = self.configuration.safe_get("storage_vnx_pool_names")
self.storage_pools = self._get_managed_storage_pools(conf_pools)
self.array_serial = None
+ self.io_ports = self._parse_ports(self.configuration.io_port_list,
+ self.protocol)
if self.protocol == 'iSCSI':
- self.iscsi_targets = self._client.get_iscsi_targets(poll=True)
+ self.iscsi_targets = self._client.get_iscsi_targets(
+ poll=True, io_ports=self.io_ports)
self.hlu_cache = {}
self.force_delete_lun_in_sg = (
self.configuration.force_delete_lun_in_storagegroup)
"manage all the pools on the VNX system.")
return storage_pools
+ def _parse_ports(self, io_port_list, protocol):
+ """Validates IO port format, supported format is a-1, b-3, a-3-0."""
+ if not io_port_list or io_port_list == '*':
+ return None
+ ports = re.split('\s*,\s*', io_port_list)
+ valid_ports = []
+ invalid_ports = []
+ if 'iSCSI' == protocol:
+ out, rc = self._client.get_connection_getport_output()
+ for port in ports:
+ port_tuple = port.split('-')
+ if (re.match('[abAB]-\d+-\d+$', port) and
+ self._validate_iscsi_port(
+ port_tuple[0], port_tuple[1], port_tuple[2], out)):
+ valid_ports.append(
+ (port_tuple[0].upper(), int(port_tuple[1]),
+ int(port_tuple[2])))
+ else:
+ invalid_ports.append(port)
+ elif 'FC' == protocol:
+ out, rc = self._client.get_port_output()
+ for port in ports:
+ port_tuple = port.split('-')
+ if re.match('[abAB]-\d+$', port) and self._validate_fc_port(
+ port_tuple[0], port_tuple[1], out):
+ valid_ports.append(
+ (port_tuple[0].upper(), int(port_tuple[1])))
+ else:
+ invalid_ports.append(port)
+ if len(invalid_ports) > 0:
+ msg = _('Invalid %(protocol)s ports %(port)s specified '
+ 'for io_port_list.') % {'protocol': self.protocol,
+ 'port': ','.join(invalid_ports)}
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ return valid_ports
+
+ def _validate_iscsi_port(self, sp, port_id, vlan_id, cmd_output):
+ """Validates whether the iSCSI port is existed on VNX"""
+ iscsi_pattern = ('SP:\s+' + sp.upper() +
+ '\nPort ID:\s+' + str(port_id) +
+ '\nPort WWN:\s+.*' +
+ '\niSCSI Alias:\s+.*\n'
+ '\nVirtual Port ID:\s+' + str(vlan_id))
+ return re.search(iscsi_pattern, cmd_output)
+
+ def _validate_fc_port(self, sp, port_id, cmd_output):
+ """Validates whether the FC port is existed on VNX"""
+ fc_pattern = ('SP Name:\s*SP\s*' + sp.upper() +
+ '\nSP Port ID:\s*' + str(port_id) +
+ '\nSP UID:\s*((\w\w:){15}(\w\w))')
+ return re.search(fc_pattern, cmd_output)
+
def get_array_serial(self):
if not self.array_serial:
self.array_serial = self._client.get_array_serial()
self.stats['consistencygroup_support'] = (
'True' if '-VNXSnapshots' in self.enablers else 'False')
-
return self.stats
def create_snapshot(self, snapshot):
'portid': port_id,
'msg': out})
- def _register_iscsi_initiator(self, ip, host, initiator_uids):
- iscsi_targets = self.iscsi_targets
+ def auto_register_with_io_port_filter(self, connector, sgdata,
+ io_port_filter):
+ """Automatically register specific IO ports to storage group."""
+ initiator = connector['initiator']
+ ip = connector['ip']
+ host = connector['host']
+ new_white = {'A': [], 'B': []}
+ if self.protocol == 'iSCSI':
+ if sgdata:
+ sp_ports = self._client.get_registered_spport_set(
+ initiator, host, sgdata['raw_output'])
+ # Normalize io_ports
+ for sp in ('A', 'B'):
+ new_ports = filter(
+ lambda pt: (pt['SP'], pt['Port ID']) not in sp_ports,
+ self.iscsi_targets[sp])
+ new_white[sp] = map(lambda white:
+ {'SP': white['SP'],
+ 'Port ID': white['Port ID'],
+ 'Virtual Port ID':
+ white['Virtual Port ID']},
+ new_ports)
+ else:
+ new_white = self.iscsi_targets
+ self._register_iscsi_initiator(ip, host, [initiator], new_white)
+
+ elif self.protocol == 'FC':
+ wwns = self._extract_fc_uids(connector)
+ ports_list = []
+ if sgdata:
+ for wwn in wwns:
+ for port in io_port_filter:
+ if ((port not in ports_list) and
+ (not re.search(wwn + '\s+SP\s+' +
+ port[0] + '\s+' + str(port[1]),
+ sgdata['raw_output'],
+ re.IGNORECASE))):
+ # Record ports to be added
+ ports_list.append(port)
+ new_white[port[0]].append({
+ 'SP': port[0],
+ 'Port ID': port[1]})
+ else:
+ # Need to translate to dict format
+ for fc_port in io_port_filter:
+ new_white[fc_port[0]].append({'SP': fc_port[0],
+ 'Port ID': fc_port[1]})
+ self._register_fc_initiator(ip, host, wwns, new_white)
+ return new_white['A'] or new_white['B']
+
+ def _register_iscsi_initiator(self, ip, host, initiator_uids,
+ port_to_register=None):
+ iscsi_targets = (port_to_register if port_to_register else
+ self.iscsi_targets)
for initiator_uid in initiator_uids:
LOG.info(_LI('Get ISCSI targets %(tg)s to register '
'initiator %(in)s.'),
self._exec_command_setpath(initiator_uid, sp, port_id,
ip, host, vport_id)
- def _register_fc_initiator(self, ip, host, initiator_uids):
- fc_targets = self._client.get_fc_targets()
+ def _register_fc_initiator(self, ip, host, initiator_uids,
+ ports_to_register=None):
+ fc_targets = (ports_to_register if ports_to_register else
+ self._client.get_fc_targets())
for initiator_uid in initiator_uids:
LOG.info(_LI('Get FC targets %(tg)s to register '
'initiator %(in)s.'),
unregistered_initiators.append(initiator_uid)
return unregistered_initiators
- def auto_register_initiator(self, connector, sgdata):
+ def auto_register_initiator_to_all(self, connector, sgdata):
"""Automatically registers available initiators.
Returns True if has registered initiator otherwise returns False.
self._register_fc_initiator(ip, host, itors_toReg)
return True
+ def auto_register_initiator(self, connector, sgdata, io_ports_filter=None):
+ """Automatically register available initiators.
+
+ :returns: True if has registered initiator otherwise return False
+ """
+ if io_ports_filter:
+ return self.auto_register_with_io_port_filter(connector, sgdata,
+ io_ports_filter)
+ else:
+ return self.auto_register_initiator_to_all(connector, sgdata)
+
def assure_host_access(self, volume, connector):
hostname = connector['host']
volumename = volume['name']
# Storage Group has not existed yet
self.assure_storage_group(hostname)
if self.itor_auto_reg:
- self.auto_register_initiator(connector, None)
+ self.auto_register_initiator(connector, None, self.io_ports)
auto_registration_done = True
else:
self._client.connect_host_to_storage_group(hostname, hostname)
poll=True)
if self.itor_auto_reg and not auto_registration_done:
- new_registerred = self.auto_register_initiator(connector, sgdata)
+ new_registerred = self.auto_register_initiator(connector, sgdata,
+ self.io_ports)
if new_registerred:
sgdata = self._client.get_storage_group(hostname,
poll=True)
properties['target_portal'] = \
"%s:3260" % targets[0]['IP Address']
properties['target_lun'] = hlu
-
- auth = volume['provider_auth']
- if auth:
- (auth_method, auth_username, auth_secret) = auth.split()
- properties['auth_method'] = auth_method
- properties['auth_username'] = auth_username
- properties['auth_password'] = auth_secret
else:
properties = {'target_discovered': False,
'target_iqns': None,
'target_dicovered': True,
'target_wwn': None}
if self.zonemanager_lookup_service is None:
- fc_properties['target_wwn'] = self.get_login_ports(connector)
+ fc_properties['target_wwn'] = self.get_login_ports(connector,
+ self.io_ports)
else:
target_wwns, itor_tgt_map = self.get_initiator_target_map(
connector['wwpns'],
- self.get_status_up_ports(connector))
+ self.get_status_up_ports(connector, self.io_ports))
fc_properties['target_wwn'] = target_wwns
fc_properties['initiator_target_map'] = itor_tgt_map
return fc_properties
self._build_provider_location_for_lun(lun_id)}
return model_update
- def get_login_ports(self, connector):
+ def get_login_ports(self, connector, io_ports=None):
return self._client.get_login_ports(connector['host'],
- connector['wwpns'])
+ connector['wwpns'],
+ io_ports)
- def get_status_up_ports(self, connector):
- return self._client.get_status_up_ports(connector['host'])
+ def get_status_up_ports(self, connector, io_ports=None):
+ return self._client.get_status_up_ports(connector['host'],
+ io_ports=io_ports)
def get_initiator_target_map(self, fc_initiators, fc_targets):
target_wwns = []
def update_volume_stats(self):
"""Retrieves stats info."""
self.update_enabler_in_volume_stats()
-
if self.protocol == 'iSCSI':
- self.iscsi_targets = self._client.get_iscsi_targets(poll=False)
+ self.iscsi_targets = self._client.get_iscsi_targets(
+ poll=False, io_ports=self.io_ports)
properties = [self._client.POOL_FREE_CAPACITY,
self._client.POOL_TOTAL_CAPACITY,