pass
+class CIM_IPProtocolEndpoint(dict):
+ pass
+
+
class SE_ReplicationSettingData(dict):
def __init__(self, *args, **kwargs):
self['DefaultInstance'] = self.createInstance()
cimproperty.value = [2, 10]
return cimproperty
+ def fake_getipv4address(self):
+ cimproperty = Fake_CIMProperty()
+ cimproperty.key = 'IPv4Address'
+ cimproperty.value = '10.10.10.10'
+ return cimproperty
+
class Fake_CIM_TierPolicyServiceCapabilities(object):
result = self._enum_maskingView()
elif ResultClass == 'EMC_Meta':
result = self._enum_metavolume()
+ elif AssocClass == 'CIM_BindsTo':
+ result = self._assocnames_bindsto()
+ elif AssocClass == 'CIM_MemberOfCollection':
+ result = self._assocnames_memberofcollection()
else:
result = self._default_assocnames(objectpath)
return result
def _assocnames_portgroup(self):
return self._enum_portgroup()
+ def _assocnames_memberofcollection(self):
+ return self._enum_hostedservice()
+
+ def _assocnames_bindsto(self):
+ return self._enum_ipprotocolendpoint()
+
def _default_assocnames(self, objectpath):
return objectpath
repServCpblInstance.properties = properties
return repServCpblInstance
+ def _getinstance_ipprotocolendpoint(self, objectpath):
+ return self._enum_ipprotocolendpoint()[0]
+
def _default_getinstance(self, objectpath):
return objectpath
swIdentities.append(swIdentity)
return swIdentities
+ def _enum_ipprotocolendpoint(self):
+ ipprotocolendpoints = []
+ ipprotocolendpoint = CIM_IPProtocolEndpoint()
+ ipprotocolendpoint['CreationClassName'] = 'CIM_IPProtocolEndpoint'
+ ipprotocolendpoint['SystemName'] = self.data.storage_system
+ classcimproperty = Fake_CIMProperty()
+ ipv4addresscimproperty = (
+ classcimproperty.fake_getipv4address())
+ properties = {u'IPv4Address': ipv4addresscimproperty}
+ ipprotocolendpoint.properties = properties
+ ipprotocolendpoint.path = ipprotocolendpoint
+ ipprotocolendpoints.append(ipprotocolendpoint)
+ return ipprotocolendpoints
+
def _default_enum(self):
names = []
name = {}
host_over_38_chars)
self.assertEqual(host2, host3)
+ def test_find_ip_protocol_endpoints(self):
+ conn = self.fake_ecom_connection()
+ foundIpAddresses = self.driver.common._find_ip_protocol_endpoints(
+ conn, self.data.storage_system, self.data.port_group)
+ self.assertEqual('10.10.10.10', foundIpAddresses[0])
+
def test_find_device_number(self):
host = 'myhost'
data = (
conn, self.data.storage_system))
foundPortGroupInstanceName = (
- self.driver.common.masking._find_port_group(
+ self.driver.common.masking.find_port_group(
conn, controllerConfigService, self.data.port_group))
# The port group has been found.
self.assertEqual(
self.driver.common.masking.utils.get_existing_instance = mock.Mock(
return_value=None)
foundPortGroupInstanceName2 = (
- self.driver.common.masking._find_port_group(
+ self.driver.common.masking.find_port_group(
conn, controllerConfigService, self.data.port_group))
# The port group has not been found as it has been deleted
# externally or by another thread.
{'volume': volumeName})
self.conn = self._get_ecom_connection()
deviceInfoDict = self.find_device_number(volume, connector['host'])
+ maskingViewDict = self._populate_masking_dict(
+ volume, connector, extraSpecs)
if ('hostlunid' in deviceInfoDict and
deviceInfoDict['hostlunid'] is not None):
'deviceNumber': deviceNumber})
else:
deviceInfoDict = self._attach_volume(
- volume, connector, extraSpecs, True)
+ volume, connector, extraSpecs, maskingViewDict, True)
else:
- deviceInfoDict = self._attach_volume(volume, connector,
- extraSpecs)
+ deviceInfoDict = self._attach_volume(
+ volume, connector, extraSpecs, maskingViewDict)
- return deviceInfoDict
+ if self.protocol.lower() == 'iscsi':
+ return self._find_ip_protocol_endpoints(
+ self.conn, deviceInfoDict['storagesystem'],
+ maskingViewDict['pgGroupName'])
+ else:
+ return deviceInfoDict
def _attach_volume(self, volume, connector, extraSpecs,
- isLiveMigration=None):
+ maskingViewDict, isLiveMigration=None):
"""Attach a volume to a host.
If live migration is being undertaken then the volume
:params volume: the volume object
:params connector: the connector object
:param extraSpecs: extra specifications
+ :param maskingViewDict: masking view information
:param isLiveMigration: boolean, can be None
:returns: dict -- deviceInfoDict
:raises: VolumeBackendAPIException
context, db, group['id'], modelUpdate['status'])
return modelUpdate, volumes_model_update
+
+ def _find_ip_protocol_endpoints(self, conn, storageSystemName,
+ portgroupname):
+ """Find the IP protocol endpoint for ISCSI
+
+ :param storageSystemName: the system name
+ :param portgroupname: the portgroup name
+ :returns: foundIpAddresses
+ """
+ foundipaddresses = []
+ configservice = (
+ self.utils.find_controller_configuration_service(
+ conn, storageSystemName))
+ portgroupinstancename = (
+ self.masking.find_port_group(conn, configservice, portgroupname))
+ iscsiendpointinstancenames = (
+ self.utils.get_iscsi_protocol_endpoints(
+ conn, portgroupinstancename))
+
+ for iscsiendpointinstancename in iscsiendpointinstancenames:
+ tcpendpointinstancenames = (
+ self.utils.get_tcp_protocol_endpoints(
+ conn, iscsiendpointinstancename))
+ for tcpendpointinstancename in tcpendpointinstancenames:
+ ipendpointinstancenames = (
+ self.utils.get_ip_protocol_endpoints(
+ conn, tcpendpointinstancename))
+ for ipendpointinstancename in ipendpointinstancenames:
+ ipaddress = (
+ self.utils.get_iscsi_ip_address(
+ conn, ipendpointinstancename))
+ foundipaddresses.append(ipaddress)
+ return foundipaddresses
emc_vmax_common.EMCVMAXCommon('iSCSI',
self.VERSION,
configuration=self.configuration))
+ self.iscsi_ip_addresses = []
def check_for_setup_error(self):
pass
def create_volume(self, volume):
- """Creates a EMC(VMAX/VNX) volume."""
+ """Creates a VMAX volume."""
volpath = self.common.create_volume(volume)
model_update = {}
}
}
"""
- self.common.initialize_connection(
+ self.iscsi_ip_addresses = self.common.initialize_connection(
volume, connector)
iscsi_properties = self.smis_get_iscsi_properties(
'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, False, None
+ except Exception as ex:
+ return None, None, True, 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."))
- if not self._check_for_iscsi_ip_address():
- LOG.error(_LE(
- "You must set your iscsi_ip_address in cinder.conf."))
-
- (out, _err) = self._execute('iscsiadm', '-m', 'discovery',
- '-t', 'sendtargets', '-p',
- self.configuration.iscsi_ip_address,
- run_as_root=True)
+ targets = []
+ if len(self.iscsi_ip_addresses) == 0:
+ LOG.error(_LE("The list of iscsi_ip_addresses is empty"))
+ return targets
+
+ for iscsi_ip_address in self.iscsi_ip_addresses:
+ out, _err, go_again, ex = self._call_iscsiadm(iscsi_ip_address)
+ if not go_again:
+ break
+ if not out:
+ 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})
- targets = []
+
for target in out.splitlines():
targets.append(target)
if self._is_volume_in_storage_group(
conn, storageGroupInstanceName,
volumeInstance, sgGroupName):
- LOG.warning(_LW(
+ LOG.debug(
"Volume: %(volumeName)s is already part "
- "of storage group %(sgGroupName)s."),
+ "of storage group %(sgGroupName)s.",
{'volumeName': volumeName,
'sgGroupName': sgGroupName})
else:
'sgGroupName': sgGroupName})
LOG.error(msg)
else:
- LOG.debug("Successfully added %(volumeName)s to "
- "%(sgGroupName)s.",
- {'volumeName': volumeName,
- 'sgGroupName': sgGroupName})
+ LOG.info(_LI(
+ "Successfully added %(volumeName)s to %(sgGroupName)s."),
+ {'volumeName': volumeName,
+ 'sgGroupName': sgGroupName})
return msg
return foundStorageGroupInstanceName
- def _find_port_group(self, conn, controllerConfigService, portGroupName):
+ def find_port_group(self, conn, controllerConfigService, portGroupName):
"""Given the port Group name get the port group instance name.
:param conn: connection to the ecom server
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
- LOG.info(_LI("Created new masking view : %(maskingViewName)s."),
- {'maskingViewName': maskingViewName})
+ LOG.info(_LI(
+ "Created new masking view : %(maskingViewName)s."),
+ {'maskingViewName': maskingViewName})
return rc, job
def find_new_masking_view(self, conn, jobDict):
:param pgGroupName: the port group name
:returns: instance name foundPortGroupInstanceName
"""
- foundPortGroupInstanceName = self._find_port_group(
+ foundPortGroupInstanceName = self.find_port_group(
conn, controllerConfigService, pgGroupName)
if foundPortGroupInstanceName is None:
LOG.error(_LE(
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
else:
- LOG.debug("Masking view %(maskingViewName)s "
- "successfully deleted.",
- {'maskingViewName': maskingViewName})
+ LOG.info(_LI(
+ "Masking view %(maskingViewName)s successfully deleted."),
+ {'maskingViewName': maskingViewName})
def _get_and_remove_rule_association(
self, conn, fastPolicyName, isTieringPolicySupported,
tierPolicyInstanceName = self.fast.get_tier_policy_by_name(
conn, storageSystemName, fastPolicyName)
- LOG.info(_LI(
+ LOG.debug(
"Policy: %(policy)s, policy service:%(service)s, "
- "masking group: %(maskingGroup)s."),
+ "masking group: %(maskingGroup)s.",
{'policy': tierPolicyInstanceName,
'service': tierPolicyServiceInstanceName,
'maskingGroup': storageGroupInstanceName})
raise exception.VolumeBackendAPIException(
data=exceptionMessage)
else:
- LOG.debug("Storage Group %(storageGroupName)s "
- "successfully deleted.",
- {'storageGroupName': storageGroupName})
+ LOG.info(_LI(
+ "Storage Group %(storageGroupName)s successfully deleted."),
+ {'storageGroupName': storageGroupName})
def _delete_storage_group(self, conn, controllerConfigService,
storageGroupInstanceName, storageGroupName,
'last': poolName[-7:]}))
else:
return poolName
+
+ def get_iscsi_protocol_endpoints(self, conn, portgroupinstancename):
+ """Get the iscsi protocol endpoints of a port group.
+
+ :param conn: the ecom connection
+ :param portgroupinstancename: the portgroup instance name
+ :returns: iscsiendpoints
+ """
+ iscsiendpoints = conn.AssociatorNames(
+ portgroupinstancename,
+ AssocClass='CIM_MemberOfCollection')
+ return iscsiendpoints
+
+ def get_tcp_protocol_endpoints(self, conn, iscsiendpointinstancename):
+ """Get the tcp protocol endpoints associated with an iscsi endpoint
+
+ :param conn: the ecom connection
+ :param iscsiendpointinstancename: the iscsi endpoint instance name
+ :returns: tcpendpoints
+ """
+ tcpendpoints = conn.AssociatorNames(
+ iscsiendpointinstancename,
+ AssocClass='CIM_BindsTo')
+ return tcpendpoints
+
+ def get_ip_protocol_endpoints(self, conn, tcpendpointinstancename):
+ """Get the ip protocol endpoints associated with an tcp endpoint
+
+ :param conn: the ecom connection
+ :param tcpendpointinstancename: the tcp endpoint instance name
+ :returns: ipendpoints
+ """
+ ipendpoints = conn.AssociatorNames(
+ tcpendpointinstancename,
+ AssocClass='CIM_BindsTo')
+ return ipendpoints
+
+ def get_iscsi_ip_address(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: foundIpAddress
+ """
+ foundIpAddress = None
+ ipendpointinstance = conn.GetInstance(ipendpointinstancename)
+ propertiesList = ipendpointinstance.properties.items()
+ for properties in propertiesList:
+ if properties[0] == 'IPv4Address':
+ cimProperties = properties[1]
+ foundIpAddress = cimProperties.value
+ return foundIpAddress