-
-# Copyright (c) 2012 EMC Corporation, Inc.
-# Copyright (c) 2012 OpenStack Foundation
+# Copyright (c) 2012 - 2014 EMC Corporation, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# License for the specific language governing permissions and limitations
# under the License.
+
import os
import shutil
import tempfile
from xml.dom.minidom import Document
-import mox
+import mock
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import test
-from cinder.volume import configuration as conf
+from cinder import units
from cinder.volume.drivers.emc.emc_smis_common import EMCSMISCommon
+from cinder.volume.drivers.emc.emc_smis_fc import EMCSMISFCDriver
from cinder.volume.drivers.emc.emc_smis_iscsi import EMCSMISISCSIDriver
-
+from cinder.volume import volume_types
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
pass
+class SE_StorageHardwareID(dict):
+ pass
+
+
+class FakeCIMInstanceName(dict):
+
+ def fake_getinstancename(self, classname, bindings):
+ instancename = FakeCIMInstanceName()
+ for key in bindings:
+ instancename[key] = bindings[key]
+ instancename.classname = classname
+ instancename.namespace = 'root/emc'
+ return instancename
+
+
+class FakeDB():
+ def volume_update(self, context, volume_id, model_update):
+ pass
+
+ def snapshot_update(self, context, snapshot_id, model_update):
+ pass
+
+ def volume_get(self, context, volume_id):
+ conn = FakeEcomConnection()
+ objectpath = {}
+ objectpath['CreationClassName'] = 'Clar_StorageVolume'
+ if volume_id == 'vol1':
+ device_id = '1'
+ objectpath['DeviceID'] = device_id
+ else:
+ objectpath['DeviceID'] = volume_id
+ return conn.GetInstance(objectpath)
+
+
+class EMCSMISCommonData():
+ connector = {'ip': '10.0.0.2',
+ 'initiator': 'iqn.1993-08.org.debian:01:222',
+ 'wwpns': ["123456789012345", "123456789054321"],
+ 'wwnns': ["223456789012345", "223456789054321"],
+ 'host': 'fakehost'}
+
+ 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': 'vol-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': 'vol-vol1',
+ 'volume_size': 1,
+ 'project_id': 'project'}
+ failed_snapshot_replica = {'name': 'failed_snapshot_replica',
+ 'size': 1,
+ 'volume_name': 'vol-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': 'vol-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}
+ failed_extend_vol = {'name': 'failed_extend_vol',
+ 'size': 1,
+ 'volume_name': 'failed_extend_vol',
+ 'id': '9',
+ 'provider_auth': None,
+ 'project_id': 'project',
+ 'display_name': 'failed_extend_vol',
+ 'display_description': 'test failed extend volume',
+ 'volume_type_id': None}
+
+
class FakeEcomConnection():
+ def __init__(self, *args, **kwargs):
+ self.data = EMCSMISCommonData()
+
def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None,
ElementType=None, Size=None,
SyncType=None, SourceElement=None,
Operation=None, Synchronization=None,
- TheElements=None,
+ TheElements=None, TheElement=None,
LUNames=None, InitiatorPortIDs=None, DeviceAccesses=None,
ProtocolControllers=None,
- MaskingGroup=None, Members=None):
+ MaskingGroup=None, Members=None,
+ HardwareId=None):
rc = 0L
myjob = SE_ConcreteJob()
myjob.classname = 'SE_ConcreteJob'
myjob['InstanceID'] = '9999'
myjob['status'] = 'success'
+ myjob['type'] = ElementName
if ElementName == 'failed_vol' and \
MethodName == 'CreateOrModifyElementFromStoragePool':
rc = 10L
myjob['status'] = 'failure'
+ elif TheElement and TheElement['ElementName'] == 'failed_extend_vol' \
+ and MethodName == 'CreateOrModifyElementFromStoragePool':
+ rc = 10L
+ myjob['status'] = 'failure'
+ elif MethodName == 'CreateOrModifyElementFromStoragePool':
+ rc = 0L
+ myjob['status'] = 'success'
elif ElementName == 'failed_snapshot_replica' and \
MethodName == 'CreateElementReplica':
rc = 10L
MethodName == 'EMCReturnToStoragePool':
rc = 10L
myjob['status'] = 'failure'
+ elif HardwareId:
+ rc = 0L
+ targetendpoints = {}
+ endpoints = []
+ endpoint = {}
+ endpoint['Name'] = '1234567890123'
+ endpoints.append(endpoint)
+ endpoint2 = {}
+ endpoint2['Name'] = '0987654321321'
+ endpoints.append(endpoint2)
+ targetendpoints['TargetEndpoints'] = endpoints
+ return rc, targetendpoints
job = {'Job': myjob}
return rc, job
result = self._enum_lunmaskctrls()
elif name == 'EMC_StorageProcessorSystem':
result = self._enum_processors()
+ elif name == 'EMC_StorageHardwareIDManagementService':
+ result = self._enum_hdwidmgmts()
else:
result = self._default_enum()
return result
result = self._enum_pool_details()
elif name == 'EMC_UnifiedStoragePool':
result = self._enum_pool_details()
+ elif name == 'SE_StorageHardwareID':
+ result = self._enum_storhdwids()
else:
result = self._default_enum()
return result
except KeyError:
name = objectpath.classname
result = None
- if name == 'Clar_StorageVolume':
+ if name == 'Clar_StorageVolume' or name == 'Symm_StorageVolume':
result = self._getinstance_storagevolume(objectpath)
elif name == 'CIM_ProtocolControllerForUnit':
result = self._getinstance_unit(objectpath)
result = self._assoc_hdwid()
elif resultClass == 'EMC_iSCSIProtocolEndpoint':
result = self._assoc_endpoint()
+ # Added test for EMC_StorageVolume
+ elif resultClass == 'EMC_StorageVolume':
+ result = self._assoc_storagevolume(objectpath)
else:
result = self._default_assoc(objectpath)
return result
return result
def _ref_unitnames(self):
- units = []
- unit = {}
+ unitnames = []
+ unitname = {}
dependent = {}
- dependent['CreationClassName'] = vol_creationclass
- dependent['DeviceID'] = test_volume['id']
- dependent['ElementName'] = test_volume['name']
- dependent['SystemName'] = storage_system
+ dependent['CreationClassName'] = self.data.vol_creationclass
+ dependent['DeviceID'] = self.data.test_volume['id']
+ dependent['ElementName'] = self.data.test_volume['name']
+ dependent['SystemName'] = self.data.storage_system
antecedent = {}
- antecedent['CreationClassName'] = lunmask_creationclass
- antecedent['DeviceID'] = lunmaskctrl_id
- antecedent['SystemName'] = storage_system
+ antecedent['CreationClassName'] = self.data.lunmask_creationclass
+ antecedent['DeviceID'] = self.data.lunmaskctrl_id
+ antecedent['SystemName'] = self.data.storage_system
- unit['Dependent'] = dependent
- unit['Antecedent'] = antecedent
- unit['CreationClassName'] = unit_creationclass
- units.append(unit)
+ unitname['Dependent'] = dependent
+ unitname['Antecedent'] = antecedent
+ unitname['CreationClassName'] = self.data.unit_creationclass
+ unitnames.append(unitname)
- return units
+ return unitnames
def _default_ref(self, objectpath):
return objectpath
def _assoc_hdwid(self):
assocs = []
assoc = {}
- assoc['StorageID'] = initiator1
+ assoc['StorageID'] = self.data.initiator1
assocs.append(assoc)
return assocs
assocs = []
assoc = {}
assoc['Name'] = 'iqn.1992-04.com.emc:cx.apm00123907237.a8,t,0x0001'
- assoc['SystemName'] = storage_system + '+SP_A+8'
+ assoc['SystemName'] = self.data.storage_system + '+SP_A+8'
+ assocs.append(assoc)
+ return assocs
+
+ # Added test for EMC_StorageVolume associators
+ def _assoc_storagevolume(self, objectpath):
+ assocs = []
+ if objectpath['type'] == 'failed_delete_vol':
+ vol = self.data.failed_delete_vol
+ elif objectpath['type'] == 'vol1':
+ vol = self.data.test_volume
+ elif objectpath['type'] == 'failed_vol':
+ vol = self.data.test_failed_volume
+ elif objectpath['type'] == 'failed_clone_sync':
+ vol = self.data.failed_clone_sync
+ elif objectpath['type'] == 'failed_clone_replica':
+ vol = self.data.failed_clone_replica
+ elif objectpath['type'] == 'failed_snapshot_replica':
+ vol = self.data.failed_snapshot_replica
+ elif objectpath['type'] == 'failed_snapshot_sync':
+ vol = self.data.failed_snapshot_sync
+ elif objectpath['type'] == 'clone1':
+ vol = self.data.test_clone
+ elif objectpath['type'] == 'clone3':
+ vol = self.data.test_clone3
+ elif objectpath['type'] == 'snapshot1':
+ vol = self.data.test_snapshot
+ elif objectpath['type'] == 'snapshot_vmax':
+ vol = self.data.test_snapshot_vmax
+ elif objectpath['type'] == 'failed_extend_vol':
+ vol = self.data.failed_extend_vol
+ else:
+ return None
+
+ vol['DeviceID'] = vol['id']
+ assoc = self._getinstance_storagevolume(vol)
assocs.append(assoc)
return assocs
return objectpath
def _getinstance_storagevolume(self, objectpath):
+ foundinstance = None
instance = EMC_StorageVolume()
vols = self._enum_storagevolumes()
for vol in vols:
if vol['DeviceID'] == objectpath['DeviceID']:
instance = vol
break
- return instance
+ if not instance:
+ foundinstance = None
+ else:
+ foundinstance = instance
+ return foundinstance
def _getinstance_syncsvsv(self, objectpath):
foundsync = None
def _getinstance_lunmask(self):
lunmask = {}
- lunmask['CreationClassName'] = lunmask_creationclass
- lunmask['DeviceID'] = lunmaskctrl_id
- lunmask['SystemName'] = storage_system
+ lunmask['CreationClassName'] = self.data.lunmask_creationclass
+ lunmask['DeviceID'] = self.data.lunmaskctrl_id
+ lunmask['SystemName'] = self.data.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
+ dependent['CreationClassName'] = self.data.vol_creationclass
+ dependent['DeviceID'] = self.data.test_volume['id']
+ dependent['ElementName'] = self.data.test_volume['name']
+ dependent['SystemName'] = self.data.storage_system
antecedent = {}
- antecedent['CreationClassName'] = lunmask_creationclass
- antecedent['DeviceID'] = lunmaskctrl_id
- antecedent['SystemName'] = storage_system
+ antecedent['CreationClassName'] = self.data.lunmask_creationclass
+ antecedent['DeviceID'] = self.data.lunmaskctrl_id
+ antecedent['SystemName'] = self.data.storage_system
unit['Dependent'] = dependent
unit['Antecedent'] = antecedent
- unit['CreationClassName'] = unit_creationclass
+ unit['CreationClassName'] = self.data.unit_creationclass
unit['DeviceNumber'] = '0'
return unit
def _enum_replicationservices(self):
rep_services = []
rep_service = {}
- rep_service['SystemName'] = storage_system
- rep_service['CreationClassName'] = rep_service_creationclass
+ rep_service['SystemName'] = self.data.storage_system
+ rep_service['CreationClassName'] = self.data.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_service['SystemName'] = self.data.storage_system
+ conf_service['CreationClassName'] =\
+ self.data.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_service['SystemName'] = self.data.storage_system
+ conf_service['CreationClassName'] =\
+ self.data.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['InstanceID'] = self.data.storage_system + '+U+' +\
+ self.data.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['InstanceID'] = self.data.storage_system + '+U+' +\
+ self.data.storage_type
pool['CreationClassName'] = 'Clar_UnifiedStoragePool'
pool['TotalManagedSpace'] = 12345678
pool['RemainingManagedSpace'] = 123456
def _enum_storagevolumes(self):
vols = []
+
vol = EMC_StorageVolume()
+ vol['name'] = self.data.test_volume['name']
vol['CreationClassName'] = 'Clar_StorageVolume'
- vol['ElementName'] = test_volume['name']
- vol['DeviceID'] = test_volume['id']
- vol['SystemName'] = storage_system
- vol.path = {'DeviceID': vol['DeviceID']}
+ vol['ElementName'] = self.data.test_volume['name']
+ vol['DeviceID'] = self.data.test_volume['id']
+ vol['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ vol.path = vol
+ vol.path.classname = vol['CreationClassName']
+
+ name = {}
+ name['classname'] = 'Clar_StorageVolume'
+ keys = {}
+ keys['CreationClassName'] = 'Clar_StorageVolume'
+ keys['SystemName'] = self.data.storage_system
+ keys['DeviceID'] = vol['DeviceID']
+ keys['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name['keybindings'] = keys
+ vol['provider_location'] = str(name)
+
vols.append(vol)
snap_vol = EMC_StorageVolume()
+ snap_vol['name'] = self.data.test_snapshot['name']
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']}
+ snap_vol['ElementName'] = self.data.test_snapshot['name']
+ snap_vol['DeviceID'] = self.data.test_snapshot['id']
+ snap_vol['SystemName'] = self.data.storage_system
+ # Added vol to path
+ snap_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ snap_vol.path = snap_vol
+ snap_vol.path.classname = snap_vol['CreationClassName']
+
+ name2 = {}
+ name2['classname'] = 'Clar_StorageVolume'
+ keys2 = {}
+ keys2['CreationClassName'] = 'Clar_StorageVolume'
+ keys2['SystemName'] = self.data.storage_system
+ keys2['DeviceID'] = snap_vol['DeviceID']
+ keys2['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name2['keybindings'] = keys2
+ snap_vol['provider_location'] = str(name2)
+
vols.append(snap_vol)
clone_vol = EMC_StorageVolume()
+ clone_vol['name'] = self.data.test_clone['name']
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']}
+ clone_vol['ElementName'] = self.data.test_clone['name']
+ clone_vol['DeviceID'] = self.data.test_clone['id']
+ clone_vol['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ clone_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ clone_vol.path = clone_vol
+ clone_vol.path.classname = clone_vol['CreationClassName']
vols.append(clone_vol)
clone_vol3 = EMC_StorageVolume()
+ clone_vol3['name'] = self.data.test_clone3['name']
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']}
+ clone_vol3['ElementName'] = self.data.test_clone3['name']
+ clone_vol3['DeviceID'] = self.data.test_clone3['id']
+ clone_vol3['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ clone_vol3['SystemCreationClassName'] = 'Clar_StorageSystem'
+ clone_vol3.path = clone_vol3
+ clone_vol3.path.classname = clone_vol3['CreationClassName']
vols.append(clone_vol3)
snap_vol_vmax = EMC_StorageVolume()
+ snap_vol_vmax['name'] = self.data.test_snapshot_vmax['name']
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']}
+ snap_vol_vmax['ElementName'] = self.data.test_snapshot_vmax['name']
+ snap_vol_vmax['DeviceID'] = self.data.test_snapshot_vmax['id']
+ snap_vol_vmax['SystemName'] = self.data.storage_system_vmax
+ # Added vol to vol.path
+ snap_vol_vmax['SystemCreationClassName'] = 'Symm_StorageSystem'
+ snap_vol_vmax.path = snap_vol_vmax
+ snap_vol_vmax.path.classname = snap_vol_vmax['CreationClassName']
+
+ name3 = {}
+ name3['classname'] = 'Clar_StorageVolume'
+ keys3 = {}
+ keys3['CreationClassName'] = 'Clar_StorageVolume'
+ keys3['SystemName'] = self.data.storage_system
+ keys3['DeviceID'] = snap_vol_vmax['DeviceID']
+ keys3['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name3['keybindings'] = keys3
+ snap_vol_vmax['provider_location'] = str(name3)
+
vols.append(snap_vol_vmax)
failed_snap_replica = EMC_StorageVolume()
+ failed_snap_replica['name'] = self.data.failed_snapshot_replica['name']
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']}
+ failed_snap_replica['ElementName'] =\
+ self.data.failed_snapshot_replica['name']
+ failed_snap_replica['DeviceID'] =\
+ self.data.failed_snapshot_replica['id']
+ failed_snap_replica['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_snap_replica['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_snap_replica.path = failed_snap_replica
+ failed_snap_replica.path.classname =\
+ failed_snap_replica['CreationClassName']
+
+ name4 = {}
+ name4['classname'] = 'Clar_StorageVolume'
+ keys4 = {}
+ keys4['CreationClassName'] = 'Clar_StorageVolume'
+ keys4['SystemName'] = self.data.storage_system
+ keys4['DeviceID'] = failed_snap_replica['DeviceID']
+ keys4['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name4['keybindings'] = keys4
+ failed_snap_replica['provider_location'] = str(name4)
+
vols.append(failed_snap_replica)
failed_snap_sync = EMC_StorageVolume()
+ failed_snap_sync['name'] = self.data.failed_snapshot_sync['name']
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']}
+ failed_snap_sync['ElementName'] =\
+ self.data.failed_snapshot_sync['name']
+ failed_snap_sync['DeviceID'] = self.data.failed_snapshot_sync['id']
+ failed_snap_sync['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_snap_sync['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_snap_sync.path = failed_snap_sync
+ failed_snap_sync.path.classname =\
+ failed_snap_sync['CreationClassName']
+
+ name5 = {}
+ name5['classname'] = 'Clar_StorageVolume'
+ keys5 = {}
+ keys5['CreationClassName'] = 'Clar_StorageVolume'
+ keys5['SystemName'] = self.data.storage_system
+ keys5['DeviceID'] = failed_snap_sync['DeviceID']
+ keys5['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name5['keybindings'] = keys5
+ failed_snap_sync['provider_location'] = str(name5)
+
vols.append(failed_snap_sync)
failed_clone_rep = EMC_StorageVolume()
+ failed_clone_rep['name'] = self.data.failed_clone_replica['name']
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']}
+ failed_clone_rep['ElementName'] =\
+ self.data.failed_clone_replica['name']
+ failed_clone_rep['DeviceID'] = self.data.failed_clone_replica['id']
+ failed_clone_rep['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_clone_rep['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_clone_rep.path = failed_clone_rep
+ failed_clone_rep.path.classname =\
+ failed_clone_rep['CreationClassName']
vols.append(failed_clone_rep)
failed_clone_s = EMC_StorageVolume()
+ failed_clone_s['name'] = self.data.failed_clone_sync['name']
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']}
+ failed_clone_s['ElementName'] = self.data.failed_clone_sync['name']
+ failed_clone_s['DeviceID'] = self.data.failed_clone_sync['id']
+ failed_clone_s['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_clone_s['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_clone_s.path = failed_clone_s
+ failed_clone_s.path.classname =\
+ failed_clone_s['CreationClassName']
vols.append(failed_clone_s)
failed_delete_vol = EMC_StorageVolume()
+ failed_delete_vol['name'] = 'failed_delete_vol'
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']}
+ failed_delete_vol['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_delete_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_delete_vol.path = failed_delete_vol
+ failed_delete_vol.path.classname =\
+ failed_delete_vol['CreationClassName']
vols.append(failed_delete_vol)
+ failed_vol = EMC_StorageVolume()
+ failed_vol['name'] = 'failed__vol'
+ failed_vol['CreationClassName'] = 'Clar_StorageVolume'
+ failed_vol['ElementName'] = 'failed_vol'
+ failed_vol['DeviceID'] = '4'
+ failed_vol['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_vol.path = failed_vol
+ failed_vol.path.classname =\
+ failed_vol['CreationClassName']
+
+ name_failed = {}
+ name_failed['classname'] = 'Clar_StorageVolume'
+ keys_failed = {}
+ keys_failed['CreationClassName'] = 'Clar_StorageVolume'
+ keys_failed['SystemName'] = self.data.storage_system
+ keys_failed['DeviceID'] = failed_vol['DeviceID']
+ keys_failed['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name_failed['keybindings'] = keys_failed
+ failed_vol['provider_location'] = str(name_failed)
+
+ vols.append(failed_vol)
+
+ failed_extend_vol = EMC_StorageVolume()
+ failed_extend_vol['name'] = 'failed_extend_vol'
+ failed_extend_vol['CreationClassName'] = 'Clar_StorageVolume'
+ failed_extend_vol['ElementName'] = 'failed_extend_vol'
+ failed_extend_vol['DeviceID'] = '9'
+ failed_extend_vol['SystemName'] = self.data.storage_system
+ # Added vol to vol.path
+ failed_extend_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ failed_extend_vol.path = failed_extend_vol
+ failed_extend_vol.path.classname =\
+ failed_extend_vol['CreationClassName']
+
+ name_extend_failed = {}
+ name_extend_failed['classname'] = 'Clar_StorageVolume'
+ keys_extend_failed = {}
+ keys_extend_failed['CreationClassName'] = 'Clar_StorageVolume'
+ keys_extend_failed['SystemName'] = self.data.storage_system
+ keys_extend_failed['DeviceID'] = failed_extend_vol['DeviceID']
+ keys_extend_failed['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name_extend_failed['keybindings'] = keys_extend_failed
+ failed_extend_vol['provider_location'] = str(name_extend_failed)
+
+ vols.append(failed_extend_vol)
+
return vols
def _enum_syncsvsvs(self):
def _enum_lunmaskctrls(self):
ctrls = []
ctrl = {}
- ctrl['CreationClassName'] = lunmask_creationclass
- ctrl['DeviceID'] = lunmaskctrl_id
- ctrl['SystemName'] = storage_system
+ ctrl['CreationClassName'] = self.data.lunmask_creationclass
+ ctrl['DeviceID'] = self.data.lunmaskctrl_id
+ ctrl['SystemName'] = self.data.storage_system
ctrls.append(ctrl)
return ctrls
ctrls = []
ctrl = {}
ctrl['CreationClassName'] = 'Clar_StorageProcessorSystem'
- ctrl['Name'] = storage_system + '+SP_A'
+ ctrl['Name'] = self.data.storage_system + '+SP_A'
ctrls.append(ctrl)
return ctrls
+ def _enum_hdwidmgmts(self):
+ services = []
+ srv = {}
+ srv['SystemName'] = self.data.storage_system
+ services.append(srv)
+ return services
+
+ def _enum_storhdwids(self):
+ storhdwids = []
+ hdwid = SE_StorageHardwareID()
+ hdwid['StorageID'] = self.data.connector['wwpns'][0]
+
+ hdwid.path = hdwid
+ storhdwids.append(hdwid)
+ return storhdwids
+
def _default_enum(self):
names = []
name = {}
class EMCSMISISCSIDriverTestCase(test.TestCase):
def setUp(self):
+
+ self.data = EMCSMISCommonData()
+
self.tempdir = tempfile.mkdtemp()
super(EMCSMISISCSIDriverTestCase, self).setUp()
self.config_file_path = None
self.create_fake_config_file()
- configuration = mox.MockObject(conf.Configuration)
+ configuration = mock.Mock()
configuration.cinder_emc_config_file = self.config_file_path
- configuration.append_config_values(mox.IgnoreArg())
self.stubs.Set(EMCSMISISCSIDriver, '_do_iscsi_discovery',
self.fake_do_iscsi_discovery)
self.stubs.Set(EMCSMISCommon, '_get_ecom_connection',
self.fake_ecom_connection)
+ instancename = FakeCIMInstanceName()
+ self.stubs.Set(EMCSMISCommon, '_getinstancename',
+ instancename.fake_getinstancename)
driver = EMCSMISISCSIDriver(configuration=configuration)
+ driver.db = FakeDB()
self.driver = driver
def create_fake_config_file(self):
+
doc = Document()
emc = doc.createElement("EMC")
doc.appendChild(emc)
emc.appendChild(ecompassword)
ecompassword.appendChild(ecompasswordtext)
- self.config_file_path = self.tempdir + '/' + config_file_name
+ self.config_file_path = self.tempdir + '/' + self.data.config_file_name
f = open(self.config_file_path, 'w')
doc.writexml(f)
f.close()
self.driver.get_volume_stats(True)
def test_create_destroy(self):
- self.driver.create_volume(test_volume)
- self.driver.delete_volume(test_volume)
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.delete_volume(self.data.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(self.data.test_volume)
+ self.driver.create_snapshot(self.data.test_snapshot)
self.driver.create_volume_from_snapshot(
- test_clone, test_snapshot)
+ self.data.test_clone, self.data.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)
+ self.data.test_clone3, self.data.test_volume)
+ self.driver.delete_volume(self.data.test_clone)
+ self.driver.delete_volume(self.data.test_clone3)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.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'] = 'SP_A'
- 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)
+ self.driver.create_volume(self.data.test_volume)
+ self.data.test_volume['EMCCurrentOwningStorageProcessor'] = 'SP_A'
+ connection_info = self.driver.initialize_connection(
+ self.data.test_volume,
+ self.data.connector)
+ self.driver.terminate_connection(self.data.test_volume,
+ self.data.connector)
+ self.driver.delete_volume(self.data.test_volume)
def test_create_volume_failed(self):
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_volume,
- test_failed_volume)
+ self.data.test_failed_volume)
def test_create_volume_snapshot_unsupported(self):
- self.driver.create_volume(test_volume)
- self.driver.create_snapshot(test_snapshot_vmax)
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.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)
+ self.data.test_clone,
+ self.data.test_snapshot_vmax)
+ self.driver.delete_snapshot(self.data.test_snapshot_vmax)
+ self.driver.delete_volume(self.data.test_volume)
def test_create_volume_snapshot_replica_failed(self):
- self.driver.create_volume(test_volume)
- self.driver.create_snapshot(test_snapshot)
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.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)
+ self.data.failed_snapshot_replica,
+ self.data.test_snapshot)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.test_volume)
def test_create_volume_snapshot_sync_failed(self):
- self.driver.create_volume(test_volume)
- self.driver.create_snapshot(test_snapshot)
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.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)
+ self.data.failed_snapshot_sync,
+ self.data.test_snapshot)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.test_volume)
def test_create_volume_clone_replica_failed(self):
- self.driver.create_volume(test_volume)
+ self.driver.create_volume(self.data.test_volume)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_cloned_volume,
- failed_clone_replica,
- test_volume)
- self.driver.delete_volume(test_volume)
+ self.data.failed_clone_replica,
+ self.data.test_volume)
+ self.driver.delete_volume(self.data.test_volume)
def test_create_volume_clone_sync_failed(self):
- self.driver.create_volume(test_volume)
+ self.driver.create_volume(self.data.test_volume)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.create_cloned_volume,
- failed_clone_sync,
- test_volume)
- self.driver.delete_volume(test_volume)
+ self.data.failed_clone_sync,
+ self.data.test_volume)
+ self.driver.delete_volume(self.data.test_volume)
def test_delete_volume_notfound(self):
notfound_delete_vol = {}
notfound_delete_vol['name'] = 'notfound_delete_vol'
notfound_delete_vol['id'] = '10'
+ notfound_delete_vol['CreationClassName'] = 'Clar_StorageVolume'
+ notfound_delete_vol['SystemName'] = self.data.storage_system
+ notfound_delete_vol['DeviceID'] = notfound_delete_vol['id']
+ notfound_delete_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name = {}
+ name['classname'] = 'Clar_StorageVolume'
+ keys = {}
+ keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
+ keys['SystemName'] = notfound_delete_vol['SystemName']
+ keys['DeviceID'] = notfound_delete_vol['DeviceID']
+ keys['SystemCreationClassName'] =\
+ notfound_delete_vol['SystemCreationClassName']
+ name['keybindings'] = keys
+ notfound_delete_vol['provider_location'] = str(name)
self.driver.delete_volume(notfound_delete_vol)
def test_delete_volume_failed(self):
- self.driver.create_volume(failed_delete_vol)
+ self.driver.create_volume(self.data.failed_delete_vol)
self.assertRaises(exception.VolumeBackendAPIException,
self.driver.delete_volume,
- failed_delete_vol)
+ self.data.failed_delete_vol)
+
+ def test_extend_volume(self):
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.extend_volume(self.data.test_volume, '10')
+ self.driver.create_volume(self.data.failed_extend_vol)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.extend_volume,
+ self.data.failed_extend_vol,
+ '10')
def _cleanup(self):
bExists = os.path.exists(self.config_file_path)
def tearDown(self):
self._cleanup()
super(EMCSMISISCSIDriverTestCase, self).tearDown()
+
+
+class EMCSMISFCDriverTestCase(test.TestCase):
+
+ def setUp(self):
+
+ self.data = EMCSMISCommonData()
+
+ self.tempdir = tempfile.mkdtemp()
+ super(EMCSMISFCDriverTestCase, self).setUp()
+ self.config_file_path = None
+ self.create_fake_config_file()
+
+ configuration = mock.Mock()
+ configuration.cinder_emc_config_file = self.config_file_path
+
+ self.stubs.Set(EMCSMISCommon, '_get_ecom_connection',
+ self.fake_ecom_connection)
+ instancename = FakeCIMInstanceName()
+ self.stubs.Set(EMCSMISCommon, '_getinstancename',
+ instancename.fake_getinstancename)
+ driver = EMCSMISFCDriver(configuration=configuration)
+ driver.db = FakeDB()
+ 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 + '/' + self.data.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 test_get_volume_stats(self):
+ self.driver.get_volume_stats(True)
+
+ def test_create_destroy(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_snapshot_destroy(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.test_snapshot)
+ self.driver.create_volume_from_snapshot(
+ self.data.test_clone, self.data.test_snapshot)
+ self.driver.create_cloned_volume(
+ self.data.test_clone3, self.data.test_volume)
+ self.driver.delete_volume(self.data.test_clone)
+ self.driver.delete_volume(self.data.test_clone3)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_map_unmap(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+
+ output = {'driver_volume_type': 'fibre_channel',
+ 'data': {'target_lun': 0,
+ 'target_wwn': ['1234567890123', '0987654321321'],
+ 'target_discovered': True}}
+ connection_info = self.driver.initialize_connection(
+ self.data.test_volume,
+ self.data.connector)
+ self.assertEqual(connection_info, output)
+
+ self.driver.terminate_connection(self.data.test_volume,
+ self.data.connector)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_failed(self):
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_volume,
+ self.data.test_failed_volume)
+
+ def test_create_volume_snapshot_unsupported(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.test_snapshot_vmax)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_volume_from_snapshot,
+ self.data.test_clone,
+ self.data.test_snapshot_vmax)
+ self.driver.delete_snapshot(self.data.test_snapshot_vmax)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_snapshot_replica_failed(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.test_snapshot)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_volume_from_snapshot,
+ self.data.failed_snapshot_replica,
+ self.data.test_snapshot)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_snapshot_sync_failed(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.create_snapshot(self.data.test_snapshot)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_volume_from_snapshot,
+ self.data.failed_snapshot_sync,
+ self.data.test_snapshot)
+ self.driver.delete_snapshot(self.data.test_snapshot)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_clone_replica_failed(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_cloned_volume,
+ self.data.failed_clone_replica,
+ self.data.test_volume)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_create_volume_clone_sync_failed(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.create_cloned_volume,
+ self.data.failed_clone_sync,
+ self.data.test_volume)
+ self.driver.delete_volume(self.data.test_volume)
+
+ def test_delete_volume_notfound(self):
+ notfound_delete_vol = {}
+ notfound_delete_vol['name'] = 'notfound_delete_vol'
+ notfound_delete_vol['id'] = '10'
+ notfound_delete_vol['CreationClassName'] = 'Clar_StorageVolume'
+ notfound_delete_vol['SystemName'] = self.data.storage_system
+ notfound_delete_vol['DeviceID'] = notfound_delete_vol['id']
+ notfound_delete_vol['SystemCreationClassName'] = 'Clar_StorageSystem'
+ name = {}
+ name['classname'] = 'Clar_StorageVolume'
+ keys = {}
+ keys['CreationClassName'] = notfound_delete_vol['CreationClassName']
+ keys['SystemName'] = notfound_delete_vol['SystemName']
+ keys['DeviceID'] = notfound_delete_vol['DeviceID']
+ keys['SystemCreationClassName'] =\
+ notfound_delete_vol['SystemCreationClassName']
+ name['keybindings'] = keys
+ notfound_delete_vol['provider_location'] = str(name)
+ self.driver.delete_volume(notfound_delete_vol)
+
+ def test_delete_volume_failed(self):
+ self.driver.create_volume(self.data.failed_delete_vol)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.delete_volume,
+ self.data.failed_delete_vol)
+
+ def test_extend_volume(self):
+ self.data.test_volume['volume_type_id'] = None
+ self.driver.create_volume(self.data.test_volume)
+ self.driver.extend_volume(self.data.test_volume, '10')
+ self.driver.create_volume(self.data.failed_extend_vol)
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver.extend_volume,
+ self.data.failed_extend_vol,
+ '10')
+
+ @mock.patch.object(
+ volume_types,
+ 'get_volume_type_extra_specs',
+ return_value={'storagetype:pool': 'gold',
+ 'storagetype:provisioning': 'thick'})
+ def test_create_volume_with_volume_type(self, _mock_volume_type):
+ volume_with_vt = self.data.test_volume
+ volume_with_vt['volume_type_id'] = 1
+ self.driver.create_volume(volume_with_vt)
+
+ configservice = {'CreationClassName':
+ 'Clar_StorageConfigurationService',
+ 'SystemName': 'CLARiiON+APM00123456789'}
+
+ pool = {'InstanceID': 'CLARiiON+APM00123456789+U+gold',
+ 'CreationClassName': 'Clar_UnifiedStoragePool'}
+
+ volumesize = int(volume_with_vt['size']) * units.GiB
+
+ storage_type = {'storagetype:provisioning': 'thick',
+ 'storagetype:pool': 'gold'}
+
+ expected = [
+ mock.call._get_storage_type(volume_with_vt),
+ mock.call._find_pool('gold'),
+ mock.call.get_provisioning(storage_type),
+ mock.call.InvokeMethod('CreateOrModifyElementFromStoragePool',
+ configservice, volume_with_vt['name'],
+ pool,
+ self.driver.common._getnum(2, '16'),
+ self.driver.common._getnum(volumesize,
+ '64'))]
+
+ 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(EMCSMISFCDriverTestCase, self).tearDown()
-# Copyright (c) 2012 EMC Corporation.
-# Copyright (c) 2012 OpenStack Foundation
+# Copyright (c) 2012 - 2014 EMC Corporation.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import units
+from cinder.volume import volume_types
LOG = logging.getLogger(__name__)
'Install PyWBEM using the python-pywbem package.'))
CINDER_EMC_CONFIG_FILE = '/etc/cinder/cinder_emc_config.xml'
+EMC_ROOT = 'root/emc'
+PROVISIONING = 'storagetype:provisioning'
+POOL = 'storagetype:pool'
emc_opts = [
cfg.StrOpt('cinder_emc_config_file',
'volume_backend_name': None}
def __init__(self, prtcl, configuration=None):
+
self.protocol = prtcl
self.configuration = configuration
self.configuration.append_config_values(emc_opts)
def create_volume(self, volume):
"""Creates a EMC(VMAX/VNX) volume."""
-
LOG.debug(_('Entering create_volume.'))
volumesize = int(volume['size']) * units.GiB
volumename = volume['name']
self.conn = self._get_ecom_connection()
- storage_type = self._get_storage_type()
+ storage_type = self._get_storage_type(volume)
LOG.debug(_('Create Volume: %(volume)s '
'Storage type: %(storage_type)s')
% {'volume': volumename,
'storage_type': storage_type})
- pool, storage_system = self._find_pool(storage_type)
+ pool, storage_system = self._find_pool(storage_type[POOL])
LOG.debug(_('Create Volume: %(volume)s Pool: %(pool)s '
'Storage System: %(storage_system)s')
LOG.error(exception_message)
raise exception.VolumeBackendAPIException(data=exception_message)
+ provisioning = self._get_provisioning(storage_type)
+
LOG.debug(_('Create Volume: %(name)s Method: '
'CreateOrModifyElementFromStoragePool ConfigServicie: '
'%(service)s ElementName: %(name)s InPool: %(pool)s '
- 'ElementType: 5 Size: %(size)lu')
+ 'ElementType: %(provisioning)s Size: %(size)lu')
% {'service': str(configservice),
'name': volumename,
'pool': str(pool),
+ 'provisioning': provisioning,
'size': volumesize})
rc, job = self.conn.InvokeMethod(
'CreateOrModifyElementFromStoragePool',
configservice, ElementName=volumename, InPool=pool,
- ElementType=self._getnum(5, '16'),
+ ElementType=self._getnum(provisioning, '16'),
Size=self._getnum(volumesize, '64'))
LOG.debug(_('Create Volume: %(volumename)s Return code: %(rc)lu')
'error': errordesc})
raise exception.VolumeBackendAPIException(data=errordesc)
+ # Find the newly created volume
+ associators = self.conn.Associators(
+ job['Job'],
+ resultClass='EMC_StorageVolume')
+ volpath = associators[0].path
+ name = {}
+ name['classname'] = volpath.classname
+ keys = {}
+ keys['CreationClassName'] = volpath['CreationClassName']
+ keys['SystemName'] = volpath['SystemName']
+ keys['DeviceID'] = volpath['DeviceID']
+ keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
+ name['keybindings'] = keys
+
LOG.debug(_('Leaving create_volume: %(volumename)s '
- 'Return code: %(rc)lu')
+ 'Return code: %(rc)lu '
+ 'volume instance: %(name)s')
% {'volumename': volumename,
- 'rc': rc})
+ 'rc': rc,
+ 'name': name})
+
+ return name
def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from a snapshot."""
raise exception.VolumeBackendAPIException(
data=exception_message)
+ # Find the newly created volume
+ associators = self.conn.Associators(
+ job['Job'],
+ resultClass='EMC_StorageVolume')
+ volpath = associators[0].path
+ name = {}
+ name['classname'] = volpath.classname
+ keys = {}
+ keys['CreationClassName'] = volpath['CreationClassName']
+ keys['SystemName'] = volpath['SystemName']
+ keys['DeviceID'] = volpath['DeviceID']
+ keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
+ name['keybindings'] = keys
+
LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s '
'Snapshot: %(snapshotname)s. Successfully clone volume '
'from snapshot. Finding the clone relationship.')
% {'volumename': volumename,
'snapshotname': snapshotname})
+ volume['provider_location'] = str(name)
sync_name, storage_system = self._find_storage_sync_sv_sv(
- volumename, snapshotname)
+ volume, snapshot)
# Remove the Clone relationshop so it can be used as a regular lun
# 8 - Detach operation
'snapshotname': snapshotname,
'rc': rc})
+ return name
+
def create_cloned_volume(self, volume, src_vref):
"""Creates a clone of the specified volume."""
LOG.debug(_('Entering create_cloned_volume.'))
raise exception.VolumeBackendAPIException(
data=exception_message)
+ # Find the newly created volume
+ associators = self.conn.Associators(
+ job['Job'],
+ resultClass='EMC_StorageVolume')
+ volpath = associators[0].path
+ name = {}
+ name['classname'] = volpath.classname
+ keys = {}
+ keys['CreationClassName'] = volpath['CreationClassName']
+ keys['SystemName'] = volpath['SystemName']
+ keys['DeviceID'] = volpath['DeviceID']
+ keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
+ name['keybindings'] = keys
+
LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s '
'Source Volume: %(srcname)s. Successfully cloned volume '
'from source volume. Finding the clone relationship.')
% {'volumename': volumename,
'srcname': srcname})
+ volume['provider_location'] = str(name)
sync_name, storage_system = self._find_storage_sync_sv_sv(
- volumename, srcname)
+ volume, src_vref)
# Remove the Clone relationshop so it can be used as a regular lun
# 8 - Detach operation
'srcname': srcname,
'rc': rc})
+ return name
+
def delete_volume(self, volume):
"""Deletes an EMC volume."""
LOG.debug(_('Entering delete_volume.'))
% {'volumename': volumename,
'rc': rc})
- def create_snapshot(self, snapshot):
+ def create_snapshot(self, snapshot, volume):
"""Creates a snapshot."""
LOG.debug(_('Entering create_snapshot.'))
self.conn = self._get_ecom_connection()
- volume = {}
- volume['name'] = volumename
- volume['provider_location'] = None
vol_instance = self._find_lun(volume)
+
device_id = vol_instance['DeviceID']
storage_system = vol_instance['SystemName']
LOG.debug(_('Device ID: %(deviceid)s: Storage System: '
raise exception.VolumeBackendAPIException(
data=exception_message)
+ # Find the newly created volume
+ associators = self.conn.Associators(
+ job['Job'],
+ resultClass='EMC_StorageVolume')
+ volpath = associators[0].path
+ name = {}
+ name['classname'] = volpath.classname
+ keys = {}
+ keys['CreationClassName'] = volpath['CreationClassName']
+ keys['SystemName'] = volpath['SystemName']
+ keys['DeviceID'] = volpath['DeviceID']
+ keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
+ name['keybindings'] = keys
+
LOG.debug(_('Leaving create_snapshot: Snapshot: %(snapshot)s '
'Volume: %(volume)s Return code: %(rc)lu.') %
{'snapshot': snapshotname, 'volume': volumename, 'rc': rc})
- def delete_snapshot(self, snapshot):
+ return name
+
+ def delete_snapshot(self, snapshot, volume):
"""Deletes a snapshot."""
LOG.debug(_('Entering delete_snapshot.'))
'volume': volumename})
sync_name, storage_system =\
- self._find_storage_sync_sv_sv(snapshotname, volumename, False)
+ self._find_storage_sync_sv_sv(snapshot, volume, False)
if sync_name is None:
LOG.error(_('Snapshot: %(snapshot)s: volume: %(volume)s '
'not found on the array. No snapshot to delete.')
'snapshotname': snapshotname,
'rc': rc})
- def create_export(self, context, volume):
- """Driver entry point to get the export info for a new volume."""
- self.conn = self._get_ecom_connection()
- volumename = volume['name']
- LOG.info(_('Create export: %(volume)s')
- % {'volume': volumename})
- vol_instance = self._find_lun(volume)
- device_id = vol_instance['DeviceID']
-
- LOG.debug(_('create_export: Volume: %(volume)s Device ID: '
- '%(device_id)s')
- % {'volume': volumename,
- 'device_id': device_id})
-
- return {'provider_location': device_id}
-
# Mapping method for VNX
def _expose_paths(self, configservice, vol_instance,
connector):
self.conn = self._get_ecom_connection()
self._unmap_lun(volume, connector)
+ def extend_volume(self, volume, new_size):
+ """Extends an existing volume."""
+ LOG.debug(_('Entering extend_volume.'))
+ volumesize = int(new_size) * units.GiB
+ volumename = volume['name']
+
+ LOG.info(_('Extend Volume: %(volume)s New size: %(size)lu')
+ % {'volume': volumename,
+ 'size': volumesize})
+
+ self.conn = self._get_ecom_connection()
+
+ storage_type = self._get_storage_type(volume)
+
+ vol_instance = self._find_lun(volume)
+
+ device_id = vol_instance['DeviceID']
+ storage_system = vol_instance['SystemName']
+ LOG.debug(_('Device ID: %(deviceid)s: Storage System: '
+ '%(storagesystem)s')
+ % {'deviceid': device_id,
+ 'storagesystem': storage_system})
+
+ configservice = self._find_storage_configuration_service(
+ storage_system)
+ if configservice is None:
+ exception_message = (_("Error Extend Volume: %(volumename)s. "
+ "Storage Configuration Service not found.")
+ % {'volumename': volumename})
+ LOG.error(exception_message)
+ raise exception.VolumeBackendAPIException(data=exception_message)
+
+ provisioning = self._get_provisioning(storage_type)
+
+ LOG.debug(_('Extend Volume: %(name)s Method: '
+ 'CreateOrModifyElementFromStoragePool ConfigServicie: '
+ '%(service)s ElementType: %(provisioning)s Size: %(size)lu'
+ 'Volume path: %(volumepath)s')
+ % {'service': str(configservice),
+ 'name': volumename,
+ 'provisioning': provisioning,
+ 'size': volumesize,
+ 'volumepath': vol_instance.path})
+
+ rc, job = self.conn.InvokeMethod(
+ 'CreateOrModifyElementFromStoragePool',
+ configservice, ElementType=self._getnum(provisioning, '16'),
+ Size=self._getnum(volumesize, '64'),
+ TheElement=vol_instance.path)
+
+ LOG.debug(_('Extend Volume: %(volumename)s Return code: %(rc)lu')
+ % {'volumename': volumename,
+ 'rc': rc})
+
+ if rc != 0L:
+ rc, errordesc = self._wait_for_job_complete(job)
+ if rc != 0L:
+ LOG.error(_('Error Extend Volume: %(volumename)s. '
+ 'Return code: %(rc)lu. Error: %(error)s')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'error': errordesc})
+ raise exception.VolumeBackendAPIException(data=errordesc)
+
+ LOG.debug(_('Leaving extend_volume: %(volumename)s '
+ 'Return code: %(rc)lu ')
+ % {'volumename': volumename,
+ 'rc': rc})
+
def update_volume_stats(self):
"""Retrieve stats info."""
LOG.debug(_("Updating volume stats"))
- self.conn = self._get_ecom_connection()
- storage_type = self._get_storage_type()
+ self.stats['total_capacity_gb'] = 'unknown'
+ self.stats['free_capacity_gb'] = 'unknown'
- pool, storagesystem = self._find_pool(storage_type, True)
+ return self.stats
- self.stats['total_capacity_gb'] = pool['TotalManagedSpace']
- self.stats['free_capacity_gb'] = pool['RemainingManagedSpace']
+ def _get_storage_type(self, volume, filename=None):
+ """Get storage type.
- return self.stats
+ Look for user input volume type first.
+ If not available, fall back to finding it in conf file.
+ """
+ specs = self._get_volumetype_extraspecs(volume)
+ if not specs:
+ specs = self._get_storage_type_conffile()
+ LOG.debug(_("Storage Type: %s") % (specs))
+ return specs
- def _get_storage_type(self, filename=None):
+ def _get_storage_type_conffile(self, filename=None):
"""Get the storage type from the config file."""
- if filename is None:
+ if filename == None:
filename = self.configuration.cinder_emc_config_file
file = open(filename, 'r')
storageType = storageTypes[0].toxml()
storageType = storageType.replace('<StorageType>', '')
storageType = storageType.replace('</StorageType>', '')
- LOG.debug(_("Found Storage Type: %s") % (storageType))
- return storageType
+ LOG.debug(_("Found Storage Type in config file: %s")
+ % (storageType))
+ specs = {}
+ specs[POOL] = storageType
+ return specs
else:
exception_message = (_("Storage type not found."))
LOG.error(exception_message)
def _find_lun(self, volume):
foundinstance = None
- try:
- device_id = volume['provider_location']
- except Exception:
- device_id = None
volumename = volume['name']
-
- names = self.conn.EnumerateInstanceNames('EMC_StorageVolume')
-
- for n in names:
- if device_id is not None:
- if n['DeviceID'] == device_id:
- vol_instance = self.conn.GetInstance(n)
- foundinstance = vol_instance
- break
- else:
- continue
-
- else:
- vol_instance = self.conn.GetInstance(n)
- if vol_instance['ElementName'] == volumename:
- foundinstance = vol_instance
- volume['provider_location'] = foundinstance['DeviceID']
- break
+ loc = volume['provider_location']
+ name = eval(loc)
+ instancename = self._getinstancename(name['classname'],
+ name['keybindings'])
+ foundinstance = self.conn.GetInstance(instancename)
if foundinstance is None:
LOG.debug(_("Volume %(volumename)s not found on the array.")
return foundinstance
- def _find_storage_sync_sv_sv(self, snapshotname, volumename,
+ def _find_storage_sync_sv_sv(self, snapshot, volume,
waitforsync=True):
foundsyncname = None
storage_system = None
percent_synced = 0
+ snapshotname = snapshot['name']
+ volumename = volume['name']
LOG.debug(_("Source: %(volumename)s Target: %(snapshotname)s.")
% {'volumename': volumename, 'snapshotname': snapshotname})
- names = self.conn.EnumerateInstanceNames(
- 'SE_StorageSynchronized_SV_SV')
-
- for n in names:
- snapshot_instance = self.conn.GetInstance(n['SyncedElement'],
- LocalOnly=False)
- if snapshotname != snapshot_instance['ElementName']:
- continue
-
- vol_instance = self.conn.GetInstance(n['SystemElement'],
- LocalOnly=False)
- if vol_instance['ElementName'] == volumename:
- foundsyncname = n
- storage_system = vol_instance['SystemName']
- if waitforsync:
- sync_instance = self.conn.GetInstance(n, LocalOnly=False)
- percent_synced = sync_instance['PercentSynced']
- break
+ snapshot_instance = self._find_lun(snapshot)
+ volume_instance = self._find_lun(volume)
+ storage_system = volume_instance['SystemName']
+ classname = 'SE_StorageSynchronized_SV_SV'
+ bindings = {'SyncedElement': snapshot_instance.path,
+ 'SystemElement': volume_instance.path}
+ foundsyncname = self._getinstancename(classname, bindings)
if foundsyncname is None:
LOG.debug(_("Source: %(volumename)s Target: %(snapshotname)s. "
return foundCtrl
# Find out how many volumes are mapped to a host
- # associated to the LunMaskingSCSIProtocolController
+ # assoociated to the LunMaskingSCSIProtocolController
def get_num_volumes_mapped(self, volume, connector):
numVolumesMapped = 0
volumename = volume['name']
return result
+ def _getinstancename(self, classname, bindings):
+ instancename = None
+ try:
+ instancename = pywbem.CIMInstanceName(
+ classname,
+ namespace=EMC_ROOT,
+ keybindings=bindings)
+ except NameError:
+ instancename = None
+
+ return instancename
+
# Find target WWNs
def get_target_wwns(self, storage_system, connector):
target_wwns = []
for targetendpoint in endpoints:
wwn = targetendpoint['Name']
# Add target wwn to the list if it is not already there
- if not any(d.get('wwn', None) == wwn for d in target_wwns):
- target_wwns.append({'wwn': wwn})
+ if not any(d == wwn for d in target_wwns):
+ target_wwns.append(wwn)
LOG.debug(_('Add target WWN: %s.') % wwn)
LOG.debug(_('Target WWNs: %s.') % target_wwns)
'foundInstances': str(foundInstances)})
return foundInstances
+
+ def _get_volumetype_extraspecs(self, volume):
+ specs = {}
+ type_id = volume['volume_type_id']
+ if type_id is not None:
+ specs = volume_types.get_volume_type_extra_specs(type_id)
+ # If specs['storagetype:pool'] not defined,
+ # set specs to {} so we can ready from config file later
+ if POOL not in specs:
+ specs = {}
+
+ return specs
+
+ def _get_provisioning(self, storage_type):
+ # provisioning is thin (5) by default
+ provisioning = 5
+ thick_str = 'thick'
+ try:
+ type_prov = storage_type[PROVISIONING]
+ if type_prov.lower() == thick_str.lower():
+ provisioning = 2
+ except KeyError:
+ # Default to thin if not defined
+ pass
+
+ return provisioning