Removing Fujitsu driver for no reported CI
CI deadlines were set and pushed since last year. An email about this requirement and the deadline of March 19th 2015 has been sent to each individual driver maintainer, as well as the mailing list [1]. This driver is being removed because the maintainer has chosen not to respond to the CI deadline email and report a CI to ensure their driver integration is successful. Therfore, we can not validate the driver is working in Cinder today in a continuous way. DocImpact [1] - http://lists.openstack.org/pipermail/openstack-dev/2015-January/054614.html Change-Id: Ibe9a3cc9831a1ef4aa7cbdb15e09bced353c738a
This commit is contained in:
parent
552878d554
commit
8466c5a0c9
@ -1,812 +0,0 @@
|
||||
# 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')
|
@ -1,69 +0,0 @@
|
||||
# Copyright (c) 2015 FUJITSU LIMITED
|
||||
#
|
||||
# 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.
|
||||
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
|
||||
from cinder import test
|
||||
import cinder.volume.drivers.fujitsu.eternus_dx_common as eternus_dx_common
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
FUJITSU_FC_MODULE = ('cinder.volume.drivers.fujitsu.'
|
||||
'eternus_dx_fc.FJDXFCDriver')
|
||||
|
||||
FUJITSU_ISCSI_MODULE = ('cinder.volume.drivers.fujitsu.'
|
||||
'eternus_dx_iscsi.FJDXISCSIDriver')
|
||||
|
||||
|
||||
class FJDriverCompatibility(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(FJDriverCompatibility, self).setUp()
|
||||
self.manager = importutils.import_object(CONF.volume_manager)
|
||||
|
||||
# Stub definition
|
||||
self.stubs.Set(
|
||||
eternus_dx_common.FJDXCommon, '__init__', self.fake_init)
|
||||
|
||||
def _load_driver(self, driver):
|
||||
self.manager.__init__(volume_driver=driver)
|
||||
|
||||
def _driver_module_name(self):
|
||||
return "%s.%s" % (self.manager.driver.__class__.__module__,
|
||||
self.manager.driver.__class__.__name__)
|
||||
|
||||
def fake_init(self, prtcl, configuration=None):
|
||||
msg = "selected protocol is %s" % prtcl
|
||||
self.assertTrue((prtcl == 'FC') or (prtcl == 'iSCSI'), msg=msg)
|
||||
|
||||
def test_fujitsu_driver_fc_old(self):
|
||||
self._load_driver(
|
||||
'cinder.volume.drivers.fujitsu_eternus_dx_fc.FJDXFCDriver')
|
||||
self.assertEqual(FUJITSU_FC_MODULE, self._driver_module_name())
|
||||
|
||||
def test_fujitsu_driver_fc_new(self):
|
||||
self._load_driver(FUJITSU_FC_MODULE)
|
||||
self.assertEqual(FUJITSU_FC_MODULE, self._driver_module_name())
|
||||
|
||||
def test_fujitsu_driver_iscsi_old(self):
|
||||
self._load_driver(
|
||||
'cinder.volume.drivers.fujitsu_eternus_dx_iscsi.FJDXISCSIDriver')
|
||||
self.assertEqual(FUJITSU_ISCSI_MODULE, self._driver_module_name())
|
||||
|
||||
def test_fujitsu_driver_iscsi_new(self):
|
||||
self._load_driver(FUJITSU_ISCSI_MODULE)
|
||||
self.assertEqual(FUJITSU_ISCSI_MODULE, self._driver_module_name())
|
File diff suppressed because it is too large
Load Diff
@ -1,234 +0,0 @@
|
||||
# Copyright (c) 2014 FUJITSU LIMITED
|
||||
# Copyright (c) 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.
|
||||
"""
|
||||
FC Drivers for ETERNUS DX arrays based on SMI-S.
|
||||
|
||||
"""
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder.volume import driver
|
||||
from cinder.volume.drivers.fujitsu import eternus_dx_common
|
||||
from cinder.zonemanager import utils as fczm_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FJDXFCDriver(driver.FibreChannelDriver):
|
||||
"""FC Drivers using SMI-S."""
|
||||
|
||||
VERSION = "1.2.0"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super(FJDXFCDriver, self).__init__(*args, **kwargs)
|
||||
self.common = eternus_dx_common.FJDXCommon(
|
||||
'FC',
|
||||
configuration=self.configuration)
|
||||
|
||||
def check_for_setup_error(self):
|
||||
pass
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_volume(self, volume):
|
||||
"""Creates a volume."""
|
||||
volpath = self.common.create_volume(volume)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_volume_from_snapshot(self, volume, snapshot):
|
||||
"""Creates a volume from a snapshot."""
|
||||
volpath = self.common.create_volume_from_snapshot(volume, snapshot)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_cloned_volume(self, volume, src_vref):
|
||||
"""Creates a cloned volume."""
|
||||
volpath = self.common.create_cloned_volume(volume, src_vref)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def delete_volume(self, volume):
|
||||
"""Deletes a volume."""
|
||||
self.common.delete_volume(volume)
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_snapshot(self, snapshot):
|
||||
"""Creates a snapshot."""
|
||||
|
||||
ctxt = context.get_admin_context()
|
||||
volumename = snapshot['volume_name']
|
||||
index = volumename.index('-')
|
||||
volumeid = volumename[index + 1:]
|
||||
volume = self.db.volume_get(ctxt, volumeid)
|
||||
|
||||
volpath = self.common.create_snapshot(snapshot, volume)
|
||||
|
||||
model_update = {}
|
||||
snapshot['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = snapshot['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def delete_snapshot(self, snapshot):
|
||||
"""Deletes a snapshot."""
|
||||
|
||||
self.common.delete_volume(snapshot)
|
||||
|
||||
def ensure_export(self, context, volume):
|
||||
"""Driver entry point to get the export info for an existing volume."""
|
||||
pass
|
||||
|
||||
def create_export(self, context, volume):
|
||||
"""Driver entry point to get the export info for a new volume."""
|
||||
pass
|
||||
|
||||
def remove_export(self, context, volume):
|
||||
"""Driver entry point to remove an export for a volume."""
|
||||
pass
|
||||
|
||||
def check_for_export(self, context, volume_id):
|
||||
"""Make sure volume is exported."""
|
||||
pass
|
||||
|
||||
@fczm_utils.AddFCZone
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Initializes the connection and returns connection info.
|
||||
|
||||
Assign any created volume to a compute node/host so that it can be
|
||||
used from that host.
|
||||
|
||||
The driver returns a driver_volume_type of 'fibre_channel'.
|
||||
The target_wwn can be a single entry or a list of wwns that
|
||||
correspond to the list of remote wwn(s) that will export the volume.
|
||||
Example return values:
|
||||
|
||||
{
|
||||
'driver_volume_type': 'fibre_channel'
|
||||
'data': {
|
||||
'target_discovered': True,
|
||||
'target_lun': 1,
|
||||
'target_wwn': '1234567890123',
|
||||
}
|
||||
}
|
||||
|
||||
or
|
||||
|
||||
{
|
||||
'driver_volume_type': 'fibre_channel'
|
||||
'data': {
|
||||
'target_discovered': True,
|
||||
'target_lun': 1,
|
||||
'target_wwn': ['1234567890123', '0987654321321'],
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
device_info = self.common.initialize_connection(volume,
|
||||
connector)
|
||||
device_number = device_info['hostlunid']
|
||||
storage_system = device_info['storagesystem']
|
||||
target_wwns, init_targ_map = self._build_initiator_target_map(
|
||||
storage_system, connector)
|
||||
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {'target_lun': device_number,
|
||||
'target_discovered': True,
|
||||
'target_wwn': target_wwns,
|
||||
'initiator_target_map': init_targ_map}}
|
||||
|
||||
LOG.debug('Return FC data: %(data)s.'
|
||||
% {'data': data})
|
||||
|
||||
return data
|
||||
|
||||
@fczm_utils.RemoveFCZone
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Disallow connection from connector."""
|
||||
ctrl = self.common.terminate_connection(volume, connector)
|
||||
|
||||
loc = volume['provider_location']
|
||||
name = eval(loc)
|
||||
storage_system = name['keybindings']['SystemName']
|
||||
target_wwns, init_targ_map = self._build_initiator_target_map(
|
||||
storage_system, connector)
|
||||
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
|
||||
if len(ctrl) == 0:
|
||||
# No more volumes attached to the host
|
||||
data['data'] = {'target_wwn': target_wwns,
|
||||
'initiator_target_map': init_targ_map}
|
||||
|
||||
LOG.debug('Return FC data: %(data)s.'
|
||||
% {'data': data})
|
||||
|
||||
return data
|
||||
|
||||
def _build_initiator_target_map(self, storage_system, connector):
|
||||
"""Build the target_wwns and the initiator target map."""
|
||||
|
||||
target_wwns = self.common.get_target_portid(connector)
|
||||
|
||||
initiator_wwns = connector['wwpns']
|
||||
|
||||
init_targ_map = {}
|
||||
for initiator in initiator_wwns:
|
||||
init_targ_map[initiator] = target_wwns
|
||||
|
||||
return target_wwns, init_targ_map
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend an existing volume."""
|
||||
self.common.extend_volume(volume, new_size)
|
||||
|
||||
def get_volume_stats(self, refresh=False):
|
||||
"""Get volume stats.
|
||||
|
||||
If 'refresh' is True, run update the stats first.
|
||||
"""
|
||||
if refresh:
|
||||
self.update_volume_stats()
|
||||
|
||||
return self._stats
|
||||
|
||||
def update_volume_stats(self):
|
||||
"""Retrieve stats info from volume group."""
|
||||
LOG.debug("Updating volume stats")
|
||||
data = self.common.update_volume_stats()
|
||||
backend_name = self.configuration.safe_get('volume_backend_name')
|
||||
data['volume_backend_name'] = backend_name or 'FJDXFCDriver'
|
||||
data['storage_protocol'] = 'FC'
|
||||
data['driver_version'] = self.VERSION
|
||||
self._stats = data
|
@ -1,255 +0,0 @@
|
||||
# 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.
|
||||
"""
|
||||
ISCSI Drivers for ETERNUS DX arrays based on SMI-S.
|
||||
|
||||
"""
|
||||
from oslo_concurrency import lockutils
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from cinder import context
|
||||
from cinder import exception
|
||||
from cinder.i18n import _, _LW
|
||||
from cinder.volume import driver
|
||||
from cinder.volume.drivers.fujitsu import eternus_dx_common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FJDXISCSIDriver(driver.ISCSIDriver):
|
||||
"""ISCSI Drivers using SMI-S."""
|
||||
|
||||
VERSION = "1.2.0"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
super(FJDXISCSIDriver, self).__init__(*args, **kwargs)
|
||||
self.common = \
|
||||
eternus_dx_common.\
|
||||
FJDXCommon('iSCSI', configuration=self.configuration)
|
||||
|
||||
def check_for_setup_error(self):
|
||||
pass
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_volume(self, volume):
|
||||
"""Creates a volume."""
|
||||
volpath = self.common.create_volume(volume)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_volume_from_snapshot(self, volume, snapshot):
|
||||
"""Creates a volume from a snapshot."""
|
||||
volpath = self.common.create_volume_from_snapshot(volume, snapshot)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_cloned_volume(self, volume, src_vref):
|
||||
"""Creates a cloned volume."""
|
||||
volpath = self.common.create_cloned_volume(volume, src_vref)
|
||||
|
||||
model_update = {}
|
||||
volume['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = volume['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def delete_volume(self, volume):
|
||||
"""Deletes a volume."""
|
||||
self.common.delete_volume(volume)
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def create_snapshot(self, snapshot):
|
||||
"""Creates a snapshot."""
|
||||
ctxt = context.get_admin_context()
|
||||
volumename = snapshot['volume_name']
|
||||
index = volumename.index('-')
|
||||
volumeid = volumename[index + 1:]
|
||||
volume = self.db.volume_get(ctxt, volumeid)
|
||||
|
||||
volpath = self.common.create_snapshot(snapshot, volume)
|
||||
|
||||
model_update = {}
|
||||
snapshot['provider_location'] = six.text_type(volpath)
|
||||
model_update['provider_location'] = snapshot['provider_location']
|
||||
return model_update
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def delete_snapshot(self, snapshot):
|
||||
"""Deletes a snapshot."""
|
||||
|
||||
self.common.delete_volume(snapshot)
|
||||
|
||||
def ensure_export(self, context, volume):
|
||||
"""Driver entry point to get the export info for an existing volume."""
|
||||
pass
|
||||
|
||||
def create_export(self, context, volume):
|
||||
"""Driver entry point to get the export info for a new volume."""
|
||||
pass
|
||||
|
||||
def remove_export(self, context, volume):
|
||||
"""Driver entry point to remove an export for a volume."""
|
||||
pass
|
||||
|
||||
def check_for_export(self, context, volume_id):
|
||||
"""Make sure volume is exported."""
|
||||
pass
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Initializes the connection and returns connection info.
|
||||
|
||||
The iscsi driver returns a driver_volume_type of 'iscsi'.
|
||||
the format of the driver data is defined in smis_get_iscsi_properties.
|
||||
Example return value::
|
||||
|
||||
{
|
||||
'driver_volume_type': 'iscsi'
|
||||
'data': {
|
||||
'target_discovered': True,
|
||||
'target_iqn': 'iqn.2010-10.org.openstack:volume-00000001',
|
||||
'target_portal': '127.0.0.0.1:3260',
|
||||
'volume_id': '12345678-1234-4321-1234-123456789012',
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
self.common.initialize_connection(volume, connector)
|
||||
|
||||
iscsi_properties = self.smis_get_iscsi_properties(volume, connector)
|
||||
return {
|
||||
'driver_volume_type': 'iscsi',
|
||||
'data': iscsi_properties
|
||||
}
|
||||
|
||||
def _do_iscsi_discovery(self, volume):
|
||||
|
||||
LOG.warn(_LW("ISCSI provider_location not stored, using discovery"))
|
||||
|
||||
(out, _err) = self._execute('iscsiadm', '-m', 'discovery',
|
||||
'-t', 'sendtargets', '-p',
|
||||
self.configuration.iscsi_ip_address,
|
||||
run_as_root=True)
|
||||
targets = []
|
||||
for target in out.splitlines():
|
||||
targets.append(target)
|
||||
|
||||
return targets
|
||||
|
||||
def smis_get_iscsi_properties(self, volume, connector):
|
||||
"""Gets iscsi configuration.
|
||||
|
||||
We ideally get saved information in the volume entity, but fall back
|
||||
to discovery if need be. Discovery may be completely removed in future
|
||||
The properties are:
|
||||
|
||||
:target_discovered: boolean indicating whether discovery was used
|
||||
|
||||
:target_iqn: the IQN of the iSCSI target
|
||||
|
||||
:target_portal: the portal of the iSCSI target
|
||||
|
||||
:target_lun: the lun of the iSCSI target
|
||||
|
||||
:volume_id: the UUID of the volume
|
||||
|
||||
:auth_method:, :auth_username:, :auth_password:
|
||||
|
||||
the authentication details. Right now, either auth_method is not
|
||||
present meaning no authentication, or auth_method == `CHAP`
|
||||
meaning use CHAP with the specified credentials.
|
||||
"""
|
||||
iscsiip = self.configuration.iscsi_ip_address
|
||||
properties = {}
|
||||
|
||||
location = self._do_iscsi_discovery(volume)
|
||||
if not location:
|
||||
raise exception.InvalidVolume(_("Could not find iSCSI export "
|
||||
" for volume %s") %
|
||||
(volume['name']))
|
||||
|
||||
LOG.debug("ISCSI Discovery: Found %s" % (location))
|
||||
properties['target_discovered'] = True
|
||||
|
||||
device_info = self.common.find_device_number(volume, connector)
|
||||
if device_info is None or device_info['hostlunid'] is None:
|
||||
exception_message = (_("Cannot find device number for volume %s")
|
||||
% volume['name'])
|
||||
raise exception.VolumeBackendAPIException(data=exception_message)
|
||||
|
||||
device_number = device_info['hostlunid']
|
||||
|
||||
for loc in location:
|
||||
if iscsiip in loc:
|
||||
results = loc.split(" ")
|
||||
properties['target_portal'] = results[0].split(",")[0]
|
||||
properties['target_iqn'] = results[1]
|
||||
break
|
||||
|
||||
properties['target_lun'] = device_number
|
||||
properties['volume_id'] = volume['id']
|
||||
|
||||
LOG.debug("ISCSI properties: %s" % (properties))
|
||||
|
||||
auth = volume['provider_auth']
|
||||
if auth:
|
||||
(auth_method, auth_username, auth_secret) = auth.split()
|
||||
|
||||
properties['auth_method'] = auth_method
|
||||
properties['auth_username'] = auth_username
|
||||
properties['auth_password'] = auth_secret
|
||||
|
||||
return properties
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Disallow connection from connector."""
|
||||
self.common.terminate_connection(volume, connector)
|
||||
|
||||
@lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
|
||||
def extend_volume(self, volume, new_size):
|
||||
"""Extend an existing volume."""
|
||||
self.common.extend_volume(volume, new_size)
|
||||
|
||||
def get_volume_stats(self, refresh=False):
|
||||
"""Get volume stats.
|
||||
|
||||
If 'refresh' is True, run update the stats first.
|
||||
"""
|
||||
if refresh:
|
||||
self.update_volume_stats()
|
||||
|
||||
return self._stats
|
||||
|
||||
def update_volume_stats(self):
|
||||
"""Retrieve stats info from volume group."""
|
||||
LOG.debug("Updating volume stats")
|
||||
data = self.common.update_volume_stats()
|
||||
backend_name = self.configuration.safe_get('volume_backend_name')
|
||||
data['volume_backend_name'] = backend_name or 'FJDXISCSIDriver'
|
||||
data['storage_protocol'] = 'iSCSI'
|
||||
data['driver_version'] = self.VERSION
|
||||
self._stats = data
|
Loading…
Reference in New Issue
Block a user