+++ /dev/null
-# Copyright (c) 2014 FUJITSU LIMITED
-# Copyright (c) 2012 EMC Corporation, Inc.
-# 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 os
-import tempfile
-
-import mock
-from oslo_log import log as logging
-
-from cinder import exception
-from cinder.i18n import _LW
-from cinder import test
-import cinder.volume.drivers.fujitsu.eternus_dx_common as eternus_dx_common
-import cinder.volume.drivers.fujitsu.eternus_dx_fc as eternus_dx_fc
-import cinder.volume.drivers.fujitsu.eternus_dx_iscsi as eternus_dx_iscsi
-
-CONFIG_FILE_NAME = 'cinder_fujitsu_eternus_dx.xml'
-STORAGE_SYSTEM = '172.16.0.2'
-
-LOG = logging.getLogger(__name__)
-
-CONF = """<?xml version='1.0' encoding='UTF-8'?>
-<FUJITSU>
-<StorageType>abcd1234_TPP</StorageType>
-<EcomServerIp>172.16.0.2</EcomServerIp>
-<EcomServerPort>5988</EcomServerPort>
-<EcomUserName>testuser</EcomUserName>
-<EcomPassword>testpass</EcomPassword>
-<SnapPool>abcd1234_OSVD</SnapPool>
-<Timeout>180</Timeout>
-</FUJITSU>"""
-
-TEST_VOLUME = {'id': '3d6eeb5d-109b-4435-b891-d01415178490',
- 'name': 'volume1',
- 'provider_location': None,
- 'provider_auth': None,
- 'volume_type_id': None,
- 'size': 1}
-# result : {volume_name : FJosv_0qJ4rpOHgFE8ipcJOMfBmg==}
-
-TEST_SNAP = {'id': 'f47a8da3-d9e2-46aa-831f-0ef04158d5a1',
- 'volume_name': 'volume-3d6eeb5d-109b-4435-b891-d01415178490',
- 'name': 'snap1',
- 'display_name': 'test_snapshot',
- 'volume': TEST_VOLUME}
-
-TEST_CLONE = {'name': 'clone1',
- 'size': 1,
- 'volume_name': 'vol1',
- 'id': '391fb914-8a55-4384-a747-588641db3b15',
- 'provider_auth': None,
- 'project_id': 'project',
- 'display_name': 'clone1',
- 'display_description': 'volume created from snapshot',
- 'volume_type_id': None}
-
-ISCSI_INITIATOR = 'iqn.1993-08.org.debian:01:8261afe17e4c'
-TEST_WWPN = ['0123456789111111', '0123456789222222']
-TEST_CONNECTOR = {'initiator': ISCSI_INITIATOR,
- 'wwpns': TEST_WWPN}
-
-STOR_CONF_SVC = 'FUJITSU_StorageConfigurationService'
-CTRL_CONF_SVC = 'FUJITSU_ControllerConfigurationService'
-REPL_SVC = 'FUJITSU_ReplicationService'
-STOR_VOL = 'FUJITSU_StorageVolume'
-SCSI_PROT_CTR = 'FUJITSU_AffinityGroupController'
-STOR_HWID = 'FUJITSU_StorageHardwareID'
-STOR_HWID_MNG_SVC = 'FUJITSU_StorageHardwareIDManagementService'
-STOR_POOL = 'FUJITSU_RAIDStoragePool'
-STOR_POOLS = ['FUJITSU_ThinProvisioningPool', 'FUJITSU_RAIDStoragePool']
-AUTH_PRIV = 'FUJITSU_AuthorizedPrivilege'
-STOR_SYNC = 'FUJITSU_StorageSynchronized'
-PROT_CTRL_UNIT = 'CIM_ProtocolControllerForUnit'
-STORAGE_TYPE = 'abcd1234_TPP'
-LUNMASKCTRL_IDS = ['AFG0010_CM00CA00P00', 'AFG0011_CM01CA00P00']
-
-STORAGE_SYSTEM = '172.16.0.2'
-
-MAP_STAT = '0'
-VOL_STAT = '0'
-
-
-class FJ_StorageVolume(dict):
- pass
-
-
-class FJ_StoragePool(dict):
- pass
-
-
-class FakeDB():
- def volume_get(self, context, volume_id):
- conn = FakeEcomConnection()
- objectpath = {}
- objectpath['CreationClassName'] = STOR_VOL
- if volume_id == '3d6eeb5d-109b-4435-b891-d01415178490':
- return TEST_VOLUME
- else:
- objectpath['DeviceID'] = volume_id
- return conn.GetInstance(objectpath)
-
-
-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/eternus'
- return instancename
-
-
-class FakeEcomConnection():
- def InvokeMethod(self, MethodName, Service, ElementName=None, InPool=None,
- ElementType=None, TheElement=None, LUNames=None,
- Size=None, Type=None, Mode=None, Locality=None,
- InitiatorPortIDs=None, TargetPortIDs=None,
- DeviceAccesses=None, SyncType=None,
- SourceElement=None, TargetElement=None,
- Operation=None,
- Synchronization=None, ProtocolControllers=None,
- TargetPool=None):
- global MAP_STAT, VOL_STAT
- LOG.debug('enter InvokeMethod:MAP_STAT: %s'
- ' VOL_STAT: %s Method: %s' %
- (MAP_STAT, VOL_STAT, MethodName))
- if MethodName == 'CreateOrModifyElementFromStoragePool':
- VOL_STAT = '1'
- rc = 0L
- vol = self._enum_volumes()
- job = {'TheElement': vol[0].path}
- elif MethodName == 'ReturnToStoragePool':
- if MAP_STAT == '1':
- rc = 32787L
- else:
- VOL_STAT = '0'
- rc = 0L
- job = {}
- elif MethodName == 'GetReplicationRelationships':
- rc = 0L
- job = {'Synchronizations': []}
- elif MethodName == 'ExposePaths':
- MAP_STAT = '1'
- rc = 0L
- job = {}
- elif MethodName == 'HidePaths':
- MAP_STAT = '0'
- rc = 0L
- job = {}
- elif MethodName == 'CreateElementReplica':
- rc = 0L
- snap = self._enum_snapshots()
- job = {'TargetElement': snap[0].path}
- elif MethodName == 'CreateReplica':
- rc = 0L
- snap = self._enum_snapshots()
- job = {'TargetElement': snap[0].path}
- elif MethodName == 'ModifyReplicaSynchronization':
- rc = 0L
- job = {}
- else:
- LOG.warn(_LW('method is not exist '))
- raise exception.VolumeBackendAPIException(data="invoke method")
- LOG.debug('exit InvokeMethod:MAP_STAT: %s VOL_STAT: %s'
- ' Method: %s rc: %d job: %s' %
- (MAP_STAT, VOL_STAT, MethodName, rc, job))
-
- return (rc, job)
-
- def EnumerateInstanceNames(self, name):
- LOG.debug('enter EnumerateInstanceNames:MAP_STAT: %s'
- ' VOL_STAT: %s name: %s' %
- (MAP_STAT, VOL_STAT, name))
- result = []
- if name == 'FUJITSU_StorageVolume':
- result = self._enum_volumes()
- elif name == 'FUJITSU_StorageConfigurationService':
- result = self._enum_confservice()
- elif name == 'FUJITSU_ReplicationService':
- result = self._enum_repservice()
- elif name == 'FUJITSU_ControllerConfigurationService':
- result = self._enum_ctrlservice()
- elif name == 'FUJITSU_AffinityGrouopController':
- result = self._enum_afntyservice()
- elif name == 'FUJITSU_StorageHardwareIDManagementService':
- result = self._enum_sthwidmngsvc()
- elif name == 'CIM_ProtocolControllerForUnit':
- result = self._ref_unitnames()
- elif name == 'CIM_StoragePool':
- result = self._enum_pools()
-
- LOG.debug('exit EnumerateInstanceNames: %s' % result)
-
- return result
-
- def EnumerateInstances(self, name):
- LOG.debug('enter EnumerateInstances:MAP_STAT: %s'
- ' VOL_STAT: %s name: %s' %
- (MAP_STAT, VOL_STAT, name))
- result = None
- if name == 'FUJITSU_StorageProduct':
- result = self._enum_sysnames()
- elif name == STOR_POOL:
- result = self._enum_pool_details('RAID')
- elif name == 'FUJITSU_ThinProvisioningPool':
- result = self._enum_pool_details('TPP')
- elif name == 'FUJITSU_SCSIProtocolEndpoint':
- result = self._enum_scsiprot_endpoint()
- elif name == 'FUJITSU_iSCSIProtocolEndpoint':
- result = self._enum_iscsiprot_endpoint()
- elif name == 'FUJITSU_StorageHardwareID':
- result = self._enum_sthwid()
- elif name == 'CIM_StoragePool':
- result = self._enum_pool_details()
- elif name == 'CIM_SCSIProtocolEndpoint':
- result = self._enum_scsiport_endpoint()
- elif name == 'FUJITSU_StorageHardwareID':
- result = None
- else:
- result = None
- LOG.debug('exit EnumerateInstanceNames: %s' % result)
-
- return result
-
- def GetInstance(self, objectpath, LocalOnly=False):
- LOG.debug('enter GetInstance:MAP_STAT: %s VOL_STAT: %s obj: %s' %
- (MAP_STAT, VOL_STAT, objectpath))
- try:
- name = objectpath['CreationClassName']
- except KeyError:
- name = objectpath.classname
-
- result = None
-
- if name == 'FUJITSU_StorageVolume':
- result = self._getinstance_storagevolume(objectpath)
- elif name == 'CIM_ProtocolControllerForUnit':
- result = self._getinstance_unit(objectpath)
-
- LOG.debug('exit GetInstance: %s' % result)
-
- return result
-
- def Associators(self, objectpath, ResultClass='FUJITSU_StorageHardwareID'):
- result = None
- if ResultClass == 'FUJITSU_StorageHardwareID':
- result = self._assoc_hdwid()
- elif ResultClass == 'FUJITSU_iSCSIProtocolEndpoint':
- result = self._assoc_endpoint()
- elif ResultClass == 'FUJITSU_StorageVolume':
- result = self._assoc_storagevolume(objectpath)
- elif ResultClass == 'FUJITSU_AuthorizedPrivilege':
- result = self._assoc_authpriv()
- else:
- result = self._default_assoc(objectpath)
- LOG.debug('exit Assocs: %s' % result)
- return result
-
- def AssociatorNames(self, objectpath,
- ResultClass=SCSI_PROT_CTR):
- result = None
- if ResultClass == SCSI_PROT_CTR:
- result = self._assocnames_lunmaskctrl()
- else:
- result = self._default_assocnames(objectpath)
- LOG.debug('exit AssocNames: %s' % result)
- return result
-
- def ReferenceNames(self, objectpath,
- ResultClass='CIM_ProtocolControllerForUnit'):
- result = []
- LOG.debug('ReferenceNames:MAP_STAT: %s' % MAP_STAT)
- if ResultClass == 'CIM_ProtocolControllerForUnit':
- if MAP_STAT == '1':
- result = self._ref_unitnames()
- else:
- result = []
- else:
- result = self._default_ref(objectpath)
- LOG.debug('ReferenceNames %s' % result)
- return result
-
- def _ref_unitnames(self):
- unitnames = []
-
- unitname = {}
- dependent = {}
- dependent['CreationClassName'] = STOR_VOL
- dependent['DeviceID'] = '600000E00D2A0000002A011500140000'
- dependent['SystemName'] = STORAGE_SYSTEM
-
- antecedent = {}
- antecedent['CreationClassName'] = SCSI_PROT_CTR
- antecedent['DeviceID'] = LUNMASKCTRL_IDS[0]
- antecedent['SystemName'] = STORAGE_SYSTEM
-
- unitname['Dependent'] = dependent
- unitname['Antecedent'] = antecedent
- unitname['CreationClassName'] = PROT_CTRL_UNIT
- unitnames.append(unitname)
-
- unitname2 = {}
- dependent2 = {}
- dependent2['CreationClassName'] = STOR_VOL
- dependent2['DeviceID'] = '600000E00D2A0000002A011500140000'
- dependent2['SystemName'] = STORAGE_SYSTEM
-
- antecedent2 = {}
- antecedent2['CreationClassName'] = SCSI_PROT_CTR
- antecedent2['DeviceID'] = LUNMASKCTRL_IDS[1]
- antecedent2['SystemName'] = STORAGE_SYSTEM
-
- unitname2['Dependent'] = dependent2
- unitname2['Antecedent'] = antecedent2
- unitname2['CreationClassName'] = PROT_CTRL_UNIT
- unitnames.append(unitname2)
-
- LOG.debug('_ref_unitnames,unitnames: %s' % str(unitnames))
- return unitnames
-
- def _default_ref(self, objectpath):
- return objectpath
-
- def _default_assoc(self, objectpath):
- return objectpath
-
- def _assocnames_lunmaskctrl(self):
- return self._enum_lunmaskctrls()
-
- def _default_assocnames(self, objectpath):
- return objectpath
-
- def _assoc_authpriv(self):
- authprivs = []
- iscsi = {}
- iscsi['InstanceID'] = ISCSI_INITIATOR
- authprivs.append(iscsi)
-
- fc = {}
- fc['InstanceID'] = TEST_WWPN[0]
- authprivs.append(fc)
-
- fc1 = {}
- fc1['InstanceID'] = TEST_WWPN[1]
- authprivs.append(fc1)
-
- LOG.debug('exit _assoc_authpriv: %s' % authprivs)
-
- return authprivs
-
- def _getinstance_unit(self, objectpath):
- unit = {}
- LOG.debug('enter _getinstance_unit:MAP_STAT: %s' % MAP_STAT)
-
- if MAP_STAT == '0':
- return unit
- dependent = {}
- dependent['CreationClassName'] = STOR_VOL
- dependent['DeviceID'] = '600000E00D2A0000002A011500140000'
- dependent['ElementName'] = TEST_VOLUME['name']
- dependent['SystemName'] = STORAGE_SYSTEM
-
- antecedent = {}
- antecedent['CreationClassName'] = SCSI_PROT_CTR
- antecedent['DeviceID'] = LUNMASKCTRL_IDS[0]
- antecedent['SystemName'] = STORAGE_SYSTEM
-
- unit['Dependent'] = dependent
- unit['Antecedent'] = antecedent
- unit['CreationClassName'] = PROT_CTRL_UNIT
- unit['DeviceNumber'] = '0'
-
- LOG.debug("exit _getinstance_unit,unit: %s" % str(unit))
- return unit
-
- def _enum_sysnames(self):
- sysnamelist = []
- sysname = {}
- sysname['IdentifyingNumber'] = 'ET603SA4621302115'
- sysnamelist.append(sysname)
- return sysnamelist
-
- def _enum_confservice(self):
- services = []
- service = {}
- service['Name'] = 'FUJITSU:ETERNUS SMI-S Agent'
- service['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- service['SystemName'] = STORAGE_SYSTEM
- service['CreationClassName'] = 'FUJITSU_StorageConfigurationService'
- services.append(service)
- return services
-
- def _enum_ctrlservice(self):
- services = []
- service = {}
- service['SystemName'] = STORAGE_SYSTEM
- service['CreationClassName'] = 'FUJITSU_ControllerConfigurationService'
- services.append(service)
- return services
-
- def _enum_afntyservice(self):
- services = []
- service = {}
- service['SystemName'] = STORAGE_SYSTEM
- service['CreationClassName'] = 'FUJITSU_AffinityGroupController'
- services.append(service)
- return services
-
- def _enum_repservice(self):
- services = []
- service = {}
- service['Name'] = 'FUJITSU:ETERNUS SMI-S Agent'
- service['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- service['SystemName'] = STORAGE_SYSTEM
- service['CreationClassName'] = 'FUJITSU_ReplicationService'
- services.append(service)
- return services
-
- def _enum_pools(self):
- pools = []
- pool = {}
- pool['InstanceID'] = 'FUJITSU:RSP0004'
- pool['CreationClassName'] = 'FUJITSU_RAIDStoragePool'
- pools.append(pool)
-
- pool2 = {}
- pool2['InstanceID'] = 'FUJITSU:TPP0004'
- pool2['CreationClassName'] = 'FUJITSU_ThinProvisioningPool'
- pools.append(pool2)
- return pools
-
- def _enum_pool_details(self):
- pools = []
-
- pool = FJ_StoragePool()
- pool['InstanceID'] = 'FUJITSU:RSP0004'
- pool['CreationClassName'] = 'FUJITSU_RAIDStoragePool'
- pool['ElementName'] = 'abcd1234_OSVD'
- pool['TotalManagedSpace'] = 1170368102400
- pool['RemainingManagedSpace'] = 1170368102400
- pool.path = pool
- pool.path.classname = 'FUJITSU_RAIDStoragePool'
- pools.append(pool)
-
- pool2 = FJ_StoragePool()
- pool2['InstanceID'] = 'FUJITSU:TPP0004'
- pool2['CreationClassName'] = 'FUJITSU_ThinProvisioningPool'
- pool2['ElementName'] = 'abcd1234_TPP'
- pool2['TotalManagedSpace'] = 1170368102400
- pool2['RemainingManagedSpace'] = 1170368102400
- pool2.path = pool2
- pool2.path.classname = 'FUJITSU_ThinProvisioningPool'
- pools.append(pool2)
- return pools
-
- def _enum_volumes(self):
- volumes = []
- if VOL_STAT == '0':
- return volumes
- volume = FJ_StorageVolume()
- volume['name'] = TEST_VOLUME['name']
- volume['CreationClassName'] = 'FUJITSU_StorageVolume'
- volume['Name'] = '600000E00D2A0000002A011500140000'
- volume['DeviceID'] = '600000E00D2A0000002A011500140000'
- volume['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- volume['SystemName'] = STORAGE_SYSTEM
- volume['ElementName'] = 'FJosv_0qJ4rpOHgFE8ipcJOMfBmg=='
- volume['volume_type_id'] = None
- volume.path = volume
- volume.path.classname = volume['CreationClassName']
-
- name = {}
- name['classname'] = 'FUJITSU_StorageVolume'
- keys = {}
- keys['CreationClassName'] = 'FUJITSU_StorageVolume'
- keys['SystemName'] = STORAGE_SYSTEM
- keys['DeviceID'] = volume['DeviceID']
- keys['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- name['keybindings'] = keys
- volume['provider_location'] = str(name)
-
- volumes.append(volume)
-
- snap_vol = FJ_StorageVolume()
- snap_vol['name'] = TEST_SNAP['name']
- snap_vol['CreationClassName'] = 'FUJITSU_StorageVolume'
- snap_vol['Name'] = '600000E00D2A0000002A0115001E0000'
- snap_vol['DeviceID'] = '600000E00D2A0000002A0115001E0000'
- snap_vol['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- snap_vol['SystemName'] = STORAGE_SYSTEM
- snap_vol['ElementName'] = 'FJosv_OgEZj1mSvKRvIKOExKktlg=='
- snap_vol.path = snap_vol
- snap_vol.path.classname = snap_vol['CreationClassName']
-
- name2 = {}
- name2['classname'] = 'FUJITSU_StorageVolume'
- keys2 = {}
- keys2['CreationClassName'] = 'FUJITSU_StorageVolume'
- keys2['SystemName'] = STORAGE_SYSTEM
- keys2['DeviceID'] = snap_vol['DeviceID']
- keys2['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- name2['keybindings'] = keys2
- snap_vol['provider_location'] = str(name2)
-
- volumes.append(snap_vol)
-
- clone_vol = FJ_StorageVolume()
- clone_vol['name'] = TEST_CLONE['name']
- clone_vol['CreationClassName'] = 'FUJITSU_StorageVolume'
- clone_vol['ElementName'] = TEST_CLONE['name']
- clone_vol['DeviceID'] = '600000E00D2A0000002A0115001E0000'
- clone_vol['SystemName'] = STORAGE_SYSTEM
- clone_vol['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- clone_vol.path = clone_vol
- clone_vol.path.classname = clone_vol['CreationClassName']
- volumes.append(clone_vol)
-
- return volumes
-
- def _enum_snapshots(self):
- snapshots = []
- snap = FJ_StorageVolume()
- snap['CreationClassName'] = 'FUJITSU_StorageVolume'
- snap['SystemName'] = STORAGE_SYSTEM
- snap['DeviceID'] = '600000E00D2A0000002A0115001E0000'
- snap['SystemCreationClassName'] = 'FUJITSU_StorageComputerSystem'
- snap.path = snap
- snap.path.classname = snap['CreationClassName']
-
- snapshots.append(snap)
-
- return snapshots
-
- def _enum_lunmaskctrls(self):
- ctrls = []
- ctrl = {}
- ctrl2 = {}
- LOG.debug('enter _enum_lunmaskctrls:MAP_STAT: %s' % MAP_STAT)
- if MAP_STAT == '1':
- ctrl['CreationClassName'] = SCSI_PROT_CTR
- ctrl['SystemName'] = STORAGE_SYSTEM
- ctrl['DeviceID'] = LUNMASKCTRL_IDS[0]
- ctrls.append(ctrl)
-
- ctrl2['CreationClassName'] = SCSI_PROT_CTR
- ctrl2['SystemName'] = STORAGE_SYSTEM
- ctrl2['DeviceID'] = LUNMASKCTRL_IDS[1]
- ctrls.append(ctrl2)
-
- LOG.debug('exit _enum_lunmaskctrls:ctrls: %s' % ctrls)
- return ctrls
-
- def _enum_scsiport_endpoint(self):
- targetlist = []
- tgtport1 = {}
- tgtport1['Name'] = '1234567890000021'
- tgtport1['CreationClassName'] = 'FUJITSU_SCSIProtocolEndpoint'
- tgtport1['ConnectionType'] = 2
- tgtport1['RAMode'] = 0
- targetlist.append(tgtport1)
-
- tgtport2 = {}
- tgtport2['Name'] = '1234567890000031'
- tgtport2['CreationClassName'] = 'FUJITSU_SCSIProtocolEndpoint'
- tgtport2['ConnectionType'] = 2
- tgtport2['RAMode'] = 0
- targetlist.append(tgtport2)
-
- tgtport3 = {}
- tgtport3['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dxl:0123456789,t,0x0009')
- tgtport3['CreationClassName'] = 'FUJITSU_iSCSIProtocolEndpoint'
- tgtport3['ConnectionType'] = 7
- tgtport3['RAMode'] = 0
- targetlist.append(tgtport3)
-
- tgtport4 = {}
- tgtport4['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dxl:1234567890,t,0x000A')
- tgtport4['CreationClassName'] = 'FUJITSU_iSCSIProtocolEndpoint'
- tgtport4['ConnectionType'] = 7
- tgtport4['RAMode'] = 0
- targetlist.append(tgtport4)
-
- return targetlist
-
- def _enum_iscsiprot_endpoint(self):
- targetlist = []
- tgtport1 = {}
- tgtport1['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dxl:0123456789,t,0x0009')
- tgtport1['ConnectionType'] = 7
- tgtport1['RAMode'] = 0
- targetlist.append(tgtport1)
-
- tgtport2 = {}
- tgtport2['Name'] = ('iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dxl:1234567890,t,0x000A')
- tgtport2['ConnectionType'] = 7
- tgtport2['RAMode'] = 0
- targetlist.append(tgtport2)
-
- return targetlist
-
- def _getinstance_storagevolume(self, objpath):
- foundinstance = None
- instance = FJ_StorageVolume()
- volumes = self._enum_volumes()
- for volume in volumes:
- LOG.debug('_getinstance_storagevolume: volume-DeviceID: %s'
- ' objpath-DeviceID: %s' %
- (volume['DeviceID'], objpath['DeviceID']))
- if volume['DeviceID'] == objpath['DeviceID']:
- instance = volume
- break
- if not instance:
- foundinstance = None
- else:
- foundinstance = instance
- return foundinstance
-
-
-class FJFCDriverTestCase(test.TestCase):
- def __init__(self, *args, **kwargs):
- super(FJFCDriverTestCase, self).__init__(*args, **kwargs)
-
- def setUp(self):
- super(FJFCDriverTestCase, self).setUp()
-
- # make fake xml-configuration file
- (handle, self.config_file) = tempfile.mkstemp('.xml')
- os.write(handle, CONF)
- os.close(handle)
-
- # make fake Object by using mock as configuration object
- self.configuration = mock.Mock()
- self.configuration.cinder_smis_config_file = self.config_file
-
- # replace some configuration function with fake
- # self.stubs.Set(self.driver.configuration, 'safe_get',
- # self.fake_configuration_safe_get)
- self.stubs.Set(eternus_dx_common.FJDXCommon, '_get_ecom_connection',
- self.fake_ecom_connection)
-
- instancename = FakeCIMInstanceName()
- self.stubs.Set(eternus_dx_common.FJDXCommon, '_getinstancename',
- instancename.fake_getinstancename)
-
- # set fc driver to self.driver
- driver = eternus_dx_fc.FJDXFCDriver(configuration=self.configuration)
- driver.db = FakeDB()
- self.driver = driver
-
- def tearDown(self):
- os.remove(self.config_file)
- super(FJFCDriverTestCase, self).tearDown()
-
- def fake_ecom_connection(self):
- conn = FakeEcomConnection()
- return conn
-
- def test_get_volume_stats(self):
- self.driver.get_volume_stats(True)
-
- def test_create_and_delete_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_map_unmap(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.initialize_connection(TEST_VOLUME,
- TEST_CONNECTOR)
- self.driver.terminate_connection(TEST_VOLUME,
- TEST_CONNECTOR)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_and_delete_snapshot(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_snapshot(TEST_SNAP)
- self.driver.delete_snapshot(TEST_SNAP)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_volume_from_snapshot(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_snapshot(TEST_SNAP)
- self.driver.create_volume_from_snapshot(TEST_CLONE, TEST_SNAP)
- self.driver.delete_snapshot(TEST_SNAP)
- self.driver.delete_volume(TEST_CLONE)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_cloned_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME)
- self.driver.delete_volume(TEST_CLONE)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_extend_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.extend_volume(TEST_VOLUME, '10')
-
-
-class FJISCSIDriverTestCase(test.TestCase):
- def __init__(self, *args, **kwargs):
- super(FJISCSIDriverTestCase, self).__init__(*args, **kwargs)
-
- def setUp(self):
- super(FJISCSIDriverTestCase, self).setUp()
-
- # make fake xml-configuration file
- (handle, self.config_file) = tempfile.mkstemp('.xml')
- os.write(handle, CONF)
- os.close(handle)
-
- # make fake Object by using mock as configuration object
- self.configuration = mock.Mock()
- self.configuration.cinder_smis_config_file = self.config_file
- self.configuration.iscsi_target_prefix = 'iqn.2000-09.com.fujitsu'
- self.configuration.iscsi_ip_address = '192.168.0.22'
-
- # replace some configuration function with fake
- # self.stubs.Set(self.driver.configuration, 'safe_get',
- # self.fake_configuration_safe_get)
-
- self.stubs.Set(eternus_dx_iscsi.FJDXISCSIDriver,
- '_do_iscsi_discovery',
- self.fake_do_iscsi_discovery)
-
- self.stubs.Set(eternus_dx_common.FJDXCommon,
- '_get_ecom_connection',
- self.fake_ecom_connection)
-
- instancename = FakeCIMInstanceName()
- self.stubs.Set(eternus_dx_common.FJDXCommon,
- '_getinstancename',
- instancename.fake_getinstancename)
-
- # set iscsi driver to self.driver
- driver = (
- eternus_dx_iscsi.FJDXISCSIDriver(configuration=self.configuration))
- driver.db = FakeDB()
- self.driver = driver
-
- def tearDown(self):
- os.remove(self.config_file)
- super(FJISCSIDriverTestCase, self).tearDown()
-
- def fake_ecom_connection(self):
- conn = FakeEcomConnection()
- return conn
-
- def fake_do_iscsi_discovery(self, volume):
- output = []
- item = ('10.0.0.3:3260,1 iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dx400:00040001,t,0x0009')
- item2 = ('10.0.0.4:3260,2 iqn.2000-09.com.fujitsu:storage-system.'
- 'eternus-dx400:00040001,t,0x000A')
- output.append(item)
- output.append(item2)
- return output
-
- def test_get_volume_stats(self):
- self.driver.get_volume_stats(True)
-
- def test_create_and_delete_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_map_unmap(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.initialize_connection(TEST_VOLUME,
- TEST_CONNECTOR)
- self.driver.terminate_connection(TEST_VOLUME,
- TEST_CONNECTOR)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_and_delete_snapshot(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_snapshot(TEST_SNAP)
- self.driver.delete_snapshot(TEST_SNAP)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_volume_from_snapshot(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_snapshot(TEST_SNAP)
- self.driver.create_volume_from_snapshot(TEST_CLONE, TEST_SNAP)
- self.driver.delete_snapshot(TEST_SNAP)
- self.driver.delete_volume(TEST_CLONE)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_create_cloned_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.create_cloned_volume(TEST_CLONE, TEST_VOLUME)
- self.driver.delete_volume(TEST_CLONE)
- self.driver.delete_volume(TEST_VOLUME)
-
- def test_extend_volume(self):
- self.driver.create_volume(TEST_VOLUME)
- self.driver.extend_volume(TEST_VOLUME, '10')
+++ /dev/null
-# Copyright (c) 2014 FUJITSU LIMITED
-# Copyright (c) 2012 - 2014 EMC Corporation.
-# 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.
-"""
-Common class for SMI-S based FUJITSU ETERNUS DX volume drivers.
-
-This common class is for FUJITSU ETERNUS DX volume drivers based on SMI-S.
-
-"""
-
-import base64
-import hashlib
-import time
-from xml.dom import minidom
-
-from oslo_config import cfg
-from oslo_log import log as logging
-from oslo_utils import units
-import six
-
-from cinder import exception
-from cinder.i18n import _, _LE, _LI, _LW
-from cinder.openstack.common import loopingcall
-from cinder.volume import volume_types
-
-LOG = logging.getLogger(__name__)
-
-CONF = cfg.CONF
-
-try:
- import pywbem
-except ImportError:
- pass
-
-CINDER_CONFIG_FILE = '/etc/cinder/cinder_fujitsu_eternus_dx.xml'
-SMIS_ROOT = 'root/eternus'
-PROVISIONING = 'storagetype:provisioning'
-POOL = 'storagetype:pool'
-STOR_CONF_SVC = 'FUJITSU_StorageConfigurationService'
-SCSI_PROT_CTR = 'FUJITSU_AffinityGroupController'
-STOR_HWID = 'FUJITSU_StorageHardwareID'
-CTRL_CONF_SVC = 'FUJITSU_ControllerConfigurationService'
-STOR_HWID_MNG_SVC = 'FUJITSU_StorageHardwareIDManagementService'
-STOR_VOL = 'FUJITSU_StorageVolume'
-REPL_SVC = 'FUJITSU_ReplicationService'
-STOR_POOLS = ['FUJITSU_ThinProvisioningPool', 'FUJITSU_RAIDStoragePool']
-AUTH_PRIV = 'FUJITSU_AuthorizedPrivilege'
-STOR_SYNC = 'FUJITSU_StorageSynchronized'
-VOL_PREFIX = 'FJosv_'
-
-drv_opts = [
- cfg.StrOpt('cinder_smis_config_file',
- default=CINDER_CONFIG_FILE,
- help='The configuration file for the Cinder '
- 'SMI-S driver'), ]
-
-CONF.register_opts(drv_opts)
-
-BROKEN = 5
-SNAPOPC = 4
-OPC = 5
-RETURN_TO_RESOURCEPOOL = 19
-DETACH = 8
-JOB_RETRIES = 60
-INTERVAL_10_SEC = 10
-
-OPERATION_dic = {SNAPOPC: RETURN_TO_RESOURCEPOOL,
- OPC: DETACH
- }
-
-RETCODE_dic = {'0': 'Success',
- '1': 'Method Not Supported',
- '4': 'Failed',
- '5': 'Invalid Parameter',
- '4097': 'Size Not Supported',
- '32769': 'Maximum number of Logical Volume in'
- ' a RAID group has been reached',
- '32770': 'Maximum number of Logical Volume in'
- ' the storage device has been reached',
- '32771': 'Maximum number of registered Host WWN'
- ' has been reached',
- '32772': 'Maximum number of affinity group has been reached',
- '32773': 'Maximum number of host affinity has been reached',
- '32785': 'The RAID group is in busy state',
- '32786': 'The Logical Volume is in busy state',
- '32787': 'The device is in busy state',
- '32788': 'Element Name is in use',
- '32792': 'No Copy License',
- '32796': 'Quick Format Error',
- '32801': 'The CA port is in invalid setting',
- '32802': 'The Logical Volume is Mainframe volume',
- '32803': 'The RAID group is not operative',
- '32804': 'The Logical Volume is not operative',
- '32808': 'No Thin Provisioning License',
- '32809': 'The Logical Element is ODX volume',
- '32811': 'This operation cannot be performed'
- ' to the NAS resources',
- '32812': 'This operation cannot be performed'
- ' to the Storage'
- ' Cluster resources',
- '32816': 'Fatal error generic',
- '35302': 'Invalid LogicalElement',
- '35304': 'LogicalElement state error',
- '35316': 'Multi-hop error',
- '35318': 'Maximum number of multi-hop has been reached',
- '35324': 'RAID is broken',
- '35331': 'Maximum number of session has been reached'
- '(per device)',
- '35333': 'Maximum number of session has been reached'
- '(per SourceElement)',
- '35334': 'Maximum number of session has been reached'
- '(per TargetElement)',
- '35335': 'Maximum number of Snapshot generation has been'
- ' reached (per SourceElement)',
- '35346': 'Copy table size is not setup',
- '35347': 'Copy table size is not enough'
- }
-
-
-class FJDXCommon(object):
- """Common code that can be used by ISCSI and FC drivers."""
-
- stats = {'driver_version': '1.2',
- 'free_capacity_gb': 0,
- 'reserved_percentage': 0,
- 'storage_protocol': None,
- 'total_capacity_gb': 0,
- 'vendor_name': 'FUJITSU',
- 'volume_backend_name': None}
-
- def __init__(self, prtcl, configuration=None):
-
- self.protocol = prtcl
- self.configuration = configuration
- self.configuration.append_config_values(drv_opts)
-
- ip, port = self._get_ecom_server()
- self.user, self.passwd = self._get_ecom_cred()
- self.url = 'http://' + ip + ':' + port
- self.conn = self._get_ecom_connection()
-
- def create_volume(self, volume):
- """Creates a volume."""
- LOG.debug('Entering create_volume.')
- volumesize = int(volume['size']) * units.Gi
- volumename = self._create_volume_name(volume['id'])
-
- LOG.info(_LI('Create Volume: %(volume)s Size: %(size)lu')
- % {'volume': volumename,
- 'size': volumesize})
-
- self.conn = self._get_ecom_connection()
-
- 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])
-
- LOG.debug('Create Volume: %(volume)s Pool: %(pool)s '
- 'Storage System: %(storage_system)s'
- % {'volume': volumename,
- 'pool': pool,
- 'storage_system': storage_system})
-
- configservice = self._find_storage_configuration_service(
- storage_system)
- if configservice is None:
- exception_message = (_("Error Create Volume: %(volumename)s. "
- "Storage Configuration Service not found "
- "for pool %(storage_type)s.")
- % {'volumename': volumename,
- 'storage_type': storage_type})
- 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: %(provisioning)s Size: %(size)lu'
- % {'service': configservice,
- 'name': volumename,
- 'pool': pool,
- 'provisioning': provisioning,
- 'size': volumesize})
-
- rc, job = self.conn.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- configservice, ElementName=volumename, InPool=pool,
- ElementType=self._getnum(provisioning, '16'),
- Size=self._getnum(volumesize, '64'))
-
- LOG.debug('Create Volume: %(volumename)s Return code: %(rc)lu'
- % {'volumename': volumename,
- 'rc': rc})
-
- if rc == 5L:
- # for DX S2
- # retry with 16 digit of volume name
- volumename = volumename[:16]
- LOG.debug('Retry with 16 digit of volume name.'
- 'Create Volume: %(name)s Method: '
- 'CreateOrModifyElementFromStoragePool'
- ' ConfigServicie: %(service)s'
- ' ElementName: %(name)s InPool: %(pool)s '
- 'ElementType: %(provisioning)s Size: %(size)lu'
- % {'service': configservice,
- 'name': volumename,
- 'pool': pool,
- 'provisioning': provisioning,
- 'size': volumesize})
-
- rc, job = self.conn.InvokeMethod(
- 'CreateOrModifyElementFromStoragePool',
- configservice, ElementName=volumename, InPool=pool,
- ElementType=self._getnum(provisioning, '16'),
- Size=self._getnum(volumesize, '64'))
-
- LOG.debug('Create Volume: %(volumename)s Return code: %(rc)lu'
- % {'volumename': volumename,
- 'rc': rc})
-
- if rc != 0L:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- LOG.error(_LE('Error Create Volume: %(volumename)s. '
- 'Return code: %(rc)lu. Error: %(error)s')
- % {'volumename': volumename,
- 'rc': rc,
- 'error': errordesc})
- raise exception.VolumeBackendAPIException(data=errordesc)
-
- # Find the newly created volume
- if "job" in job:
- associators = self.conn.Associators(
- job['Job'],
- resultClass=STOR_VOL)
- volpath = associators[0].path
- else: # for ETERNUS DX
- volpath = job['TheElement']
-
- 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 '
- 'volume instance: %(name)s'
- % {'volumename': volumename,
- 'rc': rc,
- 'name': name})
-
- return name
-
- def create_volume_from_snapshot(self, volume, snapshot):
- """Creates a volume from a snapshot."""
-
- LOG.debug('Entering create_volume_from_snapshot.')
-
- snapshotname = snapshot['name']
- volumename = self._create_volume_name(volume['id'])
- vol_instance = None
-
- LOG.info(_LI('Create Volume from Snapshot: Volume: %(volumename)s '
- 'Snapshot: %(snapshotname)s')
- % {'volumename': volumename,
- 'snapshotname': snapshotname})
-
- self.conn = self._get_ecom_connection()
-
- snapshot_instance = self._find_lun(snapshot)
- storage_system = snapshot_instance['SystemName']
-
- LOG.debug('Create Volume from Snapshot: Volume: %(volumename)s '
- 'Snapshot: %(snapshotname)s Snapshot Instance: '
- '%(snapshotinstance)s Storage System: %(storage_system)s.'
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'snapshotinstance': snapshot_instance.path,
- 'storage_system': storage_system})
-
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- exception_message = (_('Error Create Volume from Snapshot: '
- 'Volume: %(volumename)s Snapshot: '
- '%(snapshotname)s. Cannot find Replication '
- 'Service to create volume from snapshot.')
- % {'volumename': volumename,
- 'snapshotname': snapshotname})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- LOG.debug('Create Volume from Snapshot: Volume: %(volumename)s '
- 'Snapshot: %(snapshotname)s Method: CreateElementReplica '
- 'ReplicationService: %(service)s ElementName: '
- '%(elementname)s SyncType: 8 SourceElement: '
- '%(sourceelement)s'
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'service': repservice,
- 'elementname': volumename,
- 'sourceelement': snapshot_instance.path})
-
- # Create a Clone from snapshot
- name = self.create_volume(volume)
- instancename = self._getinstancename(name['classname'],
- name['keybindings'])
- vol_instance = self.conn.GetInstance(instancename)
-
- rc, job = self.conn.InvokeMethod(
- 'CreateElementReplica', repservice,
- ElementName=volumename,
- SyncType=self._getnum(8, '16'),
- SourceElement=snapshot_instance.path,
- TargetElement=vol_instance.path)
-
- if rc != 0L:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- exception_message = (_('Error Create Volume from Snapshot: '
- 'Volume: %(volumename)s Snapshot:'
- '%(snapshotname)s. '
- 'Return code: %(rc)lu.'
- 'Error: %(error)s')
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exception_message)
- volume['provider_location'] = six.text_type(name)
- self.delete_volume(volume)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- # Find the newly created volume
- if "job" in job:
- associators = self.conn.Associators(
- job['Job'],
- resultClass=STOR_VOL)
- volpath = associators[0].path
- else: # for ETERNUS DX
- volpath = job['TargetElement']
-
- 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_from_snapshot: Volume: '
- '%(volumename)s Snapshot: %(snapshotname)s '
- 'Return code: %(rc)lu.'
- % {'volumename': volumename,
- '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.')
-
- srcname = self._create_volume_name(src_vref['id'])
- volumename = self._create_volume_name(volume['id'])
-
- LOG.info(_LI('Create a Clone from Volume: Volume: %(volumename)s '
- 'Source Volume: %(srcname)s')
- % {'volumename': volumename,
- 'srcname': srcname})
-
- self.conn = self._get_ecom_connection()
-
- src_instance = self._find_lun(src_vref)
- storage_system = src_instance['SystemName']
-
- LOG.debug('Create Cloned Volume: Volume: %(volumename)s '
- 'Source Volume: %(srcname)s Source Instance: '
- '%(src_instance)s Storage System: %(storage_system)s.'
- % {'volumename': volumename,
- 'srcname': srcname,
- 'src_instance': src_instance.path,
- 'storage_system': storage_system})
-
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- exception_message = (_('Error Create Cloned Volume: '
- 'Volume: %(volumename)s Source Volume: '
- '%(srcname)s. Cannot find Replication '
- 'Service to create cloned volume.')
- % {'volumename': volumename,
- 'srcname': srcname})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- LOG.debug('Create Cloned Volume: Volume: %(volumename)s '
- 'Source Volume: %(srcname)s Method: CreateElementReplica '
- 'ReplicationService: %(service)s ElementName: '
- '%(elementname)s SyncType: 8 SourceElement: '
- '%(sourceelement)s'
- % {'volumename': volumename,
- 'srcname': srcname,
- 'service': repservice,
- 'elementname': volumename,
- 'sourceelement': src_instance.path})
-
- # Create a Clone from source volume
- name = self.create_volume(volume)
- instancename = self._getinstancename(name['classname'],
- name['keybindings'])
- vol_instance = self.conn.GetInstance(instancename)
-
- rc, job = self.conn.InvokeMethod(
- 'CreateElementReplica', repservice,
- ElementName=volumename,
- SyncType=self._getnum(8, '16'),
- SourceElement=src_instance.path,
- TargetElement=vol_instance.path)
-
- if rc != 0L:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- exception_message = (_('Error Create Cloned Volume: '
- 'Volume: %(volumename)s Source Volume:'
- '%(srcname)s. Return code: %(rc)lu.'
- 'Error: %(error)s')
- % {'volumename': volumename,
- 'srcname': srcname,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exception_message)
- volume['provider_location'] = six.text_type(name)
- self.delete_volume(volume)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- # Find the newly created volume
- if "job" in job:
- associators = self.conn.Associators(
- job['Job'],
- resultClass=STOR_VOL)
- volpath = associators[0].path
- else: # for ETERNUS DX
- volpath = job['TargetElement']
- 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_cloned_volume: Volume: '
- '%(volumename)s Source Volume: %(srcname)s '
- 'Return code: %(rc)lu.'
- % {'volumename': volumename,
- 'srcname': srcname,
- 'rc': rc})
-
- return name
-
- def delete_volume(self, volume):
- """Deletes an volume."""
- LOG.debug('Entering delete_volume.')
- volumename = self._create_volume_name(volume['id'])
- LOG.info(_LI('Delete Volume: %(volume)s')
- % {'volume': volumename})
-
- self.conn = self._get_ecom_connection()
-
- cpsession, storage_system = self._find_copysession(volume)
- if cpsession is not None:
- LOG.debug('delete_volume,volumename:%(volumename)s,'
- 'volume is using by copysession[%(cpsession)s].'
- 'delete copysession.'
- % {'volumename': volumename,
- 'cpsession': cpsession})
- self._delete_copysession(storage_system, cpsession)
-
- vol_instance = self._find_lun(volume)
- if vol_instance is None:
- LOG.error(_LE('Volume %(name)s not found on the array. '
- 'No volume to delete.')
- % {'name': volumename})
- return
-
- configservice =\
- self._find_storage_configuration_service(storage_system)
- if configservice is None:
- exception_message = (_("Error Delete Volume: %(volumename)s. "
- "Storage Configuration Service not found.")
- % {'volumename': volumename})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- device_id = vol_instance['DeviceID']
-
- LOG.debug('Delete Volume: %(name)s DeviceID: %(deviceid)s'
- % {'name': volumename,
- 'deviceid': device_id})
-
- LOG.debug('Delete Volume: %(name)s Method: ReturnToStoragePool '
- 'ConfigServic: %(service)s TheElement: %(vol_instance)s'
- % {'service': configservice,
- 'name': volumename,
- 'vol_instance': vol_instance.path})
-
- rc, job =\
- self.conn.InvokeMethod('ReturnToStoragePool',
- configservice,
- TheElement=vol_instance.path)
-
- if rc != 0L:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
- if rc != 0L:
- exception_message = (_('Error Delete Volume: %(volumename)s. '
- 'Return code: %(rc)lu. '
- 'Error: %(error)s')
- % {'volumename': volumename,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- LOG.debug('Leaving delete_volume: %(volumename)s Return code: '
- '%(rc)lu'
- % {'volumename': volumename,
- 'rc': rc})
-
- def create_snapshot(self, snapshot, volume):
- """Creates a snapshot."""
- LOG.debug('Entering create_snapshot.')
-
- snapshotname = self._create_volume_name(snapshot['id'])
- volumename = snapshot['volume_name']
- LOG.info(_LI('Create snapshot: %(snapshot)s: volume: %(volume)s')
- % {'snapshot': snapshotname,
- 'volume': volumename})
-
- self.conn = self._get_ecom_connection()
-
- vol_instance = self._find_lun(volume)
-
- device_id = vol_instance['DeviceID']
- snappool = self._get_snappool_conffile()
- pool, storage_system = self._find_pool(snappool)
-
- LOG.debug('Device ID: %(deviceid)s: Storage System: '
- '%(storagesystem)s'
- % {'deviceid': device_id,
- 'storagesystem': storage_system})
-
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- LOG.error(_LE("Cannot find Replication Service to create snapshot "
- "for volume %s.") % volumename)
- exception_message = (_("Cannot find Replication Service to "
- "create snapshot for volume %s.")
- % volumename)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- LOG.debug("Create Snapshot: Method: CreateElementReplica: "
- "Target: %(snapshot)s Source: %(volume)s Replication "
- "Service: %(service)s ElementName: %(elementname)s Sync "
- "Type: 7 SourceElement: %(sourceelement)s."
- % {'snapshot': snapshotname,
- 'volume': volumename,
- 'service': repservice,
- 'elementname': snapshotname,
- 'sourceelement': vol_instance.path})
-
- rc, job =\
- self.conn.InvokeMethod('CreateElementReplica', repservice,
- ElementName=snapshotname,
- SyncType=self._getnum(7, '16'),
- TargetPool=pool,
- SourceElement=vol_instance.path)
-
- LOG.debug('Create Snapshot: Volume: %(volumename)s '
- 'Snapshot: %(snapshotname)s Return code: %(rc)lu'
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'rc': rc})
-
- if rc == 5L:
- # for DX S2
- # retry by CreateReplica
- snapshotname = snapshotname[:16]
- LOG.debug('retry Create Snapshot: '
- 'snapshotname:%(snapshotname)s,'
- 'source volume name:%(volumename)s,'
- 'vol_instance.path:%(vol_instance)s,'
- 'Invoke CreateReplica'
- % {'snapshotname': snapshotname,
- 'volumename': volumename,
- 'vol_instance': six.text_type(vol_instance.path)})
-
- configservice = self._find_storage_configuration_service(
- storage_system)
- if configservice is None:
- exception_message = (_("Create Snapshot: %(snapshotname)s. "
- "Storage Configuration Service "
- "not found")
- % {'snapshotname': snapshotname})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- # Invoke method for create snapshot
- rc, job = self.conn.InvokeMethod(
- 'CreateReplica',
- configservice,
- ElementName=snapshotname,
- TargetPool=pool,
- CopyType=self._getnum(4, '16'),
- SourceElement=vol_instance.path)
-
- if rc != 0L:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
- if rc != 0L:
- exception_message = (_('Error Create Snapshot: %(snapshot)s '
- 'Volume: %(volume)s '
- 'Error: %(errordesc)s')
- % {'snapshot': snapshotname,
- 'volume': volumename,
- 'errordesc': errordesc})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- # Find the newly created volume
- if "job" in job:
- associators = self.conn.Associators(
- job['Job'],
- resultClass=STOR_VOL)
- volpath = associators[0].path
- else: # for ETERNUS DX
- volpath = job['TargetElement']
-
- 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})
-
- return name
-
- def delete_snapshot(self, snapshot, volume):
- """Deletes a snapshot."""
- LOG.debug('Entering delete_snapshot.')
-
- snapshotname = snapshot['name']
- volumename = snapshot['volume_name']
- LOG.info(_LI('Delete Snapshot: %(snapshot)s: volume: %(volume)s')
- % {'snapshot': snapshotname,
- 'volume': volumename})
-
- self.conn = self._get_ecom_connection()
-
- LOG.debug('Delete Snapshot: %(snapshot)s: volume: %(volume)s. '
- 'Finding StorageSychronization_SV_SV.'
- % {'snapshot': snapshotname,
- 'volume': volumename})
-
- sync_name, storage_system =\
- self._find_storage_sync_sv_sv(snapshot, volume, False)
- if sync_name is None:
- LOG.error(_LE('Snapshot: %(snapshot)s: volume: %(volume)s '
- 'not found on the array. No snapshot to delete.')
- % {'snapshot': snapshotname,
- 'volume': volumename})
- return
-
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- exception_message = (_("Cannot find Replication Service to "
- "create snapshot for volume %s.")
- % volumename)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- # Delete snapshot - deletes both the target element
- # and the snap session
- LOG.debug("Delete Snapshot: Target: %(snapshot)s "
- "Source: %(volume)s. Method: "
- "ModifyReplicaSynchronization: "
- "Replication Service: %(service)s Operation: 19 "
- "Synchronization: %(sync_name)s."
- % {'snapshot': snapshotname,
- 'volume': volumename,
- 'service': repservice,
- 'sync_name': sync_name})
-
- rc, job =\
- self.conn.InvokeMethod('ModifyReplicaSynchronization',
- repservice,
- Operation=self._getnum(19, '16'),
- Synchronization=sync_name)
-
- LOG.debug('Delete Snapshot: Volume: %(volumename)s Snapshot: '
- '%(snapshotname)s Return code: %(rc)lu'
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'rc': rc})
-
- if rc != 0L:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- if rc != 0L:
- exception_message = (_('Error Delete Snapshot: Volume: '
- '%(volumename)s Snapshot: '
- '%(snapshotname)s. '
- 'Return code: %(rc)lu.'
- ' Error: %(error)s')
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- # It takes a while for the relationship between the snapshot
- # and the source volume gets cleaned up. Needs to wait until
- # it is cleaned up. Otherwise, the source volume can't be
- # deleted immediately after the snapshot deletion because it
- # still has snapshot.
- wait_timeout = int(self._get_timeout())
- wait_interval = 10
- start = int(time.time())
-
- def _wait_for_job():
- try:
- sync_name, storage_system =\
- self._find_storage_sync_sv_sv(snapshot, volume, False)
- if sync_name is None:
- LOG.info(_LI('Snapshot: %(snapshot)s: volume: %(volume)s. '
- 'Snapshot is deleted.')
- % {'snapshot': snapshotname,
- 'volume': volumename})
- raise loopingcall.LoopingCallDone()
- if int(time.time()) - start >= wait_timeout:
- LOG.warn(_LW('Snapshot: %(snapshot)s: volume: %(volume)s. '
- 'Snapshot deleted but cleanup timed out.')
- % {'snapshot': snapshotname,
- 'volume': volumename})
- raise loopingcall.LoopingCallDone()
- except Exception as ex:
- if ex.args[0] == 6:
- # 6 means object not found, so snapshot is deleted cleanly
- LOG.info(_LI('Snapshot: %(snapshot)s: volume: %(volume)s. '
- 'Snapshot is deleted.')
- % {'snapshot': snapshotname,
- 'volume': volumename})
- else:
- LOG.warn(_LW('Snapshot: %(snapshot)s: volume: %(volume)s. '
- 'Snapshot deleted but error during cleanup. '
- 'Error: %(error)s')
- % {'snapshot': snapshotname,
- 'volume': volumename,
- 'error': six.text_type(ex.args)})
- raise loopingcall.LoopingCallDone()
-
- timer = loopingcall.FixedIntervalLoopingCall(
- _wait_for_job)
- timer.start(interval=wait_interval)
-
- LOG.debug('Leaving delete_snapshot: Volume: %(volumename)s '
- 'Snapshot: %(snapshotname)s Return code: %(rc)lu.'
- % {'volumename': volumename,
- 'snapshotname': snapshotname,
- 'rc': rc})
-
- # Mapping method
- def _expose_paths(self, configservice, vol_instance,
- connector):
- """This method maps a volume to a host.
-
- It adds a volume and initiator to a Storage Group
- and therefore maps the volume to the host.
- """
- results = []
- volumename = vol_instance['ElementName']
- lun_name = vol_instance['Name']
- initiators = self._find_initiator_names(connector)
- storage_system = vol_instance['SystemName']
- lunmask_ctrls = self._find_lunmasking_scsi_protocol_controller(
- storage_system, connector)
- targets = self.get_target_portid(connector)
-
- if len(lunmask_ctrls) == 0:
- # create new lunmasking
- for target in targets:
- LOG.debug('ExposePaths: %(vol)s ConfigServicie: %(service)s '
- 'LUNames: %(lun_name)s '
- 'InitiatorPortIDs: %(initiator)s '
- 'TargetPortIDs: %(target)s DeviceAccesses: 2'
- % {'vol': vol_instance.path,
- 'service': configservice,
- 'lun_name': lun_name,
- 'initiator': initiators,
- 'target': target})
-
- rc, controller =\
- self.conn.InvokeMethod('ExposePaths',
- configservice, LUNames=[lun_name],
- InitiatorPortIDs=initiators,
- TargetPortIDs=[target],
- DeviceAccesses=[self._getnum(2, '16'
- )])
- results.append(rc)
- if rc != 0L:
- msg = (_('Error mapping volume %(volumename)s.rc:%(rc)lu')
- % {'volumename': volumename, 'rc': rc})
- LOG.warn(msg)
-
- else:
- # add lun to lunmasking
- for lunmask_ctrl in lunmask_ctrls:
- LOG.debug('ExposePaths parameter '
- 'LunMaskingSCSIProtocolController: '
- '%(lunmasking)s'
- % {'lunmasking': lunmask_ctrl})
- rc, controller =\
- self.conn.InvokeMethod('ExposePaths',
- configservice, LUNames=[lun_name],
- DeviceAccesses=[
- self._getnum(2, '16')],
- ProtocolControllers=[lunmask_ctrl])
- results.append(rc)
- if rc != 0L:
- msg = (_('Error mapping volume %(volumename)s.rc:%(rc)lu')
- % {'volumename': volumename, 'rc': rc})
- LOG.warn(msg)
-
- if 0L not in results:
- msg = (_('Error mapping volume %(volumename)s:%(results)s.')
- % {'volumename': volumename, 'results': results})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- LOG.debug('ExposePaths for volume %s completed successfully.'
- % volumename)
-
- # Unmapping method
- def _hide_paths(self, configservice, vol_instance,
- connector):
- """This method unmaps a volume from the host.
-
- Removes a volume from the Storage Group
- and therefore unmaps the volume from the host.
- """
- volumename = vol_instance['ElementName']
- lun_name = vol_instance['Name']
- lunmask_ctrls =\
- self._find_lunmasking_scsi_protocol_controller_for_vol(
- vol_instance, connector)
-
- for lunmask_ctrl in lunmask_ctrls:
- LOG.debug('HidePaths: %(vol)s ConfigServicie: %(service)s '
- 'LUNames: %(lun_name)s'
- ' LunMaskingSCSIProtocolController: '
- '%(lunmasking)s'
- % {'vol': vol_instance.path,
- 'service': configservice,
- 'lun_name': lun_name,
- 'lunmasking': lunmask_ctrl})
-
- rc, controller = self.conn.InvokeMethod(
- 'HidePaths', configservice,
- LUNames=[lun_name], ProtocolControllers=[lunmask_ctrl])
-
- if rc != 0L:
- msg = (_('Error unmapping volume %(volumename)s.rc:%(rc)lu')
- % {'volumename': volumename, 'rc': rc})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- LOG.debug('HidePaths for volume %s completed successfully.'
- % volumename)
-
- def _map_lun(self, volume, connector):
- """Maps a volume to the host."""
- volumename = self._create_volume_name(volume['id'])
- LOG.info(_LI('Map volume: %(volume)s')
- % {'volume': volumename})
-
- vol_instance = self._find_lun(volume)
- storage_system = vol_instance['SystemName']
-
- configservice = self._find_controller_configuration_service(
- storage_system)
- if configservice is None:
- exception_message = (_("Cannot find Controller Configuration "
- "Service for storage system %s")
- % storage_system)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- self._expose_paths(configservice, vol_instance, connector)
-
- def _unmap_lun(self, volume, connector):
- """Unmaps a volume from the host."""
- volumename = self._create_volume_name(volume['id'])
- LOG.info(_LI('Unmap volume: %(volume)s')
- % {'volume': volumename})
-
- device_info = self.find_device_number(volume, connector)
- device_number = device_info['hostlunid']
- if device_number is None:
- LOG.info(_LI("Volume %s is not mapped. No volume to unmap.")
- % (volumename))
- return
-
- vol_instance = self._find_lun(volume)
- storage_system = vol_instance['SystemName']
-
- configservice = self._find_controller_configuration_service(
- storage_system)
- if configservice is None:
- exception_message = (_("Cannot find Controller Configuration "
- "Service for storage system %s")
- % storage_system)
- raise exception.VolumeBackendAPIException(data=exception_message)
- self._hide_paths(configservice, vol_instance, connector)
-
- def initialize_connection(self, volume, connector):
- """Initializes the connection and returns connection info."""
- volumename = self._create_volume_name(volume['id'])
- LOG.info(_LI('Initialize connection: %(volume)s')
- % {'volume': volumename})
- self.conn = self._get_ecom_connection()
- device_info = self.find_device_number(volume, connector)
- device_number = device_info['hostlunid']
- if device_number is not None:
- LOG.info(_LI("Volume %s is already mapped.")
- % (volumename))
- else:
- self._map_lun(volume, connector)
- # Find host lun id again after the volume is exported to the host
- device_info = self.find_device_number(volume, connector)
-
- return device_info
-
- def terminate_connection(self, volume, connector):
- """Disallow connection from connector."""
- volumename = self._create_volume_name(volume['id'])
- LOG.info(_LI('Terminate connection: %(volume)s')
- % {'volume': volumename})
- self.conn = self._get_ecom_connection()
- self._unmap_lun(volume, connector)
-
- vol_instance = self._find_lun(volume)
- storage_system = vol_instance['SystemName']
- ctrl = self._find_lunmasking_scsi_protocol_controller(
- storage_system, connector)
- return ctrl
-
- def extend_volume(self, volume, new_size):
- """Extends an existing volume."""
- LOG.debug('Entering extend_volume.')
- volumesize = int(new_size) * units.Gi
- volumename = self._create_volume_name(volume['id'])
-
- LOG.info(_LI('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': 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:
- if "job" in job:
- rc, errordesc = self._wait_for_job_complete(self.conn, job)
- else:
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- exception_message = (_('Error Extend Volume: %(volumename)s. '
- 'Return code: %(rc)lu. '
- 'Error: %(error)s')
- % {'volumename': volumename,
- 'rc': rc,
- 'error': errordesc})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(
- data=exception_message)
-
- 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.stats['total_capacity_gb'] = 'unknown'
- self.stats['free_capacity_gb'] = 'unknown'
-
- return self.stats
-
- def _get_storage_type(self, volume, filename=None):
- """Get storage type.
-
- 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_conffile(self, filename=None):
- """Get the storage type from the config file."""
- if filename is None:
- filename = self.configuration.cinder_smis_config_file
-
- file = open(filename, 'r')
- data = file.read()
- file.close()
- dom = minidom.parseString(data)
- storageTypes = dom.getElementsByTagName('StorageType')
- if storageTypes is not None and len(storageTypes) > 0:
- storageType = storageTypes[0].toxml()
- storageType = storageType.replace('<StorageType>', '')
- storageType = storageType.replace('</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)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- def _get_snappool_conffile(self, filename=None):
- """Get the snap pool from the config file."""
- snappool = None
- if filename is None:
- filename = self.configuration.cinder_smis_config_file
-
- file = open(filename, 'r')
- data = file.read()
- file.close()
- dom = minidom.parseString(data)
- snappools = dom.getElementsByTagName('SnapPool')
- if snappools is not None and len(snappools) > 0:
- snappool = snappools[0].toxml()
- snappool = snappool.replace('<SnapPool>', '')
- snappool = snappool.replace('</SnapPool>', '')
- LOG.debug("Found Snap Pool in config file: [%s]"
- % (snappool))
- return snappool
- else:
- exception_message = (_("Snap pool not found."))
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- def _get_timeout(self, filename=None):
- if filename is None:
- filename = self.configuration.cinder_smis_config_file
-
- file = open(filename, 'r')
- data = file.read()
- file.close()
- dom = minidom.parseString(data)
- timeouts = dom.getElementsByTagName('Timeout')
- if timeouts is not None and len(timeouts) > 0:
- timeout = timeouts[0].toxml().replace('<Timeout>', '')
- timeout = timeout.replace('</Timeout>', '')
- LOG.debug("Found Timeout: %s" % (timeout))
- return timeout
- else:
- LOG.debug("Timeout not specified.")
- return 10
-
- def _get_ecom_cred(self, filename=None):
- if filename is None:
- filename = self.configuration.cinder_smis_config_file
-
- file = open(filename, 'r')
- data = file.read()
- file.close()
- dom = minidom.parseString(data)
- ecomUsers = dom.getElementsByTagName('EcomUserName')
- if ecomUsers is not None and len(ecomUsers) > 0:
- ecomUser = ecomUsers[0].toxml().replace('<EcomUserName>', '')
- ecomUser = ecomUser.replace('</EcomUserName>', '')
- ecomPasswds = dom.getElementsByTagName('EcomPassword')
- if ecomPasswds is not None and len(ecomPasswds) > 0:
- ecomPasswd = ecomPasswds[0].toxml().replace('<EcomPassword>', '')
- ecomPasswd = ecomPasswd.replace('</EcomPassword>', '')
- if ecomUser is not None and ecomPasswd is not None:
- return ecomUser, ecomPasswd
- else:
- LOG.debug("Ecom user not found.")
- return None
-
- def _get_ecom_server(self, filename=None):
- if filename is None:
- filename = self.configuration.cinder_smis_config_file
-
- file = open(filename, 'r')
- data = file.read()
- file.close()
- dom = minidom.parseString(data)
- ecomIps = dom.getElementsByTagName('EcomServerIp')
- if ecomIps is not None and len(ecomIps) > 0:
- ecomIp = ecomIps[0].toxml().replace('<EcomServerIp>', '')
- ecomIp = ecomIp.replace('</EcomServerIp>', '')
- ecomPorts = dom.getElementsByTagName('EcomServerPort')
- if ecomPorts is not None and len(ecomPorts) > 0:
- ecomPort = ecomPorts[0].toxml().replace('<EcomServerPort>', '')
- ecomPort = ecomPort.replace('</EcomServerPort>', '')
- if ecomIp is not None and ecomPort is not None:
- LOG.debug("Ecom IP: %(ecomIp)s Port: %(ecomPort)s",
- {'ecomIp': ecomIp, 'ecomPort': ecomPort})
- return ecomIp, ecomPort
- else:
- LOG.debug("Ecom server not found.")
- return None
-
- def _get_ecom_connection(self, filename=None):
- conn = pywbem.WBEMConnection(self.url, (self.user, self.passwd),
- default_namespace=SMIS_ROOT)
- if conn is None:
- exception_message = (_("Cannot connect to ECOM server"))
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- return conn
-
- def _find_replication_service(self, storage_system):
- foundRepService = None
- repservices = self.conn.EnumerateInstanceNames(
- REPL_SVC)
- for repservice in repservices:
- if storage_system == repservice['SystemName']:
- foundRepService = repservice
- LOG.debug("Found Replication Service: %s"
- % (repservice))
- break
-
- return foundRepService
-
- def _find_storage_configuration_service(self, storage_system):
- foundConfigService = None
- configservices = self.conn.EnumerateInstanceNames(
- STOR_CONF_SVC)
- for configservice in configservices:
- if storage_system == configservice['SystemName']:
- foundConfigService = configservice
- LOG.debug("Found Storage Configuration Service: %s"
- % (configservice))
- break
-
- return foundConfigService
-
- def _find_controller_configuration_service(self, storage_system):
- foundConfigService = None
- configservices = self.conn.EnumerateInstanceNames(
- CTRL_CONF_SVC)
- for configservice in configservices:
- if storage_system == configservice['SystemName']:
- foundConfigService = configservice
- LOG.debug("Found Controller Configuration Service: %s"
- % (configservice))
- break
-
- return foundConfigService
-
- def _find_storage_hardwareid_service(self, storage_system):
- foundConfigService = None
- configservices = self.conn.EnumerateInstanceNames(
- STOR_HWID_MNG_SVC)
- for configservice in configservices:
- if storage_system == configservice['SystemName']:
- foundConfigService = configservice
- LOG.debug("Found Storage Hardware ID Management Service: %s"
- % (configservice))
- break
-
- return foundConfigService
-
- # Find pool based on storage_type
- def _find_pool(self, storage_type, details=False):
- foundPool = None
- systemname = None
- poolinstanceid = None
- # Only get instance names if details flag is False;
- # Otherwise get the whole instances
-
- systemname, port = self._get_ecom_server()
- poolinstanceid = self._get_pool_instance_id(storage_type)
-
- if details is False:
- pools = self.conn.EnumerateInstanceNames(
- 'CIM_StoragePool')
- else:
- pools = self.conn.EnumerateInstances(
- 'CIM_StoragePool')
-
- for pool in pools:
- if six.text_type(pool['InstanceID']) == six.text_type(
- poolinstanceid):
- foundPool = pool
- break
-
- if foundPool is None:
- exception_message = (_("Pool %(storage_type)s is not found.")
- % {'storage_type': storage_type})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- if systemname is None:
- exception_message = (_("Storage system not found for pool "
- "%(storage_type)s.")
- % {'storage_type': storage_type})
- LOG.error(exception_message)
- raise exception.VolumeBackendAPIException(data=exception_message)
-
- LOG.debug("Pool: %(pool)s SystemName: %(systemname)s."
- % {'pool': foundPool,
- 'systemname': systemname})
- return foundPool, systemname
-
- def _find_lun(self, volume):
- foundinstance = None
-
- volumename = self._create_volume_name(volume['id'])
- loc = volume['provider_location']
- try:
- name = eval(loc)
- instancename = self._getinstancename(name['classname'],
- name['keybindings'])
- foundinstance = self.conn.GetInstance(instancename)
- except Exception:
- foundinstance = None
-
- if foundinstance is None:
- LOG.debug("Volume %(volumename)s not found on the array."
- "volume instance is None."
- % {'volumename': volumename})
- else:
- LOG.debug("Volume name: %(volumename)s Volume instance: "
- "%(vol_instance)s."
- % {'volumename': volumename,
- 'vol_instance': foundinstance.path})
-
- return foundinstance
-
- def _find_storage_sync_sv_sv(self, snapshot, volume,
- waitforsync=True):
- foundsyncname = None
- storage_system = None
-
- snapshotname = self._create_volume_name(snapshot['id'])
- volumename = self._create_volume_name(volume['id'])
- LOG.debug("Source: %(volumename)s Target: %(snapshotname)s."
- % {'volumename': volumename, 'snapshotname': snapshotname})
-
- snapshot_instance = self._find_lun(snapshot)
- volume_instance = self._find_lun(volume)
- if snapshot_instance is None or volume_instance is None:
- LOG.info(_LI('Snapshot Volume %(snapshotname)s, '
- 'Source Volume %(volumename)s not '
- 'found on the array.')
- % {'snapshotname': snapshotname,
- 'volumename': volumename})
- return None, None
-
- storage_system = volume_instance['SystemName']
- classname = STOR_SYNC
- 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. "
- "Storage Synchronized not found. "
- % {'volumename': volumename,
- 'snapshotname': snapshotname})
- else:
- LOG.debug("Storage system: %(storage_system)s "
- "Storage Synchronized instance: %(sync)s."
- % {'storage_system': storage_system,
- 'sync': foundsyncname})
- # Wait for SE_StorageSynchronized_SV_SV to be fully synced
- if waitforsync:
- self.wait_for_sync(self.conn, foundsyncname)
-
- return foundsyncname, storage_system
-
- def _find_initiator_names(self, connector):
- foundinitiatornames = []
- iscsi = 'iscsi'
- fc = 'fc'
- name = 'initiator name'
- if self.protocol.lower() == iscsi and connector['initiator']:
- foundinitiatornames.append(connector['initiator'])
- elif self.protocol.lower() == fc and connector['wwpns']:
- for wwn in connector['wwpns']:
- foundinitiatornames.append(wwn)
- name = 'world wide port names'
-
- if foundinitiatornames is None or len(foundinitiatornames) == 0:
- msg = (_('Error finding %s.') % name)
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- LOG.debug("Found %(name)s: %(initiator)s."
- % {'name': name,
- 'initiator': foundinitiatornames})
- return foundinitiatornames
-
- def _wait_for_job_complete(self, conn, job):
- """Given the job wait for it to complete.
-
- :param conn: connection the ecom server
- :param job: the job dict
- """
-
- def _wait_for_job_complete():
- """Called at an interval until the job is finished"""
- if self._is_job_finished(conn, job):
- raise loopingcall.LoopingCallDone()
- if self.retries > JOB_RETRIES:
- LOG.error(_LE("_wait_for_job_complete failed after %(retries)d"
- " tries") % {'retries': self.retries})
- raise loopingcall.LoopingCallDone()
- try:
- self.retries += 1
- if not self.wait_for_job_called:
- if self._is_job_finished(conn, job):
- self.wait_for_job_called = True
- except Exception as e:
- LOG.error(_LE("Exception: %s") % six.text_type(e))
- exceptionMessage = (_("Issue encountered waiting for job."))
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(exceptionMessage)
-
- self.retries = 0
- self.wait_for_job_called = False
- timer = loopingcall.FixedIntervalLoopingCall(_wait_for_job_complete)
- timer.start(interval=INTERVAL_10_SEC).wait()
-
- jobInstanceName = job['Job']
- jobinstance = conn.GetInstance(jobInstanceName,
- LocalOnly=False)
- rc = jobinstance['ErrorCode']
- errordesc = jobinstance['ErrorDescription']
-
- return rc, errordesc
-
- def _is_job_finished(self, conn, job):
- """Check if the job is finished.
- :param conn: connection the ecom server
- :param job: the job dict
-
- :returns: True if finished; False if not finished;
- """
- jobInstanceName = job['Job']
- jobinstance = conn.GetInstance(jobInstanceName,
- LocalOnly=False)
- jobstate = jobinstance['JobState']
- # From ValueMap of JobState in CIM_ConcreteJob
- # 2L=New, 3L=Starting, 4L=Running, 32767L=Queue Pending
- # ValueMap("2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13..32767,
- # 32768..65535"),
- # Values("New, Starting, Running, Suspended, Shutting Down,
- # Completed, Terminated, Killed, Exception, Service,
- # Query Pending, DMTF Reserved, Vendor Reserved")]
- # NOTE(deva): string matching based on
- # http://ipmitool.cvs.sourceforge.net/
- # viewvc/ipmitool/ipmitool/lib/ipmi_chassis.c
- if jobstate in [2L, 3L, 4L, 32767L]:
- return False
- else:
- return True
-
- def wait_for_sync(self, conn, syncName):
- """Given the sync name wait for it to fully synchronize.
- :param conn: connection the ecom server
- :param syncName: the syncName
- """
-
- def _wait_for_sync():
- """Called at an interval until the synchronization is finished"""
- if self._is_sync_complete(conn, syncName):
- raise loopingcall.LoopingCallDone()
- if self.retries > JOB_RETRIES:
- LOG.error(_LE("_wait_for_sync failed after %(retries)d tries")
- % {'retries': self.retries})
- raise loopingcall.LoopingCallDone()
- try:
- self.retries += 1
- if not self.wait_for_sync_called:
- if self._is_sync_complete(conn, syncName):
- self.wait_for_sync_called = True
- except Exception as e:
- LOG.error(_LE("Exception: %s") % six.text_type(e))
- exceptionMessage = (_("Issue encountered waiting for "
- "synchronization."))
- LOG.error(exceptionMessage)
- raise exception.VolumeBackendAPIException(exceptionMessage)
-
- self.retries = 0
- self.wait_for_sync_called = False
- timer = loopingcall.FixedIntervalLoopingCall(_wait_for_sync)
- timer.start(interval=INTERVAL_10_SEC).wait()
-
- def _is_sync_complete(self, conn, syncName):
- """Check if the job is finished.
- :param conn: connection the ecom server
- :param syncName: the sync name
-
- :returns: True if fully synchronized; False if not;
- """
- syncInstance = conn.GetInstance(syncName,
- LocalOnly=False)
- percentSynced = syncInstance['PercentSynced']
-
- if percentSynced < 100:
- return False
- else:
- return True
-
- # Find LunMaskingSCSIProtocolController for the local host on the
- # specified storage system
- def _find_lunmasking_scsi_protocol_controller(self, storage_system,
- connector):
- foundCtrls = []
- initiators = self._find_initiator_names(connector)
- controllers = self.conn.EnumerateInstanceNames(
- SCSI_PROT_CTR)
- for ctrl in controllers:
- if storage_system != ctrl['SystemName']:
- continue
- associators =\
- self.conn.Associators(ctrl,
- ResultClass=AUTH_PRIV)
- for assoc in associators:
- for initiator in initiators:
- if initiator.lower() not in assoc['InstanceID'].lower():
- continue
-
- LOG.debug('_find_lunmasking_scsi_protocol_controller,'
- 'AffinityGroup:%(ag)s'
- % {'ag': ctrl})
- foundCtrls.append(ctrl)
- break
- break
-
- LOG.debug("LunMaskingSCSIProtocolController for storage system "
- "%(storage_system)s and initiator %(initiator)s is "
- "%(ctrl)s."
- % {'storage_system': storage_system,
- 'initiator': initiators,
- 'ctrl': foundCtrls})
- return foundCtrls
-
- # Find LunMaskingSCSIProtocolController for the local host and the
- # specified storage volume
- def _find_lunmasking_scsi_protocol_controller_for_vol(self, vol_instance,
- connector):
- foundCtrls = []
- initiators = self._find_initiator_names(connector)
- controllers =\
- self.conn.AssociatorNames(
- vol_instance.path,
- ResultClass=SCSI_PROT_CTR)
- LOG.debug('_find_lunmasking_scsi_protocol_controller_for_vol:'
- 'controllers:%(controllers)s'
- % {'controllers': controllers})
- for ctrl in controllers:
- associators =\
- self.conn.Associators(
- ctrl,
- ResultClass=AUTH_PRIV)
- foundCtrl = None
- for assoc in associators:
- for initiator in initiators:
- if initiator.lower() not in assoc['InstanceID'].lower():
- continue
-
- LOG.debug('_find_lunmasking_scsi_protocol_controller'
- '_for_vol,'
- 'AffinityGroup:%(ag)s'
- % {'ag': ctrl})
- foundCtrl = ctrl
- foundCtrls.append(foundCtrl)
- break
- if foundCtrl is not None:
- break
-
- LOG.debug("LunMaskingSCSIProtocolController for storage volume "
- "%(vol)s and initiator %(initiator)s is %(ctrl)s."
- % {'vol': vol_instance.path,
- 'initiator': initiators,
- 'ctrl': foundCtrls})
- return foundCtrls
-
- # Find out how many volumes are mapped to a host
- # assoociated to the LunMaskingSCSIProtocolController
- def get_num_volumes_mapped(self, volume, connector):
- numVolumesMapped = 0
- volumename = volume['name']
- vol_instance = self._find_lun(volume)
- if vol_instance is None:
- msg = (_('Volume %(name)s not found on the array. '
- 'Cannot determine if there are volumes mapped.')
- % {'name': volumename})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- storage_system = vol_instance['SystemName']
-
- ctrl = self._find_lunmasking_scsi_protocol_controller(
- storage_system,
- connector)
-
- LOG.debug("LunMaskingSCSIProtocolController for storage system "
- "%(storage)s and %(connector)s is %(ctrl)s."
- % {'storage': storage_system,
- 'connector': connector,
- 'ctrl': ctrl})
-
- associators = self.conn.Associators(
- ctrl,
- resultClass=STOR_VOL)
-
- numVolumesMapped = len(associators)
-
- LOG.debug("Found %(numVolumesMapped)d volumes on storage system "
- "%(storage)s mapped to %(connector)s."
- % {'numVolumesMapped': numVolumesMapped,
- 'storage': storage_system,
- 'connector': connector})
- return numVolumesMapped
-
- # Find a device number that a host can see for a volume
- def find_device_number(self, volume, connector):
- out_num_device_number = None
-
- volumename = self._create_volume_name(volume['id'])
- vol_instance = self._find_lun(volume)
- storage_system = vol_instance['SystemName']
- sp = None
-
- ctrls = self._find_lunmasking_scsi_protocol_controller_for_vol(
- vol_instance,
- connector)
-
- LOG.debug("LunMaskingSCSIProtocolController for "
- "volume %(vol)s and connector %(connector)s "
- "is %(ctrl)s."
- % {'vol': vol_instance.path,
- 'connector': connector,
- 'ctrl': ctrls})
-
- if len(ctrls) != 0:
- unitnames = self.conn.ReferenceNames(
- vol_instance.path,
- ResultClass='CIM_ProtocolControllerForUnit')
-
- for unitname in unitnames:
- controller = unitname['Antecedent']
- classname = controller['CreationClassName']
- index = classname.find(SCSI_PROT_CTR)
- if index > -1:
- if ctrls[0]['DeviceID'] != controller['DeviceID']:
- continue
- # Get an instance of CIM_ProtocolControllerForUnit
- unitinstance = self.conn.GetInstance(unitname,
- LocalOnly=False)
- numDeviceNumber = int(unitinstance['DeviceNumber'], 16)
- out_num_device_number = numDeviceNumber
- break
-
- if out_num_device_number is None:
- LOG.info(_LI("Device number not found for volume "
- "%(volumename)s %(vol_instance)s.")
- % {'volumename': volumename,
- 'vol_instance': vol_instance.path})
- else:
- LOG.debug("Found device number %(device)d for volume "
- "%(volumename)s %(vol_instance)s." %
- {'device': out_num_device_number,
- 'volumename': volumename,
- 'vol_instance': vol_instance.path})
-
- data = {'hostlunid': out_num_device_number,
- 'storagesystem': storage_system,
- 'owningsp': sp}
-
- LOG.debug("Device info: %(data)s." % {'data': data})
-
- return data
-
- def _getnum(self, num, datatype):
- try:
- result = {
- '8': pywbem.Uint8(num),
- '16': pywbem.Uint16(num),
- '32': pywbem.Uint32(num),
- '64': pywbem.Uint64(num)
- }
- result = result.get(datatype, num)
- except NameError:
- result = num
-
- return result
-
- def _getinstancename(self, classname, bindings):
- instancename = None
- try:
- instancename = pywbem.CIMInstanceName(
- classname,
- namespace=SMIS_ROOT,
- keybindings=bindings)
- except NameError:
- instancename = None
-
- return instancename
-
- # Find Storage Hardware IDs
- def _find_storage_hardwareids(self, connector):
- foundInstances = []
- wwpns = self._find_initiator_names(connector)
- hardwareids = self.conn.EnumerateInstances(
- STOR_HWID)
- for hardwareid in hardwareids:
- storid = hardwareid['StorageID']
- for wwpn in wwpns:
- if wwpn.lower() == storid.lower():
- foundInstances.append(hardwareid.path)
-
- LOG.debug("Storage Hardware IDs for %(wwpns)s is "
- "%(foundInstances)s."
- % {'wwpns': wwpns,
- 'foundInstances': 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
-
- def _create_volume_name(self, id_code):
- """create volume_name on ETERNUS from id on OpenStack."""
-
- LOG.debug('_create_volume_name [%s],Enter method.'
- % id_code)
-
- if id_code is None:
- msg = (_('_create_volume_name,'
- 'id_code is None.'))
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- # pylint: disable=E1101
- m = hashlib.md5()
- m.update(id_code)
- # pylint: disable=E1121
- volname = base64.urlsafe_b64encode((m.digest()))
- ret = VOL_PREFIX + six.text_type(volname)
-
- LOG.debug('_create_volume_name: '
- ' id:%(id)s'
- ' volumename:%(ret)s'
- ' Exit method.'
- % {'id': id_code, 'ret': ret})
-
- return ret
-
- def _get_pool_instance_id(self, poolname):
- """get pool instacne_id from pool name"""
- LOG.debug('_get_pool_instance_id,'
- 'Enter method,poolname:%s'
- % (poolname))
-
- poolinstanceid = None
- pool = None
- pools = []
- msg = None
-
- try:
- pools = self.conn.EnumerateInstances(
- 'CIM_StoragePool')
- except Exception:
- msg = (_('_get_pool_instance_id,'
- 'poolname:%(poolname)s,'
- 'EnumerateInstances,'
- 'cannot connect to ETERNUS.')
- % {'poolname': poolname})
-
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- for pool in pools:
- pool_elementname = pool['ElementName']
- poolclass = pool.path.classname
- LOG.debug('poolname from file or VolumeType:%s'
- ' poolname from smis:%s'
- ' poolclass from smis:%s'
- % (poolname, pool_elementname, poolclass))
-
- if six.text_type(poolname) == six.text_type(pool_elementname):
- if poolclass in STOR_POOLS:
- poolinstanceid = pool['InstanceID']
- break
-
- if poolinstanceid is None:
- msg = (_('_get_pool_instance_id,'
- 'poolname:%(poolname)s,'
- 'poolinstanceid is None.')
- % {'poolname': poolname})
- LOG.info(msg)
-
- LOG.debug('_get_pool_instance_id,'
- 'Exit method,poolinstanceid:%s'
- % (poolinstanceid))
-
- return poolinstanceid
-
- def get_target_portid(self, connector):
- """return target_portid"""
-
- LOG.debug('get_target_portid,Enter method')
-
- target_portidlist = []
- tgtportlist = []
- tgtport = None
- conn_type = {'fc': 2, 'iscsi': 7}
-
- try:
- tgtportlist = self.conn.EnumerateInstances(
- 'CIM_SCSIProtocolEndpoint')
- except Exception:
- msg = (_('get_target_portid,'
- 'connector:%(connector)s,'
- 'EnumerateInstances,'
- 'cannot connect to ETERNUS.')
- % {'connector': connector})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- for tgtport in tgtportlist:
- if tgtport['ConnectionType'] == conn_type[self.protocol.lower()]:
- target_portidlist.append(tgtport['Name'])
-
- LOG.debug('get_target_portid,'
- 'portid:%(portid)s,'
- 'connection type:%(cont)s,'
- % {'portid': tgtport['Name'],
- 'cont': tgtport['ConnectionType']})
-
- LOG.debug('get_target_portid,'
- 'target portid: %(target_portid)s '
- % {'target_portid': target_portidlist})
-
- if len(target_portidlist) == 0:
- msg = (_('get_target_portid,'
- 'protcol:%(protocol)s,'
- 'connector:%(connector)s,'
- 'target_portid does not found.')
- % {'protocol': self.protocol,
- 'connector': connector})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- LOG.debug('get_target_portid,Exit method')
-
- return target_portidlist
-
- def _find_copysession(self, volume):
- """find copysession from volumename on ETERNUS"""
- LOG.debug('_find_copysession, Enter method')
-
- cpsession = None
- vol_instance = None
- repservice = None
- rc = 0
- replicarellist = None
- replicarel = None
- snapshot_vol_instance = None
- msg = None
- errordesc = None
-
- vol_instance = self._find_lun(volume)
- if vol_instance is None:
- return None, None
-
- volumename = vol_instance['ElementName']
- storage_system = vol_instance['SystemName']
- if vol_instance is not None:
- # find target_volume
-
- # get copysession list
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- msg = (_('_find_copysession,'
- 'Cannot find Replication Service to '
- 'find copysession'))
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- def _wait_for_job(repservice):
- cpsession_instance = None
- LOG.debug('_find_copysession,source_volume'
- ' while copysession')
- cpsession = None
-
- rc, replicarellist = self.conn.InvokeMethod(
- 'GetReplicationRelationships',
- repservice,
- Type=self._getnum(2, '16'),
- Mode=self._getnum(2, '16'),
- Locality=self._getnum(2, '16'))
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- msg = (_('_find_copysession,'
- 'source_volumename:%(volumename)s,'
- 'Return code:%(rc)lu,'
- 'Error:%(errordesc)s')
- % {'volumename': volumename,
- 'rc': rc,
- 'errordesc': errordesc})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- for replicarel in replicarellist['Synchronizations']:
- LOG.debug('_find_copysession,'
- 'source_volume,'
- 'replicarel:%(replicarel)s'
- % {'replicarel': replicarel})
- try:
- snapshot_vol_instance = self.conn.GetInstance(
- replicarel['SystemElement'],
- LocalOnly=False)
- except Exception:
- msg = (_('_find_copysession,'
- 'source_volumename:%(volumename)s,'
- 'GetInstance,'
- 'cannot connect to ETERNUS.')
- % {'volumename': volumename})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- LOG.debug('_find_copysession,'
- 'snapshot ElementName:%(elementname)s,'
- 'source_volumename:%(volumename)s'
- % {'elementname':
- snapshot_vol_instance['ElementName'],
- 'volumename': volumename})
-
- if volumename == snapshot_vol_instance['ElementName']:
- # find copysession
- cpsession = replicarel
- LOG.debug('_find_copysession,'
- 'volumename:%(volumename)s,'
- 'Storage Synchronized instance:%(sync)s'
- % {'volumename': volumename,
- 'sync': six.text_type(cpsession)})
- msg = (_('_find_copy_session,'
- 'source_volumename:%(volumename)s,'
- 'wait for end of copysession')
- % {'volumename': volumename})
- LOG.info(msg)
-
- try:
- cpsession_instance = self.conn.GetInstance(
- replicarel)
- except Exception:
- break
-
- LOG.debug('_find_copysession,'
- 'status:%(status)s'
- % {'status':
- cpsession_instance['CopyState']})
- if cpsession_instance['CopyState'] == BROKEN:
- msg = (_('_find_copysession,'
- 'source_volumename:%(volumename)s,'
- 'copysession state is BROKEN')
- % {'volumename': volumename})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
- break
- else:
- LOG.debug('_find_copysession,'
- 'volumename:%(volumename)s,'
- 'Storage Synchronized not found.'
- % {'volumename': volumename})
-
- if cpsession is None:
- raise loopingcall.LoopingCallDone()
-
- timer = loopingcall.FixedIntervalLoopingCall(
- _wait_for_job, repservice)
- timer.start(interval=10).wait()
-
- rc, replicarellist = self.conn.InvokeMethod(
- 'GetReplicationRelationships',
- repservice,
- Type=self._getnum(2, '16'),
- Mode=self._getnum(2, '16'),
- Locality=self._getnum(2, '16'))
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- if rc != 0L:
- msg = (_('_find_copysession,'
- 'source_volumename:%(volumename)s,'
- 'Return code:%(rc)lu,'
- 'Error:%(errordesc)s')
- % {'volumename': volumename,
- 'rc': rc,
- 'errordesc': errordesc})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- # find copysession for target_volume
- for replicarel in replicarellist['Synchronizations']:
- LOG.debug('_find_copysession,'
- 'replicarel:%(replicarel)s'
- % {'replicarel': replicarel})
-
- # target volume
- try:
- snapshot_vol_instance = self.conn.GetInstance(
- replicarel['SyncedElement'],
- LocalOnly=False)
- except Exception:
- msg = (_('_find_copysession,'
- 'target_volumename:%(volumename)s,'
- 'GetInstance,'
- 'cannot connect to ETERNUS.')
- % {'volumename': volumename})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
- LOG.debug('_find_copysession,'
- 'snapshot ElementName:%(elementname)s,'
- 'volumename:%(volumename)s'
- % {'elementname':
- snapshot_vol_instance['ElementName'],
- 'volumename': volumename})
-
- if volumename == snapshot_vol_instance['ElementName']:
- # find copysession
- cpsession = replicarel
- LOG.debug('_find_copysession,'
- 'volumename:%(volumename)s,'
- 'Storage Synchronized instance:%(sync)s'
- % {'volumename': volumename,
- 'sync': six.text_type(cpsession)})
- break
-
- else:
- LOG.debug('_find_copysession,'
- 'volumename:%(volumename)s,'
- 'Storage Synchronized not found.'
- % {'volumename': volumename})
-
- else:
- # does not find target_volume of copysession
- msg = (_('_find_copysession,'
- 'volumename:%(volumename)s,'
- 'not found.')
- % {'volumename': volumename})
- LOG.info(msg)
-
- LOG.debug('_find_copysession,Exit method')
-
- return cpsession, storage_system
-
- def _delete_copysession(self, storage_system, cpsession):
- """delete copysession"""
- LOG.debug('_delete_copysession,Entering')
- LOG.debug('_delete_copysession,[%s]' % cpsession)
-
- snapshot_instance = None
- msg = None
- errordesc = None
-
- try:
- snapshot_instance = self.conn.GetInstance(
- cpsession,
- LocalOnly=False)
- except Exception:
- msg = (_('_delete_copysession, '
- 'copysession:%(cpsession)s,'
- 'GetInstance,'
- 'cannot connect to ETERNUS.')
- % {'cpsession': cpsession})
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- copytype = snapshot_instance['CopyType']
-
- # set oparation code
- operation = OPERATION_dic[copytype]
-
- repservice = self._find_replication_service(storage_system)
- if repservice is None:
- msg = (_('_delete_copysession,'
- 'Cannot find Replication Service to '
- 'delete copysession'))
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- # Invoke method for delete copysession
- rc, job = self.conn.InvokeMethod(
- 'ModifyReplicaSynchronization',
- repservice,
- Operation=self._getnum(operation, '16'),
- Synchronization=cpsession,
- Force=True,
- WaitForCopyState=self._getnum(15, '16'))
-
- errordesc = RETCODE_dic[six.text_type(rc)]
-
- LOG.debug('_delete_copysession,'
- 'copysession:%(cpsession)s,'
- 'operation:%(operation)s,'
- 'Return code:%(rc)lu,'
- 'Error:%(errordesc)s,'
- 'Exit method'
- % {'cpsession': cpsession,
- 'operation': operation,
- 'rc': rc,
- 'errordesc': errordesc})
-
- if rc != 0L:
- msg = (_('_delete_copysession,'
- 'copysession:%(cpsession)s,'
- 'operation:%(operation)s,'
- 'Return code:%(rc)lu,'
- 'Error:%(errordesc)s')
- % {'cpsession': cpsession,
- 'operation': operation,
- 'rc': rc,
- 'errordesc': errordesc})
-
- LOG.error(msg)
- raise exception.VolumeBackendAPIException(data=msg)
-
- return