Merge "VMAX driver - Removal of iscsiadm from vmax cinder"

This commit is contained in:
Jenkins 2016-09-11 18:19:29 +00:00 committed by Gerrit Code Review
commit 781475f114
4 changed files with 108 additions and 202 deletions

View File

@ -17,7 +17,6 @@ import os
import shutil
import sys
import tempfile
import time
import unittest
from xml.dom import minidom
@ -159,6 +158,13 @@ class Fake_CIMProperty(object):
cimproperty.value = '10.10.10.10'
return cimproperty
def fake_getiqn(self):
cimproperty = Fake_CIMProperty()
cimproperty.key = 'Name'
cimproperty.value = (
'iqn.1992-04.com.emc:600009700bca30c01b9c012000000003,t,0x0001')
return cimproperty
def fake_getSupportedReplicationTypesCIMProperty(self, reptypes):
cimproperty = Fake_CIMProperty()
if reptypes == 'V3':
@ -1725,6 +1731,17 @@ class FakeEcomConnection(object):
ipprotocolendpoint.properties = properties
ipprotocolendpoint.path = ipprotocolendpoint
ipprotocolendpoints.append(ipprotocolendpoint)
iqnprotocolendpoint = CIM_IPProtocolEndpoint()
iqnprotocolendpoint['CreationClassName'] = (
'Symm_VirtualiSCSIProtocolEndpoint')
iqnprotocolendpoint['SystemName'] = self.data.storage_system
classcimproperty = Fake_CIMProperty()
iqncimproperty = (
classcimproperty.fake_getiqn())
properties = {u'Name': iqncimproperty}
iqnprotocolendpoint.properties = properties
iqnprotocolendpoint.path = iqnprotocolendpoint
ipprotocolendpoints.append(iqnprotocolendpoint)
return ipprotocolendpoints
def _default_enum(self):
@ -1754,16 +1771,11 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
True,
'volume_backend_name':
'ISCSINoFAST'}))
self.mock_object(emc_vmax_iscsi.EMCVMAXISCSIDriver,
'smis_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
self.mock_object(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
self.fake_ecom_connection)
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
@ -1936,17 +1948,6 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
conn = FakeEcomConnection()
return conn
def fake_do_iscsi_discovery(self, volume):
output = []
properties = {}
properties['target_portal'] = '10.10.0.50:3260'
properties['target_iqn'] = 'iqn.1992-04.com.emc:50000973f006dd80'
output.append(properties)
return output
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -2178,9 +2179,9 @@ class EMCVMAXISCSIDriverNoFastTestCase(test.TestCase):
def test_find_ip_protocol_endpoints(self):
conn = self.fake_ecom_connection()
foundIpAddresses = self.driver.common._find_ip_protocol_endpoints(
endpoint = self.driver.common._find_ip_protocol_endpoints(
conn, self.data.storage_system, self.data.port_group)
self.assertEqual('10.10.10.10', foundIpAddresses[0])
self.assertEqual('10.10.10.10', endpoint[0]['ip'])
def test_find_device_number(self):
host = 'fakehost'
@ -3954,17 +3955,11 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
configuration.cinder_emc_config_file = self.config_file_path
configuration.safe_get.return_value = 'ISCSIFAST'
configuration.config_group = 'ISCSIFAST'
self.mock_object(emc_vmax_iscsi.EMCVMAXISCSIDriver,
'smis_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
self.mock_object(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
self.fake_ecom_connection)
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
@ -4041,17 +4036,6 @@ class EMCVMAXISCSIDriverFastTestCase(test.TestCase):
conn = FakeEcomConnection()
return conn
def fake_do_iscsi_discovery(self, volume):
output = []
properties = {}
properties['target_portal'] = '10.10.0.50:3260'
properties['target_iqn'] = 'iqn.1992-04.com.emc:50000973f006dd80'
output.append(properties)
return output
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -4613,8 +4597,6 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
@ -4686,9 +4668,6 @@ class EMCVMAXFCDriverNoFastTestCase(test.TestCase):
conn = FakeEcomConnection()
return conn
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -5180,8 +5159,6 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
driver = emc_vmax_fc.EMCVMAXFCDriver(configuration=configuration)
@ -5258,9 +5235,6 @@ class EMCVMAXFCDriverFastTestCase(test.TestCase):
conn = FakeEcomConnection()
return conn
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -5846,8 +5820,6 @@ class EMCV3DriverTestCase(test.TestCase):
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
self.patcher = mock.patch(
@ -5930,9 +5902,6 @@ class EMCV3DriverTestCase(test.TestCase):
self.conn = FakeEcomConnection()
return self.conn
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return True
@ -6699,19 +6668,13 @@ class EMCV2MultiPoolDriverTestCase(test.TestCase):
configuration.cinder_emc_config_file = self.config_file_path
configuration.config_group = 'MULTI_POOL'
self.mock_object(emc_vmax_iscsi.EMCVMAXISCSIDriver,
'smis_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
self.mock_object(emc_vmax_common.EMCVMAXCommon, '_get_ecom_connection',
self.fake_ecom_connection)
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
driver.db = FakeDB()
self.driver = driver
@ -6799,17 +6762,6 @@ class EMCV2MultiPoolDriverTestCase(test.TestCase):
self.conn = FakeEcomConnection()
return self.conn
def fake_do_iscsi_discovery(self, volume):
output = []
properties = {}
properties['target_portal'] = '10.10.0.50:3260'
properties['target_iqn'] = 'iqn.1992-04.com.emc:50000973f006dd80'
output.append(properties)
return output
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -6993,8 +6945,6 @@ class EMCV3MultiSloDriverTestCase(test.TestCase):
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
@ -7096,9 +7046,6 @@ class EMCV3MultiSloDriverTestCase(test.TestCase):
self.conn = FakeEcomConnection()
return self.conn
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return True
@ -7300,8 +7247,6 @@ class EMCV2MultiPoolDriverMultipleEcomsTestCase(test.TestCase):
instancename = FakeCIMInstanceName()
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'get_instance_name',
instancename.fake_getinstancename)
self.mock_object(time, 'sleep',
self.fake_sleep)
self.mock_object(emc_vmax_utils.EMCVMAXUtils, 'isArrayV3',
self.fake_is_v3)
driver = emc_vmax_fc.EMCVMAXFCDriver(configuration=configuration)
@ -7456,9 +7401,6 @@ class EMCV2MultiPoolDriverMultipleEcomsTestCase(test.TestCase):
self.conn = FakeEcomConnection()
return self.conn
def fake_sleep(self, seconds):
return
def fake_is_v3(self, conn, serialNumber):
return False
@ -8268,6 +8210,13 @@ class EMCVMAXUtilsTest(test.TestCase):
os.remove(emc_vmax_utils.LIVE_MIGRATION_FILE)
shutil.rmtree(tempdir)
def test_get_iqn(self):
conn = FakeEcomConnection()
iqn = "iqn.1992-04.com.emc:600009700bca30c01b9c012000000003,t,0x0001"
ipprotocolendpoints = conn._enum_ipprotocolendpoint()
foundIqn = self.driver.utils.get_iqn(conn, ipprotocolendpoints[1])
self.assertEqual(iqn, foundIqn)
class EMCVMAXCommonTest(test.TestCase):
def setUp(self):
@ -8381,6 +8330,20 @@ class EMCVMAXCommonTest(test.TestCase):
self.driver.common._cleanup_target(
repServiceInstanceName, targetInstance, extraSpecs)
def test_get_ip_and_iqn(self):
conn = FakeEcomConnection()
endpoint = {}
ipprotocolendpoints = conn._enum_ipprotocolendpoint()
ip_and_iqn = self.driver.common.get_ip_and_iqn(conn, endpoint,
ipprotocolendpoints[0])
ip_and_iqn = self.driver.common.get_ip_and_iqn(conn, endpoint,
ipprotocolendpoints[1])
self.assertEqual(
'iqn.1992-04.com.emc:600009700bca30c01b9c012000000003,t,0x0001',
ip_and_iqn['iqn'])
self.assertEqual(
'10.10.10.10', ip_and_iqn['ip'])
class EMCVMAXProvisionTest(test.TestCase):
def setUp(self):
@ -8464,42 +8427,22 @@ class EMCVMAXISCSITest(test.TestCase):
configuration = mock.Mock()
configuration.safe_get.return_value = 'iSCSITests'
configuration.config_group = 'iSCSITests'
self.mock_object(emc_vmax_iscsi.EMCVMAXISCSIDriver,
'smis_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
emc_vmax_common.EMCVMAXCommon._gather_info = mock.Mock()
driver = emc_vmax_iscsi.EMCVMAXISCSIDriver(configuration=configuration)
driver.db = FakeDB()
self.driver = driver
def fake_do_iscsi_discovery(self, volume):
output = []
properties = {}
properties['target_portal'] = '10.10.0.50:3260'
properties['target_iqn'] = 'iqn.1992-04.com.emc:50000973f006dd80'
output.append(properties)
properties = {}
properties['target_portal'] = '10.10.0.51:3260'
properties['target_iqn'] = 'iqn.1992-04.com.emc:50000973f006dd81'
output.append(properties)
return output
def test_parse_target_list(self):
targets = ["10.10.10.31:3260,0 iqn.1f:29.ID2",
"10.10.10.32:3260,0 iqn.2f:29.ID2"]
out_targets = self.driver._parse_target_list(targets)
self.assertEqual('10.10.10.31:3260', out_targets[0]['target_portal'])
self.assertEqual('iqn.1f:29.ID2', out_targets[0]['target_iqn'])
self.assertEqual('10.10.10.32:3260', out_targets[1]['target_portal'])
self.assertEqual('iqn.2f:29.ID2', out_targets[1]['target_iqn'])
def test_smis_get_iscsi_properties(self):
self.driver.iscsi_ip_addresses = ['10.10.0.50', '10.10.0.51']
device_info = {'hostlunid': 1}
self.driver.common.find_device_number = (
mock.Mock(return_value=device_info))
iqns_and_ips = (
[{'iqn': 'iqn.1992-04.com.emc:50000973f006dd80,t,0x0001',
'ip': '10.10.0.50'},
{'iqn': 'iqn.1992-04.com.emc:50000973f006dd81,t,0x0001',
'ip': '10.10.0.51'}])
properties = self.driver.smis_get_iscsi_properties(
self.data.test_volume, self.data.connector, True)
self.data.test_volume, self.data.connector, iqns_and_ips, True)
self.assertEqual([1, 1], properties['target_luns'])
self.assertEqual(['iqn.1992-04.com.emc:50000973f006dd80',
'iqn.1992-04.com.emc:50000973f006dd81'],

View File

@ -432,7 +432,7 @@ class EMCVMAXCommon(object):
volume, connector, extraSpecs, maskingViewDict))
if self.protocol.lower() == 'iscsi':
deviceInfoDict['iscsi_ip_addresses'] = (
deviceInfoDict['ip_and_iqn'] = (
self._find_ip_protocol_endpoints(
self.conn, deviceInfoDict['storagesystem'],
portGroupName))
@ -4484,12 +4484,12 @@ class EMCVMAXCommon(object):
ipendpointinstancenames = (
self.utils.get_ip_protocol_endpoints(
conn, tcpendpointinstancename))
endpoint = {}
for ipendpointinstancename in ipendpointinstancenames:
ipaddress = (
self.utils.get_iscsi_ip_address(
conn, ipendpointinstancename))
if ipaddress:
foundipaddresses.append(ipaddress)
endpoint = self.get_ip_and_iqn(conn, endpoint,
ipendpointinstancename)
if bool(endpoint):
foundipaddresses.append(endpoint)
return foundipaddresses
def _extend_v3_volume(self, volumeInstance, volumeName, newSize,
@ -4538,3 +4538,26 @@ class EMCVMAXCommon(object):
{'sourceVol': sourceInstance.path,
'targetVol': targetInstance.path})
return targetInstance
def get_ip_and_iqn(self, conn, endpoint, ipendpointinstancename):
"""Get ip and iqn from the endpoint.
:param conn: ecom connection
:param endpoint: end point
:param ipendpointinstancename: ip endpoint
:returns: endpoint
"""
if ('iSCSIProtocolEndpoint' in six.text_type(
ipendpointinstancename['CreationClassName'])):
iqn = self.utils.get_iqn(conn, ipendpointinstancename)
if iqn:
endpoint['iqn'] = iqn
elif ('IPProtocolEndpoint' in six.text_type(
ipendpointinstancename['CreationClassName'])):
ipaddress = (
self.utils.get_iscsi_ip_address(
conn, ipendpointinstancename))
if ipaddress:
endpoint['ip'] = ipaddress
return endpoint

View File

@ -16,8 +16,6 @@
ISCSI Drivers for EMC VMAX arrays based on SMI-S.
"""
import os
from oslo_log import log as logging
import six
@ -93,7 +91,6 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
emc_vmax_common.EMCVMAXCommon('iSCSI',
self.VERSION,
configuration=self.configuration))
self.iscsi_ip_addresses = []
def check_for_setup_error(self):
pass
@ -194,17 +191,16 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
device_info = self.common.initialize_connection(
volume, connector)
try:
self.iscsi_ip_addresses = device_info['iscsi_ip_addresses']
ip_and_iqn = device_info['ip_and_iqn']
is_multipath = device_info['is_multipath']
except KeyError as ex:
exception_message = (_("Cannot get iSCSI ipaddresses or "
"multipath flag. Exception is %(ex)s. ")
% {'ex': ex})
raise exception.VolumeBackendAPIException(data=exception_message)
iscsi_properties = self.smis_get_iscsi_properties(
volume, connector, is_multipath)
volume, connector, ip_and_iqn, is_multipath)
LOG.info(_LI("Leaving initialize_connection: %s"), iscsi_properties)
return {
@ -212,50 +208,6 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
'data': iscsi_properties
}
def _call_iscsiadm(self, iscsi_ip_address):
"""Calls iscsiadm with iscsi ip address"""
try:
(out, _err) = self._execute('iscsiadm', '-m', 'discovery',
'-t', 'sendtargets', '-p',
iscsi_ip_address,
run_as_root=True)
return out, _err, None
except Exception as ex:
return None, None, ex
def smis_do_iscsi_discovery(self, volume):
"""Calls iscsiadm with each iscsi ip address in the list"""
LOG.info(_LI("ISCSI provider_location not stored, using discovery."))
targets = []
if len(self.iscsi_ip_addresses) == 0:
LOG.error(_LE("The list of iscsi_ip_addresses is empty"))
return targets
outList = []
for iscsi_ip_address in self.iscsi_ip_addresses:
if iscsi_ip_address:
out, _err, ex = self._call_iscsiadm(iscsi_ip_address)
if out:
outList.append(out)
if len(outList) == 0:
if ex:
exception_message = (_("Unsuccessful iscsiadm. "
"Exception is %(ex)s. ")
% {'ex': ex})
else:
exception_message = (_("iscsiadm execution failed. "))
raise exception.VolumeBackendAPIException(data=exception_message)
LOG.info(_LI(
"smis_do_iscsi_discovery is: %(out)s."),
{'out': out})
for out in outList:
for target in out.splitlines():
targets.append(target)
outTargets = self._parse_target_list(targets)
return outTargets
def _parse_target_list(self, targets):
"""Parse target list into usable format.
@ -271,7 +223,8 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
outTargets.append(properties)
return outTargets
def smis_get_iscsi_properties(self, volume, connector, is_multipath):
def smis_get_iscsi_properties(self, volume, connector, ip_and_iqn,
is_multipath):
"""Gets iscsi configuration.
We ideally get saved information in the volume entity, but fall back
@ -288,14 +241,6 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
meaning use CHAP with the specified credentials.
"""
targets = self.smis_do_iscsi_discovery(volume)
if len(targets) == 0:
raise exception.InvalidVolume(_("Could not find iSCSI export "
"for volume %(volumeName)s.")
% {'volumeName': volume['name']})
LOG.debug("ISCSI Discovery: Found %s", targets)
device_info = self.common.find_device_number(
volume, connector['host'])
@ -315,28 +260,18 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
% {'volumeName': volume['name']})
raise exception.VolumeBackendAPIException(data=exception_message)
properties = {'target_discovered': False,
'target_iqn': 'unknown',
'target_iqns': None,
'target_portal': 'unknown',
'target_portals': None,
'target_lun': 'unknown',
'target_luns': None,
'volume_id': volume['id']}
if len(self.iscsi_ip_addresses) > 0:
if len(self.iscsi_ip_addresses) > 1 and is_multipath:
properties['target_iqns'] = [t['target_iqn'] for t in targets]
properties['target_portals'] = (
[t['target_portal'] for t in targets])
properties['target_luns'] = [lun_id] * len(targets)
properties['target_discovered'] = True
properties['target_iqn'] = [t['target_iqn'] for t in targets][0]
properties['target_portal'] = (
[t['target_portal'] for t in targets][0])
properties['target_lun'] = lun_id
else:
LOG.error(_LE('Failed to find available iSCSI targets.'))
properties = {}
if len(ip_and_iqn) > 1 and is_multipath:
properties['target_portals'] = ([t['ip'] + ":3260" for t in
ip_and_iqn])
properties['target_iqns'] = ([t['iqn'].split(",")[0] for t in
ip_and_iqn])
properties['target_luns'] = [lun_id] * len(ip_and_iqn)
properties['target_discovered'] = True
properties['target_iqn'] = ip_and_iqn[0]['iqn'].split(",")[0]
properties['target_portal'] = ip_and_iqn[0]['ip'] + ":3260"
properties['target_lun'] = lun_id
properties['volume_id'] = volume['id']
LOG.info(_LI(
"ISCSI properties: %(properties)s."), {'properties': properties})
@ -425,17 +360,6 @@ class EMCVMAXISCSIDriver(driver.ISCSIDriver):
"""Deletes a cgsnapshot."""
return self.common.delete_cgsnapshot(context, cgsnapshot, snapshots)
def _check_for_iscsi_ip_address(self):
"""Check to see if iscsi_ip_address is set in cinder.conf
:returns: boolean -- True if iscsi_ip_address id defined in config.
"""
bExists = os.path.exists(CINDER_CONF)
if bExists:
if 'iscsi_ip_address' in open(CINDER_CONF).read():
return True
return False
def manage_existing(self, volume, external_ref):
"""Manages an existing VMAX Volume (import to Cinder).

View File

@ -2796,3 +2796,19 @@ class EMCVMAXUtils(object):
"record.",
{'Volume': volume['id']})
return returned_record
def get_iqn(self, conn, ipendpointinstancename):
"""Get the IPv4Address from the ip endpoint instance name.
:param conn: the ecom connection
:param ipendpointinstancename: the ip endpoint instance name
:returns: foundIqn
"""
foundIqn = None
ipendpointinstance = conn.GetInstance(ipendpointinstancename)
propertiesList = ipendpointinstance.properties.items()
for properties in propertiesList:
if properties[0] == 'Name':
cimProperties = properties[1]
foundIqn = cimProperties.value
return foundIqn