2870a28740
This patch fixed the following issues in EMC driver found during G3 testing: 1. VNX array has two storage processors and it is doing load balancing when attaching a LUN to a host. The storage processor used to attach a LUN to a host is different from the one discovered by the driver sometimes, causing Copy Image to Volume to fail. 2. The clone relationship is removed after a volume is successfully cloned. However, this happens too soon sometimes before the cloned volume is fully synced with the source volume. The fix is to wait until it is fully synced. Change-Id: I5b8fab263723c47faf30b950a611c5bde7f29092 Fixes: bug #1135221
758 lines
28 KiB
Python
758 lines
28 KiB
Python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
|
|
|
# Copyright (c) 2012 EMC Corporation, Inc.
|
|
# Copyright (c) 2012 OpenStack LLC.
|
|
# All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
|
|
import mox
|
|
import os
|
|
import shutil
|
|
import tempfile
|
|
from xml.dom.minidom import Document
|
|
|
|
from cinder import exception
|
|
from cinder import flags
|
|
from cinder.openstack.common import log as logging
|
|
from cinder import test
|
|
from cinder.volume import configuration as conf
|
|
from cinder.volume.drivers.emc.emc_smis_common import EMCSMISCommon
|
|
from cinder.volume.drivers.emc.emc_smis_iscsi import EMCSMISISCSIDriver
|
|
|
|
CINDER_EMC_CONFIG_FILE = '/etc/cinder/cinder_emc_config.xml'
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
config_file_name = 'cinder_emc_config.xml'
|
|
storage_system = 'CLARiiON+APM00123456789'
|
|
storage_system_vmax = 'SYMMETRIX+000195900551'
|
|
lunmaskctrl_id = 'CLARiiON+APM00123456789+00aa11bb22cc33dd44ff55gg66hh77ii88jj'
|
|
initiator1 = 'iqn.1993-08.org.debian:01:1a2b3c4d5f6g'
|
|
stconf_service_creationclass = 'Clar_StorageConfigurationService'
|
|
ctrlconf_service_creationclass = 'Clar_ControllerConfigurationService'
|
|
rep_service_creationclass = 'Clar_ReplicationService'
|
|
vol_creationclass = 'Clar_StorageVolume'
|
|
pool_creationclass = 'Clar_UnifiedStoragePool'
|
|
lunmask_creationclass = 'Clar_LunMaskingSCSIProtocolController'
|
|
unit_creationclass = 'CIM_ProtocolControllerForUnit'
|
|
storage_type = 'gold'
|
|
|
|
test_volume = {'name': 'vol1',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '1',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'vol1',
|
|
'display_description': 'test volume',
|
|
'volume_type_id': None}
|
|
test_failed_volume = {'name': 'failed_vol',
|
|
'size': 1,
|
|
'volume_name': 'failed_vol',
|
|
'id': '4',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'failed_vol',
|
|
'display_description': 'test failed volume',
|
|
'volume_type_id': None}
|
|
test_snapshot = {'name': 'snapshot1',
|
|
'size': 1,
|
|
'id': '4444',
|
|
'volume_name': 'vol1',
|
|
'volume_size': 1,
|
|
'project_id': 'project'}
|
|
test_clone = {'name': 'clone1',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '2',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'clone1',
|
|
'display_description': 'volume created from snapshot',
|
|
'volume_type_id': None}
|
|
test_clone3 = {'name': 'clone3',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '3',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'clone3',
|
|
'display_description': 'cloned volume',
|
|
'volume_type_id': None}
|
|
test_snapshot_vmax = {'name': 'snapshot_vmax',
|
|
'size': 1,
|
|
'id': '4445',
|
|
'volume_name': 'vol1',
|
|
'volume_size': 1,
|
|
'project_id': 'project'}
|
|
failed_snapshot_replica = {'name': 'failed_snapshot_replica',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '5',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'vol1',
|
|
'display_description': 'failed snapshot replica',
|
|
'volume_type_id': None}
|
|
failed_snapshot_sync = {'name': 'failed_snapshot_sync',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '6',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'failed_snapshot_sync',
|
|
'display_description': 'failed snapshot sync',
|
|
'volume_type_id': None}
|
|
failed_clone_replica = {'name': 'failed_clone_replica',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '7',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'vol1',
|
|
'display_description': 'failed clone replica',
|
|
'volume_type_id': None}
|
|
failed_clone_sync = {'name': 'failed_clone_sync',
|
|
'size': 1,
|
|
'volume_name': 'vol1',
|
|
'id': '8',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'vol1',
|
|
'display_description': 'failed clone sync',
|
|
'volume_type_id': None}
|
|
failed_delete_vol = {'name': 'failed_delete_vol',
|
|
'size': 1,
|
|
'volume_name': 'failed_delete_vol',
|
|
'id': '99999',
|
|
'provider_auth': None,
|
|
'project_id': 'project',
|
|
'display_name': 'failed delete vol',
|
|
'display_description': 'failed delete volume',
|
|
'volume_type_id': None}
|
|
|
|
|
|
class EMC_StorageVolume(dict):
|
|
pass
|
|
|
|
|
|
class SE_ConcreteJob(dict):
|
|
pass
|
|
|
|
|
|
class FakeEcomConnection():
|
|
|
|
def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None,
|
|
ElementType=None, Size=None,
|
|
SyncType=None, SourceElement=None,
|
|
Operation=None, Synchronization=None,
|
|
TheElements=None,
|
|
LUNames=None, InitiatorPortIDs=None, DeviceAccesses=None,
|
|
ProtocolControllers=None,
|
|
MaskingGroup=None, Members=None):
|
|
|
|
rc = 0L
|
|
myjob = SE_ConcreteJob()
|
|
myjob.classname = 'SE_ConcreteJob'
|
|
myjob['InstanceID'] = '9999'
|
|
myjob['status'] = 'success'
|
|
if ElementName == 'failed_vol' and \
|
|
MethodName == 'CreateOrModifyElementFromStoragePool':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
elif ElementName == 'failed_snapshot_replica' and \
|
|
MethodName == 'CreateElementReplica':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
elif Synchronization and \
|
|
Synchronization['SyncedElement']['ElementName'] \
|
|
== 'failed_snapshot_sync' and \
|
|
MethodName == 'ModifyReplicaSynchronization':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
elif ElementName == 'failed_clone_replica' and \
|
|
MethodName == 'CreateElementReplica':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
elif Synchronization and \
|
|
Synchronization['SyncedElement']['ElementName'] \
|
|
== 'failed_clone_sync' and \
|
|
MethodName == 'ModifyReplicaSynchronization':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
elif TheElements and \
|
|
TheElements[0]['DeviceID'] == '99999' and \
|
|
MethodName == 'EMCReturnToStoragePool':
|
|
rc = 10L
|
|
myjob['status'] = 'failure'
|
|
|
|
job = {'Job': myjob}
|
|
return rc, job
|
|
|
|
def EnumerateInstanceNames(self, name):
|
|
result = None
|
|
if name == 'EMC_ReplicationService':
|
|
result = self._enum_replicationservices()
|
|
elif name == 'EMC_StorageConfigurationService':
|
|
result = self._enum_stconfsvcs()
|
|
elif name == 'EMC_ControllerConfigurationService':
|
|
result = self._enum_ctrlconfsvcs()
|
|
elif name == 'EMC_VirtualProvisioningPool':
|
|
result = self._enum_pools()
|
|
elif name == 'EMC_UnifiedStoragePool':
|
|
result = self._enum_pools()
|
|
elif name == 'EMC_StorageVolume':
|
|
result = self._enum_storagevolumes()
|
|
elif name == 'Clar_StorageVolume':
|
|
result = self._enum_storagevolumes()
|
|
elif name == 'SE_StorageSynchronized_SV_SV':
|
|
result = self._enum_syncsvsvs()
|
|
elif name == 'CIM_ProtocolControllerForUnit':
|
|
result = self._enum_unitnames()
|
|
elif name == 'EMC_LunMaskingSCSIProtocolController':
|
|
result = self._enum_lunmaskctrls()
|
|
else:
|
|
result = self._default_enum()
|
|
return result
|
|
|
|
def EnumerateInstances(self, name):
|
|
result = None
|
|
if name == 'EMC_VirtualProvisioningPool':
|
|
result = self._enum_pool_details()
|
|
elif name == 'EMC_UnifiedStoragePool':
|
|
result = self._enum_pool_details()
|
|
else:
|
|
result = self._default_enum()
|
|
return result
|
|
|
|
def GetInstance(self, objectpath, LocalOnly=False):
|
|
try:
|
|
name = objectpath['CreationClassName']
|
|
except KeyError:
|
|
name = objectpath.classname
|
|
result = None
|
|
if name == 'Clar_StorageVolume':
|
|
result = self._getinstance_storagevolume(objectpath)
|
|
elif name == 'CIM_ProtocolControllerForUnit':
|
|
result = self._getinstance_unit(objectpath)
|
|
elif name == 'Clar_LunMaskingSCSIProtocolController':
|
|
result = self._getinstance_lunmask()
|
|
elif name == 'SE_ConcreteJob':
|
|
result = self._getinstance_job(objectpath)
|
|
elif name == 'SE_StorageSynchronized_SV_SV':
|
|
result = self._getinstance_syncsvsv(objectpath)
|
|
else:
|
|
result = self._default_getinstance(objectpath)
|
|
return result
|
|
|
|
def Associators(self, objectpath, resultClass='EMC_StorageHardwareID'):
|
|
result = None
|
|
if resultClass == 'EMC_StorageHardwareID':
|
|
result = self._assoc_hdwid()
|
|
else:
|
|
result = self._default_assoc(objectpath)
|
|
return result
|
|
|
|
def AssociatorNames(self, objectpath,
|
|
resultClass='EMC_LunMaskingSCSIProtocolController'):
|
|
result = None
|
|
if resultClass == 'EMC_LunMaskingSCSIProtocolController':
|
|
result = self._assocnames_lunmaskctrl()
|
|
else:
|
|
result = self._default_assocnames(objectpath)
|
|
return result
|
|
|
|
def ReferenceNames(self, objectpath,
|
|
ResultClass='CIM_ProtocolControllerForUnit'):
|
|
result = None
|
|
if ResultClass == 'CIM_ProtocolControllerForUnit':
|
|
result = self._ref_unitnames()
|
|
else:
|
|
result = self._default_ref(objectpath)
|
|
return result
|
|
|
|
def _ref_unitnames(self):
|
|
units = []
|
|
unit = {}
|
|
|
|
dependent = {}
|
|
dependent['CreationClassName'] = vol_creationclass
|
|
dependent['DeviceID'] = test_volume['id']
|
|
dependent['ElementName'] = test_volume['name']
|
|
dependent['SystemName'] = storage_system
|
|
|
|
antecedent = {}
|
|
antecedent['CreationClassName'] = lunmask_creationclass
|
|
antecedent['DeviceID'] = lunmaskctrl_id
|
|
antecedent['SystemName'] = storage_system
|
|
|
|
unit['Dependent'] = dependent
|
|
unit['Antecedent'] = antecedent
|
|
unit['CreationClassName'] = unit_creationclass
|
|
units.append(unit)
|
|
|
|
return units
|
|
|
|
def _default_ref(self, objectpath):
|
|
return objectpath
|
|
|
|
def _assoc_hdwid(self):
|
|
assocs = []
|
|
assoc = {}
|
|
assoc['StorageID'] = initiator1
|
|
assocs.append(assoc)
|
|
return assocs
|
|
|
|
def _default_assoc(self, objectpath):
|
|
return objectpath
|
|
|
|
def _assocnames_lunmaskctrl(self):
|
|
return self._enum_lunmaskctrls()
|
|
|
|
def _default_assocnames(self, objectpath):
|
|
return objectpath
|
|
|
|
def _getinstance_storagevolume(self, objectpath):
|
|
instance = EMC_StorageVolume()
|
|
vols = self._enum_storagevolumes()
|
|
for vol in vols:
|
|
if vol['DeviceID'] == objectpath['DeviceID']:
|
|
instance = vol
|
|
break
|
|
return instance
|
|
|
|
def _getinstance_syncsvsv(self, objectpath):
|
|
foundsync = None
|
|
syncs = self._enum_syncsvsvs()
|
|
for sync in syncs:
|
|
if (sync['SyncedElement'] == objectpath['SyncedElement'] and
|
|
sync['SystemElement'] == objectpath['SystemElement']):
|
|
foundsync = sync
|
|
break
|
|
return foundsync
|
|
|
|
def _getinstance_lunmask(self):
|
|
lunmask = {}
|
|
lunmask['CreationClassName'] = lunmask_creationclass
|
|
lunmask['DeviceID'] = lunmaskctrl_id
|
|
lunmask['SystemName'] = storage_system
|
|
return lunmask
|
|
|
|
def _getinstance_unit(self, objectpath):
|
|
unit = {}
|
|
|
|
dependent = {}
|
|
dependent['CreationClassName'] = vol_creationclass
|
|
dependent['DeviceID'] = test_volume['id']
|
|
dependent['ElementName'] = test_volume['name']
|
|
dependent['SystemName'] = storage_system
|
|
|
|
antecedent = {}
|
|
antecedent['CreationClassName'] = lunmask_creationclass
|
|
antecedent['DeviceID'] = lunmaskctrl_id
|
|
antecedent['SystemName'] = storage_system
|
|
|
|
unit['Dependent'] = dependent
|
|
unit['Antecedent'] = antecedent
|
|
unit['CreationClassName'] = unit_creationclass
|
|
unit['DeviceNumber'] = '0'
|
|
|
|
return unit
|
|
|
|
def _getinstance_job(self, jobpath):
|
|
jobinstance = {}
|
|
jobinstance['InstanceID'] = '9999'
|
|
if jobpath['status'] == 'failure':
|
|
jobinstance['JobState'] = 10
|
|
jobinstance['ErrorCode'] = 99
|
|
jobinstance['ErrorDescription'] = 'Failure'
|
|
else:
|
|
jobinstance['JobState'] = 7
|
|
jobinstance['ErrorCode'] = 0
|
|
jobinstance['ErrorDescription'] = ''
|
|
return jobinstance
|
|
|
|
def _default_getinstance(self, objectpath):
|
|
return objectpath
|
|
|
|
def _enum_replicationservices(self):
|
|
rep_services = []
|
|
rep_service = {}
|
|
rep_service['SystemName'] = storage_system
|
|
rep_service['CreationClassName'] = rep_service_creationclass
|
|
rep_services.append(rep_service)
|
|
return rep_services
|
|
|
|
def _enum_stconfsvcs(self):
|
|
conf_services = []
|
|
conf_service = {}
|
|
conf_service['SystemName'] = storage_system
|
|
conf_service['CreationClassName'] = stconf_service_creationclass
|
|
conf_services.append(conf_service)
|
|
return conf_services
|
|
|
|
def _enum_ctrlconfsvcs(self):
|
|
conf_services = []
|
|
conf_service = {}
|
|
conf_service['SystemName'] = storage_system
|
|
conf_service['CreationClassName'] = ctrlconf_service_creationclass
|
|
conf_services.append(conf_service)
|
|
return conf_services
|
|
|
|
def _enum_pools(self):
|
|
pools = []
|
|
pool = {}
|
|
pool['InstanceID'] = storage_system + '+U+' + storage_type
|
|
pool['CreationClassName'] = 'Clar_UnifiedStoragePool'
|
|
pools.append(pool)
|
|
return pools
|
|
|
|
def _enum_pool_details(self):
|
|
pools = []
|
|
pool = {}
|
|
pool['InstanceID'] = storage_system + '+U+' + storage_type
|
|
pool['CreationClassName'] = 'Clar_UnifiedStoragePool'
|
|
pool['TotalManagedSpace'] = 12345678
|
|
pool['RemainingManagedSpace'] = 123456
|
|
pools.append(pool)
|
|
return pools
|
|
|
|
def _enum_storagevolumes(self):
|
|
vols = []
|
|
vol = EMC_StorageVolume()
|
|
vol['CreationClassName'] = 'Clar_StorageVolume'
|
|
vol['ElementName'] = test_volume['name']
|
|
vol['DeviceID'] = test_volume['id']
|
|
vol['SystemName'] = storage_system
|
|
vol.path = {'DeviceID': vol['DeviceID']}
|
|
vols.append(vol)
|
|
|
|
snap_vol = EMC_StorageVolume()
|
|
snap_vol['CreationClassName'] = 'Clar_StorageVolume'
|
|
snap_vol['ElementName'] = test_snapshot['name']
|
|
snap_vol['DeviceID'] = test_snapshot['id']
|
|
snap_vol['SystemName'] = storage_system
|
|
snap_vol.path = {'DeviceID': snap_vol['DeviceID']}
|
|
vols.append(snap_vol)
|
|
|
|
clone_vol = EMC_StorageVolume()
|
|
clone_vol['CreationClassName'] = 'Clar_StorageVolume'
|
|
clone_vol['ElementName'] = test_clone['name']
|
|
clone_vol['DeviceID'] = test_clone['id']
|
|
clone_vol['SystemName'] = storage_system
|
|
clone_vol.path = {'DeviceID': clone_vol['DeviceID']}
|
|
vols.append(clone_vol)
|
|
|
|
clone_vol3 = EMC_StorageVolume()
|
|
clone_vol3['CreationClassName'] = 'Clar_StorageVolume'
|
|
clone_vol3['ElementName'] = test_clone3['name']
|
|
clone_vol3['DeviceID'] = test_clone3['id']
|
|
clone_vol3['SystemName'] = storage_system
|
|
clone_vol3.path = {'DeviceID': clone_vol3['DeviceID']}
|
|
vols.append(clone_vol3)
|
|
|
|
snap_vol_vmax = EMC_StorageVolume()
|
|
snap_vol_vmax['CreationClassName'] = 'Symm_StorageVolume'
|
|
snap_vol_vmax['ElementName'] = test_snapshot_vmax['name']
|
|
snap_vol_vmax['DeviceID'] = test_snapshot_vmax['id']
|
|
snap_vol_vmax['SystemName'] = storage_system_vmax
|
|
snap_vol_vmax.path = {'DeviceID': snap_vol_vmax['DeviceID']}
|
|
vols.append(snap_vol_vmax)
|
|
|
|
failed_snap_replica = EMC_StorageVolume()
|
|
failed_snap_replica['CreationClassName'] = 'Clar_StorageVolume'
|
|
failed_snap_replica['ElementName'] = failed_snapshot_replica['name']
|
|
failed_snap_replica['DeviceID'] = failed_snapshot_replica['id']
|
|
failed_snap_replica['SystemName'] = storage_system
|
|
failed_snap_replica.path = {
|
|
'DeviceID': failed_snap_replica['DeviceID']}
|
|
vols.append(failed_snap_replica)
|
|
|
|
failed_snap_sync = EMC_StorageVolume()
|
|
failed_snap_sync['CreationClassName'] = 'Clar_StorageVolume'
|
|
failed_snap_sync['ElementName'] = failed_snapshot_sync['name']
|
|
failed_snap_sync['DeviceID'] = failed_snapshot_sync['id']
|
|
failed_snap_sync['SystemName'] = storage_system
|
|
failed_snap_sync.path = {
|
|
'DeviceID': failed_snap_sync['DeviceID']}
|
|
vols.append(failed_snap_sync)
|
|
|
|
failed_clone_rep = EMC_StorageVolume()
|
|
failed_clone_rep['CreationClassName'] = 'Clar_StorageVolume'
|
|
failed_clone_rep['ElementName'] = failed_clone_replica['name']
|
|
failed_clone_rep['DeviceID'] = failed_clone_replica['id']
|
|
failed_clone_rep['SystemName'] = storage_system
|
|
failed_clone_rep.path = {
|
|
'DeviceID': failed_clone_rep['DeviceID']}
|
|
vols.append(failed_clone_rep)
|
|
|
|
failed_clone_s = EMC_StorageVolume()
|
|
failed_clone_s['CreationClassName'] = 'Clar_StorageVolume'
|
|
failed_clone_s['ElementName'] = failed_clone_sync['name']
|
|
failed_clone_s['DeviceID'] = failed_clone_sync['id']
|
|
failed_clone_s['SystemName'] = storage_system
|
|
failed_clone_s.path = {
|
|
'DeviceID': failed_clone_s['DeviceID']}
|
|
vols.append(failed_clone_s)
|
|
|
|
failed_delete_vol = EMC_StorageVolume()
|
|
failed_delete_vol['CreationClassName'] = 'Clar_StorageVolume'
|
|
failed_delete_vol['ElementName'] = 'failed_delete_vol'
|
|
failed_delete_vol['DeviceID'] = '99999'
|
|
failed_delete_vol['SystemName'] = storage_system
|
|
failed_delete_vol.path = {'DeviceID': failed_delete_vol['DeviceID']}
|
|
vols.append(failed_delete_vol)
|
|
|
|
return vols
|
|
|
|
def _enum_syncsvsvs(self):
|
|
syncs = []
|
|
|
|
vols = self._enum_storagevolumes()
|
|
|
|
sync = self._create_sync(vols[0], vols[1], 100)
|
|
syncs.append(sync)
|
|
|
|
sync2 = self._create_sync(vols[1], vols[2], 100)
|
|
syncs.append(sync2)
|
|
|
|
sync3 = self._create_sync(vols[0], vols[3], 100)
|
|
syncs.append(sync3)
|
|
|
|
objpath1 = vols[1]
|
|
for vol in vols:
|
|
if vol['ElementName'] == 'failed_snapshot_sync':
|
|
objpath2 = vol
|
|
break
|
|
sync4 = self._create_sync(objpath1, objpath2, 100)
|
|
syncs.append(sync4)
|
|
|
|
objpath1 = vols[0]
|
|
for vol in vols:
|
|
if vol['ElementName'] == 'failed_clone_sync':
|
|
objpath2 = vol
|
|
break
|
|
sync5 = self._create_sync(objpath1, objpath2, 100)
|
|
syncs.append(sync5)
|
|
|
|
return syncs
|
|
|
|
def _create_sync(self, objpath1, objpath2, percentsynced):
|
|
sync = {}
|
|
sync['SyncedElement'] = objpath2
|
|
sync['SystemElement'] = objpath1
|
|
sync['CreationClassName'] = 'SE_StorageSynchronized_SV_SV'
|
|
sync['PercentSynced'] = percentsynced
|
|
return sync
|
|
|
|
def _enum_unitnames(self):
|
|
return self._ref_unitnames()
|
|
|
|
def _enum_lunmaskctrls(self):
|
|
ctrls = []
|
|
ctrl = {}
|
|
ctrl['CreationClassName'] = lunmask_creationclass
|
|
ctrl['DeviceID'] = lunmaskctrl_id
|
|
ctrl['SystemName'] = storage_system
|
|
ctrls.append(ctrl)
|
|
return ctrls
|
|
|
|
def _default_enum(self):
|
|
names = []
|
|
name = {}
|
|
name['Name'] = 'default'
|
|
names.append(name)
|
|
return names
|
|
|
|
|
|
class EMCSMISISCSIDriverTestCase(test.TestCase):
|
|
|
|
def setUp(self):
|
|
self.tempdir = tempfile.mkdtemp()
|
|
super(EMCSMISISCSIDriverTestCase, self).setUp()
|
|
self.config_file_path = None
|
|
self.create_fake_config_file()
|
|
|
|
configuration = mox.MockObject(conf.Configuration)
|
|
configuration.cinder_emc_config_file = self.config_file_path
|
|
configuration.append_config_values(mox.IgnoreArg())
|
|
|
|
self.stubs.Set(EMCSMISISCSIDriver, '_get_iscsi_properties',
|
|
self.fake_get_iscsi_properties)
|
|
self.stubs.Set(EMCSMISCommon, '_get_ecom_connection',
|
|
self.fake_ecom_connection)
|
|
driver = EMCSMISISCSIDriver(configuration=configuration)
|
|
self.driver = driver
|
|
|
|
def create_fake_config_file(self):
|
|
doc = Document()
|
|
emc = doc.createElement("EMC")
|
|
doc.appendChild(emc)
|
|
|
|
storagetype = doc.createElement("StorageType")
|
|
storagetypetext = doc.createTextNode("gold")
|
|
emc.appendChild(storagetype)
|
|
storagetype.appendChild(storagetypetext)
|
|
|
|
ecomserverip = doc.createElement("EcomServerIp")
|
|
ecomserveriptext = doc.createTextNode("1.1.1.1")
|
|
emc.appendChild(ecomserverip)
|
|
ecomserverip.appendChild(ecomserveriptext)
|
|
|
|
ecomserverport = doc.createElement("EcomServerPort")
|
|
ecomserverporttext = doc.createTextNode("10")
|
|
emc.appendChild(ecomserverport)
|
|
ecomserverport.appendChild(ecomserverporttext)
|
|
|
|
ecomusername = doc.createElement("EcomUserName")
|
|
ecomusernametext = doc.createTextNode("user")
|
|
emc.appendChild(ecomusername)
|
|
ecomusername.appendChild(ecomusernametext)
|
|
|
|
ecompassword = doc.createElement("EcomPassword")
|
|
ecompasswordtext = doc.createTextNode("pass")
|
|
emc.appendChild(ecompassword)
|
|
ecompassword.appendChild(ecompasswordtext)
|
|
|
|
self.config_file_path = self.tempdir + '/' + config_file_name
|
|
f = open(self.config_file_path, 'w')
|
|
doc.writexml(f)
|
|
f.close()
|
|
|
|
def fake_ecom_connection(self):
|
|
conn = FakeEcomConnection()
|
|
return conn
|
|
|
|
def fake_get_iscsi_properties(self, volume):
|
|
LOG.info('Fake _get_iscsi_properties.')
|
|
properties = {}
|
|
properties['target_discovered'] = True
|
|
properties['target_portal'] = '10.10.10.10'
|
|
properties['target_iqn'] = 'iqn.1993-08.org.debian:01:a1b2c3d4e5f6'
|
|
device_number = '000008'
|
|
properties['target_lun'] = device_number
|
|
properties['volume_id'] = volume['id']
|
|
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
|
|
LOG.info(_("Fake ISCSI properties: %s") % (properties))
|
|
return properties
|
|
|
|
def test_get_volume_stats(self):
|
|
self.driver.get_volume_stats(True)
|
|
|
|
def test_create_destroy(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_snapshot_destroy(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.driver.create_snapshot(test_snapshot)
|
|
self.driver.create_volume_from_snapshot(
|
|
test_clone, test_snapshot)
|
|
self.driver.create_cloned_volume(
|
|
test_clone3, test_volume)
|
|
self.driver.delete_volume(test_clone)
|
|
self.driver.delete_volume(test_clone3)
|
|
self.driver.delete_snapshot(test_snapshot)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_map_unmap(self):
|
|
self.driver.create_volume(test_volume)
|
|
export = self.driver.create_export(None, test_volume)
|
|
test_volume['provider_location'] = export['provider_location']
|
|
test_volume['EMCCurrentOwningStorageProcessor'] = \
|
|
'iqn.1993-08.org.debian:01:a1b2c3d4e5f6'
|
|
connector = {'initiator': initiator1}
|
|
connection_info = self.driver.initialize_connection(test_volume,
|
|
connector)
|
|
self.driver.terminate_connection(test_volume, connector)
|
|
self.driver.remove_export(None, test_volume)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_failed(self):
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_volume,
|
|
test_failed_volume)
|
|
|
|
def test_create_volume_snapshot_unsupported(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.driver.create_snapshot(test_snapshot_vmax)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_volume_from_snapshot,
|
|
test_clone,
|
|
test_snapshot_vmax)
|
|
self.driver.delete_snapshot(test_snapshot_vmax)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_snapshot_replica_failed(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.driver.create_snapshot(test_snapshot)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_volume_from_snapshot,
|
|
failed_snapshot_replica,
|
|
test_snapshot)
|
|
self.driver.delete_snapshot(test_snapshot)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_snapshot_sync_failed(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.driver.create_snapshot(test_snapshot)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_volume_from_snapshot,
|
|
failed_snapshot_sync,
|
|
test_snapshot)
|
|
self.driver.delete_snapshot(test_snapshot)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_clone_replica_failed(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_cloned_volume,
|
|
failed_clone_replica,
|
|
test_volume)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_create_volume_clone_sync_failed(self):
|
|
self.driver.create_volume(test_volume)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.create_cloned_volume,
|
|
failed_clone_sync,
|
|
test_volume)
|
|
self.driver.delete_volume(test_volume)
|
|
|
|
def test_delete_volume_notfound(self):
|
|
notfound_delete_vol = {}
|
|
notfound_delete_vol['name'] = 'notfound_delete_vol'
|
|
notfound_delete_vol['id'] = '10'
|
|
self.driver.delete_volume(notfound_delete_vol)
|
|
|
|
def test_delete_volume_failed(self):
|
|
self.driver.create_volume(failed_delete_vol)
|
|
self.assertRaises(exception.VolumeBackendAPIException,
|
|
self.driver.delete_volume,
|
|
failed_delete_vol)
|
|
|
|
def _cleanup(self):
|
|
bExists = os.path.exists(self.config_file_path)
|
|
if bExists:
|
|
os.remove(self.config_file_path)
|
|
shutil.rmtree(self.tempdir)
|
|
|
|
def tearDown(self):
|
|
self._cleanup()
|
|
super(EMCSMISISCSIDriverTestCase, self).tearDown()
|