File eternus-dx-volumedriver-1.1.1.diff of Package openstack-cinder
--- cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_common.py
+++ cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_common.py
@@ -0,0 +1,2988 @@
+# Copyright (c) 2014 FUJITSU LIMITED
+# Copyright (c) 2012 EMC Corporation.
+# Copyright (c) 2012 OpenStack Foundation
+# 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.
+#
+
+'''
+Cinder Volume driver for Fujitsu ETERNUS DX S2 and S3 series.
+'''
+
+##------------------------------------------------------------------------------------------------##
+## ##
+## ETERNUS OpenStack Volume Driver ##
+## ##
+## Note : ##
+## File Name : fujitsu_eternus_dx_common.py ##
+## Copyright 2014 FUJITSU LIMITED ##
+## ##
+## history : ##
+## 2014.03 : 1.0.0 : volume(create,delete,attach,detach,create from snapshot) ##
+## snapshot(create,delete) ##
+## 2014.04 : 1.0.1 : Fix comment ##
+## 2014.06 : 1.1.0 : Support 4 features ##
+## Extend Volume ##
+## Clone Volume ##
+## Copy Image to Volume ##
+## Copy Volume to Image ##
+## 2014.11 : 1.1.1 : Support ETERNUS DX V10L30 Firmware ##
+##------------------------------------------------------------------------------------------------##
+
+import time
+import hashlib
+import base64
+from oslo.config import cfg
+from xml.dom.minidom import *
+from xml.etree.ElementTree import *
+from cinder import exception
+from cinder.openstack.common import lockutils
+from cinder.openstack.common import log as logging
+
+LOG = logging.getLogger(__name__)
+
+try:
+ import pywbem
+except:
+ LOG.error(_('import pywbem failed!!'
+ 'pywbem is necessary for this volume driver.'))
+
+#**************************************************************************************************#
+CONF = cfg.CONF
+VOL_PREFIX = "FJosv_"
+RAIDGROUP = 2
+TPPOOL = 5
+SNAPOPC = 4
+OPC = 5
+RETURN_TO_RESOURCEPOOL = 19
+DETACH = 8
+INITIALIZED = 2
+UNSYNCHRONIZED = 3
+BROKEN = 5
+PREPARED = 11
+REPL = "FUJITSU_ReplicationService"
+STOR_CONF = "FUJITSU_StorageConfigurationService"
+CTRL_CONF = "FUJITSU_ControllerConfigurationService"
+STOR_HWID = "FUJITSU_StorageHardwareIDManagementService"
+
+#**************************************************************************************************#
+FJ_ETERNUS_DX_OPT_list = [cfg.StrOpt('cinder_eternus_config_file',
+ default='/etc/cinder/cinder_fujitsu_eternus_dx.xml',
+ help='config file for cinder fujitsu_eternus_dx volume driver')]
+
+#**************************************************************************************************#
+POOL_TYPE_dic = {RAIDGROUP:'RAID_GROUP',
+ TPPOOL :'Thinporvisioning_POOL'
+ }
+
+OPERATION_dic = {SNAPOPC:RETURN_TO_RESOURCEPOOL,
+ OPC :DETACH
+ }
+
+RETCODE_dic = {'0' :'Success',
+ '1' :'Method Not Supported',
+ '4' :'Failed',
+ '5' :'Invalid Parameter',
+ '4096' :'Success',
+ '4097' :'Size Not Supported',
+ '4101' :'Target/initiator combination already exposed',
+ '4102' :'Requested logical unit number in use',
+ '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 #
+# summary : cinder volume driver for Fujitsu ETERNUS DX #
+#--------------------------------------------------------------------------------------------------#
+class FJDXCommon(object):
+ '''
+ Common code that does not depend on protocol.
+ '''
+
+ # initialize
+ stats = {'driver_version': '1.1',
+ 'free_capacity_gb': 0,
+ 'reserved_percentage': 0,
+ 'storage_protocol': None,
+ 'total_capacity_gb': 0,
+ 'vendor_name': 'FUJITSU',
+ 'QoS_support': False,
+ 'volume_backend_name': None}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : __init__ #
+ # summary : #
+ # parameters : #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def __init__(self, prtcl, configuration=None):
+ '''
+ Constructor
+ '''
+ self.protocol = prtcl
+ self.configuration = configuration
+ self.configuration.append_config_values(FJ_ETERNUS_DX_OPT_list)
+
+ if prtcl == 'iSCSI':
+ # get iSCSI ipaddress from driver configuration file
+ self.configuration.iscsi_ip_address = self._get_drvcfg('EternusISCSIIP')
+ # end of if
+ self.conn = self._get_eternus_connection()
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume #
+ # summary : create volume on ETERNUS #
+ # parameters : volume #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_volume(self, volume):
+ '''
+ create volume on ETERNUS
+ '''
+ # volumesize : volume size Byte
+ # volumename : volumename on ETERNUS
+ # eternus_pool : poolname
+ # pool : pool instance
+ # pooltype : RAID(2) or TPP(5)
+ # configservice: FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****create_volume,Enter method'))
+
+ # initialize
+ systemnamelist = None
+ volumesize = 0
+ volumename = None
+ eternus_pool = None
+ pool = None
+ pooltype = 0
+ configservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ # conversion of the unit. GB to B
+ volumesize = int(volume['size']) * 1073741824
+
+ # create to volumename on ETERNUS from cinder VolumeID
+ volumename = self._create_volume_name(volume['id'])
+ LOG.debug(_('*****create_volume,volumename:%(volumename)s,'
+ 'volumesize:%(volumesize)u')
+ % {'volumename': volumename,
+ 'volumesize': volumesize})
+
+ self.conn = self._get_eternus_connection()
+
+ # get poolname from driver configuration file
+ eternus_pool = self._get_drvcfg('EternusPool')
+ # Existence check the pool
+ pool = self._find_pool(eternus_pool)
+ if pool is None:
+ msg = (_('create_volume,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # set pooltype
+ if 'RSP' in pool['InstanceID']:
+ pooltype = RAIDGROUP
+ else:
+ pooltype = TPPOOL
+ # end of if
+
+ configservice = self._find_eternus_service(STOR_CONF)
+ if configservice is None:
+ msg = (_('create_volume,volume:%(volume)s,'
+ 'volumename:%(volumename)s,'
+ 'eternus_pool:%(eternus_pool),'
+ 'Error!! Storage Configuration Service is None.')
+ % {'volume':volume,
+ 'volumename': volumename,
+ 'eternus_pool':eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ LOG.debug(_('*****create_volume,CreateOrModifyElementFromStoragePool,'
+ 'ConfigService:%(service)s,'
+ 'ElementName:%(volumename)s,'
+ 'InPool:%(eternus_pool)s,'
+ 'ElementType:%(pooltype)u,'
+ 'Size:%(volumesize)u')
+ % {'service':configservice,
+ 'volumename': volumename,
+ 'eternus_pool':eternus_pool,
+ 'pooltype':pooltype,
+ 'volumesize': volumesize})
+
+ # Invoke method for create volume
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateOrModifyElementFromStoragePool',
+ configservice,
+ ElementName=volumename,
+ InPool=pool,
+ ElementType=pywbem.Uint16(pooltype),
+ Size=pywbem.Uint64(volumesize))
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('create_volume,'
+ 'volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # get eternus model for metadata
+ # systemname = systemnamelist[0]['IdentifyingNumber']
+ # ex) ET092DC4511133A10
+ try:
+ systemnamelist = self.conn.EnumerateInstances(
+ 'FUJITSU_StorageProduct')
+ except:
+ msg=(_('create_volume,'
+ 'volume:%(volume)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'volume':volume})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ LOG.debug(_('*****create_volume,'
+ 'volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s,'
+ 'Backend:%(backend)s,'
+ 'Pool Name:%(eternus_pool)s,'
+ 'Pool Type:%(pooltype)s,'
+ 'Leaving create_volume')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc':errordesc,
+ 'backend':systemnamelist[0]['IdentifyingNumber'],
+ 'eternus_pool':eternus_pool,
+ 'pooltype':POOL_TYPE_dic[pooltype]})
+
+ return {'FJ_Backend':systemnamelist[0]['IdentifyingNumber'],
+ 'FJ_Volume_Name':volumename,
+ 'FJ_Pool_Name':eternus_pool,
+ 'FJ_Pool_Type':POOL_TYPE_dic[pooltype]}
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume_from_snapshot #
+ # summary : create volume from snapshot #
+ # parameters : volume, snapshot #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_volume_from_snapshot(self, volume, snapshot):
+ '''
+ Creates a volume from a snapshot
+ '''
+ # sysnames : FUJITSU_SrogareProduct
+ # backend : ETERNUS model
+ # snapshotname : snapshotname on OpenStack
+ # t_volumename : target volumename on ETERNUS
+ # s_volumename : source volumename on ETERNUS
+ # eternus_pool : poolname
+ # pool : pool instance
+ # pooltype : RAID(2) or TPP(5)
+ # configservice : FUJITSU_StorageConfigurationService
+ # source_volume_instance: snapshot instance
+ # target_volume_instance: target volume instance
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****create_volume_from_snapshot,Enter method'))
+
+ # initialize
+ systemnamelist = None
+ systemname = None
+ snapshotname = None
+ t_volumename = None
+ s_volumename = None
+ eternus_pool = None
+ pool = None
+ pooltype = 0
+ repservice = None
+ source_volume_instance = None
+ target_volume_instance = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ snapshotname = snapshot['name']
+ t_volumename = self._create_volume_name(volume['id'])
+ s_volumename = self._create_volume_name(snapshot['id'])
+ self.conn = self._get_eternus_connection()
+ source_volume_instance = self._find_lun(s_volumename)
+
+ # Existence check the source volume
+ if source_volume_instance is None:
+ msg=(_('create_volume_from_snapshot,'
+ 'Source Volume is not exist in ETERNUS.'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ # create volume for destination of cloned volume
+ self.create_volume(volume)
+ target_volume_instance = self._find_lun(t_volumename)
+
+ # get eternus model for metadata
+ # systemname = systemnamelist[0]['IdentifyingNumber']
+ # ex) ET092DC4511133A10
+ try:
+ systemnamelist = self.conn.EnumerateInstances(
+ 'FUJITSU_StorageProduct')
+ except:
+ msg=(_('create_volume_from_snapshot,'
+ 'volume:%(volume)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'volume':volume})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ systemname = systemnamelist[0]['IdentifyingNumber']
+
+ LOG.debug(_('*****create_volume_from_snapshot,'
+ 'volumename:%(volumename)s,'
+ 'snapshotname:%(snapshotname)s,'
+ 'source volume instance:%(source_volume_instance)s,')
+ % {'volumename': t_volumename,
+ 'snapshotname': snapshotname,
+ 'source_volume_instance': str(source_volume_instance.path)})
+
+ # get repservice for CreateElementReplica
+ repservice = self._find_eternus_service(REPL)
+
+ if repservice is None:
+ msg = (_('create_volume_from_snapshot,'
+ 'Replication Service not found'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # get poolname from driver configuration file
+ eternus_pool = self._get_drvcfg('EternusPool')
+ # Existence check the pool
+ pool = self._find_pool(eternus_pool)
+ if pool is None:
+ msg = (_('create_volume_from_snapshot,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # set pooltype
+ if 'RSP' in pool['InstanceID']:
+ pooltype = RAIDGROUP
+ else:
+ pooltype = TPPOOL
+ # end of if
+
+ # Invoke method for create cloned volume from snapshot
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateElementReplica',
+ repservice,
+ TargetPool=pool,
+ SyncType=pywbem.Uint16(8),
+ SourceElement=source_volume_instance.path,
+ TargetElement=target_volume_instance.path)
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('create_volume_from_snapshot,'
+ 'volumename:%(volumename)s,'
+ 'snapshotname:%(snapshotname)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volumename': t_volumename,
+ 'snapshotname': snapshotname,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.error(msg)
+ if rc == 5 and str(systemname[4]) == '2':
+ msg = (_('create_volume_from_snapshot,'
+ 'NOT supported on DX S2[%(backend)s].')
+ % {'backend':systemname})
+ LOG.error(msg)
+ # end of if
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****create_volume_from_snapshot,Exit method'))
+
+ return {'FJ_Backend':systemname,
+ 'FJ_Volume_Name':t_volumename,
+ 'FJ_Pool_Name':eternus_pool,
+ 'FJ_Pool_Type':POOL_TYPE_dic[pooltype]}
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_cloned_volume #
+ # summary : create cloned volume on ETERNUS #
+ # parameters : volume, src_vref #
+ # return-value : volume meta data #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_cloned_volume(self, volume, src_vref):
+ '''
+ Create clone of the specified volume.
+ '''
+ # sysnames : FUJITSU_SrogareProduct
+ # backend : ETERNUS model
+ # t_volumename : target volumename on ETERNUS
+ # s_volumename : source volumename on ETERNUS
+ # eternus_pool : poolname
+ # pool : pool instance
+ # pooltype : RAID(2) or TPP(5)
+ # repservice : FUJITSU_ReplicationService
+ # source_volume_instance: source volume instance
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****create_cloned_volume,Enter method'))
+
+ # initialize
+ systemnamelist = None
+ systemname = None
+ t_volumename = None
+ s_volumename = None
+ eternus_pool = None
+ pool = None
+ pooltype = 0
+ repservice = None
+ source_volume_instance = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ s_volumename = self._create_volume_name(src_vref['id'])
+ self.conn = self._get_eternus_connection()
+ source_volume_instance = self._find_lun(s_volumename)
+
+ # Existence check the source volume
+ if source_volume_instance is None:
+ msg=(_('create_cloned_volume,'
+ 'Source Volume is not exist in ETERNUS.'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ # create volume for destination of cloned volume
+ self.create_volume(volume)
+ t_volumename = self._create_volume_name(volume['id'])
+ target_volume_instance = self._find_lun(t_volumename)
+
+ # get eternus model for metadata
+ # systemname = systemnamelist[0]['IdentifyingNumber']
+ # ex) ET092DC4511133A10
+ try:
+ systemnamelist = self.conn.EnumerateInstances(
+ 'FUJITSU_StorageProduct')
+ except:
+ msg=(_('create_cloned_volume,'
+ 'volume:%(volume)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'volume':volume})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ systemname = systemnamelist[0]['IdentifyingNumber']
+
+ LOG.debug(_('*****create_cloned_volume,'
+ 'volumename:%(volumename)s,'
+ 'sourcevolumename:%(sourcevolumename)s,'
+ 'source volume instance:%(source_volume_instance)s,')
+ % {'volumename': t_volumename,
+ 'sourcevolumename': s_volumename,
+ 'source_volume_instance': str(source_volume_instance.path)})
+
+ # get replicationservice for CreateElementReplica
+ repservice = self._find_eternus_service(REPL)
+
+ if repservice is None:
+ msg = (_('create_cloned_volume,'
+ 'Replication Service not found'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # get poolname from driver configuration file
+ eternus_pool = self._get_drvcfg('EternusPool')
+ # Existence check the pool
+ pool = self._find_pool(eternus_pool)
+ if pool is None:
+ msg = (_('create_cloned_volume,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # set pooltype
+ if 'RSP' in pool['InstanceID']:
+ pooltype = RAIDGROUP
+ else:
+ pooltype = TPPOOL
+ # end of if
+
+ # Invoke method for create cloned volume from volume
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateElementReplica',
+ repservice,
+ TargetPool=pool,
+ SyncType=pywbem.Uint16(8),
+ SourceElement=source_volume_instance.path,
+ TargetElement=target_volume_instance.path)
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('create_cloned_volume,'
+ 'volumename:%(volumename)s,'
+ 'sourcevolumename:%(sourcevolumename)s,'
+ 'source volume instance:%(source_volume_instance)s,'
+ 'target volume instance:%(target_volume_instance)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volumename': t_volumename,
+ 'sourcevolumename': s_volumename,
+ 'source_volume_instance': str(source_volume_instance.path),
+ 'target_volume_instance': str(target_volume_instance.path),
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.error(msg)
+ if rc == 5 and str(systemname[4]) == '2':
+ msg = (_('create_cloned_volume,'
+ 'NOT supported on DX S2[%(backend)s].')
+ % {'backend':systemname})
+ LOG.error(msg)
+ # end of if
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****create_cloned_volume,Exit method'))
+
+ return {'FJ_Backend':systemname,
+ 'FJ_Volume_Name':t_volumename,
+ 'FJ_Pool_Name':eternus_pool,
+ 'FJ_Pool_Type':POOL_TYPE_dic[pooltype]}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_volume #
+ # summary : delete volume on ETERNUS #
+ # parameters : volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def delete_volume(self, volume):
+ '''
+ Delete volume on ETERNUS.
+ '''
+ # volumename : volumename on ETERNUS
+ # vol_instance : volume instance
+ # cps : copy session instance
+ # configservice: FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****delete_volume,Enter method'))
+
+ # initialize
+ volumename = None
+ vol_instance = None
+ cpsession = None
+ configservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main preprocessing
+ volumename = self._create_volume_name(volume['id'])
+ self.conn = self._get_eternus_connection()
+
+ # if volume is used by copysession,
+ # stop the copysession.
+ cpsession = self._find_copysession(volumename)
+ 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(cpsession)
+ # end of if
+
+ # Existence check the volume
+ vol_instance = self._find_lun(volumename)
+ if vol_instance is None:
+ LOG.debug(_('*****delete_volume,volumename:%(volumename)s,'
+ 'volume not found on ETERNUS.'
+ 'delete only management data on cinder database.')
+ % {'volumename': volumename})
+ return
+ # end of if
+
+ # begin volume deletion processing
+ configservice = self._find_eternus_service(STOR_CONF)
+ if configservice is None:
+ msg = (_('delete_volume,volumename:%(volumename)s,'
+ 'Storage Configuration Service not found.')
+ % {'volumename': volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****delete_volume,volumename:%(volumename)s,'
+ 'vol_instance:%(vol_instance)s,'
+ 'Method: ReturnToStoragePool')
+ % {'volumename': volumename,
+ 'vol_instance': str(vol_instance.path)})
+
+ # Invoke method for delete volume
+ rc, errordesc, job = self._exec_eternus_service(
+ 'ReturnToStoragePool',
+ configservice,
+ TheElement=vol_instance.path)
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('delete_volume,volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc': errordesc})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****delete_volume,volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s,'
+ 'Exit Method')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc': errordesc})
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_snapshot #
+ # summary : create snapshot using SnapOPC #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_snapshot(self, snapshot):
+ '''
+ create snapshot using SnapOPC
+ '''
+ # snapshotname : snapshot name on Openstack
+ # volumename : source volume name on Openstack
+ # vol_id : source volume id
+ # volume : source volume dictionary
+ # vol_instance : source volume instance
+ # s_volumename : source volume name on ETERNUS
+ # d_volumename : destination volume name on ETERNUS
+ # eternus_pool : poolname
+ # pool : pool instance
+ # configservice : FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****create_snapshot,Enter method'))
+
+ # initialize
+ snapshotname = None
+ volumename = None
+ vol_id = None
+ volume = None
+ vol_instance = None
+ d_volumename = None
+ s_volumename = None
+ vol_instance = None
+ configservice = None
+ eternus_pool = None
+ pool = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ snapshotname = snapshot['name']
+ volumename = snapshot['volume_name']
+ vol_id = snapshot['volume_id']
+ volume = snapshot['volume']
+ d_volumename = self._create_volume_name(snapshot['id'])
+ s_volumename = self._create_volume_name(vol_id)
+ vol_instance = self._find_lun(s_volumename)
+ configservice = self._find_eternus_service(STOR_CONF)
+ self.conn = self._get_eternus_connection()
+
+ # Existence check the volume
+ if vol_instance is None:
+ # source volume is not found on ETERNUS
+ msg = (_('create_snapshot,'
+ 'volumename on ETERNUS:%(s_volumename)s,'
+ 'source volume is not found on ETERNUS.')
+ % {'s_volumename': s_volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ if configservice is None:
+ msg = (_('create_snapshot,'
+ 'volumename:%(volumename)s,'
+ 'Storage Configuration Service not found.')
+ % {'volumename': volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # get poolname from driver configuration file
+ eternus_pool = self._get_drvcfg('EternusPool')
+ # Existence check the pool
+ pool = self._find_pool(eternus_pool)
+ if pool is None:
+ msg = (_('create_snapshot,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****create_snapshot,'
+ 'snapshotname:%(snapshotname)s,'
+ 'source volume name:%(volumename)s,'
+ 'vol_instance.path:%(vol_instance)s,'
+ 'dest_volumename:%(d_volumename)s,'
+ 'pool:%(pool)s,'
+ 'Invoke CreateReplica')
+ % {'snapshotname': snapshotname,
+ 'volumename': volumename,
+ 'vol_instance': str(vol_instance.path),
+ 'd_volumename': d_volumename,
+ 'pool': pool})
+
+ # Invoke method for create snapshot
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateReplica',
+ configservice,
+ ElementName=d_volumename,
+ TargetPool=pool,
+ CopyType=pywbem.Uint16(4),
+ SourceElement=vol_instance.path)
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('create_snapshot,'
+ 'snapshotname:%(snapshotname)s,'
+ 'source volume name:%(volumename)s,'
+ 'vol_instance.path:%(vol_instance)s,'
+ 'dest_volumename:%(d_volumename)s,'
+ 'pool:%(pool)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'snapshotname': snapshotname,
+ 'volumename': volumename,
+ 'vol_instance': str(vol_instance.path),
+ 'd_volumename': d_volumename,
+ 'pool': pool,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****create_snapshot,volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s,'
+ 'Exit Method')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc': errordesc})
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_snapshot #
+ # summary : delete snapshot #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def delete_snapshot(self, snapshot):
+ '''
+ delete snapshot
+ '''
+ # Delete snapshot - deletes the target element and the snap session
+ # snapshotname : snapshot display name
+ # volumename : source volume display name on openstack
+ # d_volumename : destination volume name on ETERNUS
+ # snapshot['id']: destination volume id for _find_lun
+ # cpsession : Storage Synchronized
+ # repservice : FUJITSU_ReplicationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+
+ LOG.debug(_('*****delete_snapshot,Enter method'))
+
+ # initialize
+
+ # main processing
+
+ self.delete_volume(snapshot)
+
+ LOG.debug(_('*****delete_snapshot,Exit method'))
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : initialize_connection #
+ # summary : set HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : connection info #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def initialize_connection(self, volume, connector):
+ '''
+ Allow connection to connector and return connection info.
+ '''
+ # targetlist : target port id list
+ # mapdata : the element which constitutes device_info
+ # msg : message
+ # device_info: return value
+
+ LOG.debug(_('*****initialize_connection,Enter method'))
+
+ # initialize
+ targetlist = []
+ mapdata = {}
+ msg = None
+ device_info = {}
+
+ # main processing
+ self.conn = self._get_eternus_connection()
+ targetlist = self._get_target_portid(connector)
+ mapdata = self._find_device_number(volume, connector, targetlist)
+
+ if len(mapdata) == 0:
+ # volume not found on ETERNUS
+ msg = (_('initialize_connection,'
+ 'volume:%(volume)s,'
+ 'Volume not found.')
+ % {'volume':volume['name']})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ if mapdata['target_lun'] is not None:
+ # volume is already mapped
+ msg = (_('initialize_connection,'
+ 'volume:%(volume)s,'
+ 'target_lun:%(target_lun)s,'
+ 'Volume is already mapped.')
+ % {'volume':volume['name'],
+ 'target_lun':mapdata['target_lun']})
+ LOG.info(msg)
+ else:
+ self._map_lun(volume, connector, targetlist)
+ mapdata = self._find_device_number(volume, connector, targetlist)
+ # end of if
+
+ mapdata['target_discoverd'] = True
+ mapdata['volume_id'] = volume['id']
+
+ if self.protocol == 'iSCSI':
+ device_info = {'driver_volume_type': 'iscsi',
+ 'data': mapdata}
+ elif self.protocol == 'fc':
+ device_info = {'driver_volume_type': 'fibre_channel',
+ 'data': mapdata}
+ # end of if
+
+ LOG.debug(_('*****initialize_connection,'
+ 'device_info:%(info)s,'
+ 'Exit method')
+ % {'info': device_info})
+
+ return device_info
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : terminate_connection #
+ # summary : remove HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def terminate_connection(self, volume, connector, force=False, **kwargs):
+ '''
+ Disallow connection from connector
+ '''
+ LOG.debug(_('*****terminate_connection,Enter method'))
+
+ # main processing
+ self.conn = self._get_eternus_connection()
+ self._unmap_lun(volume, connector)
+
+ LOG.debug(_('*****terminate_connection,Exit method'))
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : extend_volume #
+ # summary : extend volume on ETERNUS #
+ # parameters : volume new_size #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def extend_volume(self, volume, new_size):
+ '''
+ extend volume on ETERNUS
+ '''
+ # volumesize : volume new size Byte
+ # volumename : volumename on ETERNUS
+ # source_volume_instance : source volume instance
+ # eternus_pool : poolname
+ # pool : pool instance
+ # pooltype : RAID(2) or TPP(5)
+ # configservice : FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****extend_volume,Enter method'))
+
+ # initialize
+ systemnamelist = None
+ volumesize = 0
+ volumename = None
+ source_volume_instance = None
+ eternus_pool = None
+ pool = None
+ pooltype = 0
+ configservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ #main processing
+ #conversion of the unit. GB to B
+ volumesize = new_size * 1073741824
+ #create to volumename on ETERNUS from cinder VolumeID
+ volumename = self._create_volume_name(volume['id'])
+ #get source volume instance
+ source_volume_instance = self._find_lun(volumename)
+ if source_volume_instance is None:
+ msg = (_('extend_volume,'
+ 'source_volume:%(volumename)s,'
+ 'not found.')
+ % {'volumename': volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****extend_volume,volumename:%(volumename)s,'
+ 'volumesize:%(volumesize)u,'
+ 'source volume instance:%(source_volume_instance)s,'
+ % {'volumename': volumename,
+ 'volumesize': volumesize,
+ 'source_volume_instance': str(source_volume_instance.path)}))
+
+ self.conn = self._get_eternus_connection()
+
+ # get poolname from driver configuration file
+ eternus_pool = self._get_drvcfg('EternusPool')
+ # Existence check the pool
+ pool = self._find_pool(eternus_pool)
+ if pool is None:
+ msg = (_('extend_volume,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # set pooltype
+ if 'RSP' in pool['InstanceID']:
+ pooltype = RAIDGROUP
+ else:
+ pooltype = TPPOOL
+ # end of if
+
+ configservice = self._find_eternus_service(STOR_CONF)
+ if configservice is None:
+ msg = (_('extend_volume,volume:%(volume)s,'
+ 'volumename:%(volumename)s,'
+ 'eternus_pool:%(eternus_pool),'
+ 'Error!! Storage Configuration Service is None.')
+ % {'volume':volume,
+ 'volumename': volumename,
+ 'eternus_pool':eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ LOG.debug(_('*****extend_volume,CreateOrModifyElementFromStoragePool,'
+ 'ConfigService:%(service)s,'
+ 'ElementName:%(volumename)s,'
+ 'InPool:%(eternus_pool)s,'
+ 'ElementType:%(pooltype)u,'
+ 'Size:%(volumesize)u,'
+ 'TheElement:%(source_volume_instance)s')
+ % {'service':configservice,
+ 'volumename': volumename,
+ 'eternus_pool':eternus_pool,
+ 'pooltype':pooltype,
+ 'volumesize': volumesize,
+ 'source_volume_instance': str(source_volume_instance.path)})
+
+ # Invoke method for extend volume
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateOrModifyElementFromStoragePool',
+ configservice,
+ ElementName=volumename,
+ InPool=pool,
+ ElementType=pywbem.Uint16(pooltype),
+ Size=pywbem.Uint64(volumesize),
+ TheElement=source_volume_instance.path)
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('extend_volume,'
+ 'volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s,'
+ 'PoolType:%(pooltype)s')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc':errordesc,
+ 'pooltype':POOL_TYPE_dic[pooltype]})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****extend_volume,'
+ 'volumename:%(volumename)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s,'
+ 'Pool Name:%(eternus_pool)s,'
+ 'Pool Type:%(pooltype)s,'
+ 'Leaving extend_volume')
+ % {'volumename': volumename,
+ 'rc': rc,
+ 'errordesc':errordesc,
+ 'eternus_pool':eternus_pool,
+ 'pooltype':POOL_TYPE_dic[pooltype]})
+ return
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : refresh_volume_stats #
+ # summary : get pool capacity #
+ # parameters : None #
+ # return-value : self.stats #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def refresh_volume_stats(self):
+ '''
+ get pool capacity.
+ '''
+ # eternus_pool : poolname
+ # pool : pool instance
+
+ LOG.debug(_('*****refresh_volume_stats,Enter method'))
+
+ # initialize
+ eternus_pool = None
+ pool = None
+
+ # main processing
+ self.conn = self._get_eternus_connection()
+ eternus_pool = self._get_drvcfg('EternusPool')
+ pool = self._find_pool(eternus_pool,True)
+
+ # Existence check the pool
+ if pool is None:
+ msg = (_('refresh_volume_stats,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found.')
+ % {'eternus_pool': eternus_pool})
+ LOG.info(msg)
+
+ # create pool(RAID Group)
+ self._create_pool(eternus_pool)
+ pool = self._find_pool(eternus_pool,True)
+ if pool is None:
+ msg = (_('refresh_volume_stats,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'not found after create_pool.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ # end of if
+
+ self.stats['total_capacity_gb'] = pool['TotalManagedSpace']
+ self.stats['free_capacity_gb'] = pool['RemainingManagedSpace']
+
+ LOG.debug(_('*****refresh_volume_stats,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'total capacity[%(total)s],'
+ 'free capacity[%(free)s]')
+ % {'eternus_pool':eternus_pool,
+ 'total':self.stats['total_capacity_gb'],
+ 'free':self.stats['free_capacity_gb']})
+
+ return self.stats
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_device_number #
+ # summary : return number of mapping order #
+ # parameters : volume, connector, targetlist #
+ # return-value : mapping order #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_device_number(self, volume, connector, targetlist = []):
+ '''
+ return mapping order
+ '''
+ # map_num : number of mapping order
+ # mapdata : device information
+ # volumename : volumename on ETERNUS
+ # vol_instance : volume instance
+ # ag_instance : affinity group instance
+ # aglist : affinity group list associated with the connector and the volume
+ # targetlist : target portid
+ # vo_volmaplist : volume mapping information list associated with the volume
+ # ag_volmaplist : volume mapping information list associated with the affinitygroup
+ # vo_volmap : volume mapping information associated with the volume
+ # ag_volmap : volume mapping information associated with the affinitygroup
+ # volmapinstance : volume mapping instance
+ # iqn : iSCSI Qualified Name associated with the volume and the affinitygroup
+ # found_volmaplist : volume mapping information list
+
+ LOG.debug(_('*****_find_device_number,Enter method'))
+
+ # initialize
+ map_num = None
+ mapdata = {}
+ volumename = None
+ vol_instance = None
+ ag_instance = None
+ aglist = []
+ vo_volmaplist = []
+ ag_volmaplist = []
+ vo_volmap = None
+ ag_volmap = None
+ volmapinstance = {}
+ iqn = None
+ found_volmaplist = []
+
+ # main processing
+ volumename = self._create_volume_name(volume['id'])
+ vol_instance = self._find_lun(volumename)
+
+ # Existence check the volume
+ if vol_instance is None:
+ # volume does not found
+ LOG.debug(_('*****_find_device_number,Device does not found.'))
+ return mapdata
+ # end of if
+
+ # find affinity group
+ # attach the connector and include the volume
+ aglist = self._find_affinity_group(connector, vol_instance)
+ if len(aglist) == 0 :
+ LOG.debug(_('*****_find_device_number,ag_list:%s') % (aglist))
+ else:
+ ag_instance = self.conn.GetInstance(aglist[0],LocalOnly=False)
+
+ # get volume mapping order
+ try:
+ ag_volmaplist = self.conn.ReferenceNames(
+ ag_instance.path,
+ ResultClass='CIM_ProtocolControllerForUnit')
+ vo_volmaplist = self.conn.ReferenceNames(
+ vol_instance.path,
+ ResultClass='CIM_ProtocolControllerForUnit')
+ except:
+ msg=(_('_find_device_number,'
+ 'volume:%(volume)s,'
+ 'ReferenceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'volume':volume})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ LOG.debug(_('*****_find_device_number,'
+ 'ag_volmaplist:%(ag_volmaplist)s,'
+ 'vo_volmaplist:%(vo_volmaplist)s'
+ )
+ % {'ag_volmaplist':ag_volmaplist,
+ 'vo_volmaplist':vo_volmaplist})
+
+ for ag_volmap in ag_volmaplist:
+ for vo_volmap in vo_volmaplist:
+ LOG.debug(_('*****_find_device_number,ag_volmap:%s') % (ag_volmap))
+ LOG.debug(_('*****_find_device_number,vo_volmap:%s') % (vo_volmap))
+ if ag_volmap == vo_volmap:
+ found_volmaplist.append(ag_volmap)
+ break
+ # end of if
+ if len(found_volmaplist) != 0:
+ break
+ # end of if
+ # end of for ag_volmaplist
+ LOG.debug(_('*****_find_device_number,found_volmaplist:%s') % found_volmaplist)
+
+ for found_volmap in found_volmaplist:
+ try:
+ volmapinstance = self.conn.GetInstance(
+ found_volmap,
+ LocalOnly=False)
+ except:
+ msg=(_('_find_device_number,'
+ 'volume:%(volume)s,'
+ 'GetInstance,'
+ 'cannot connect to ETERNUS.')
+ % {'volume':volume})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ map_num = int(volmapinstance['DeviceNumber'], 16)
+ LOG.debug(_('*****_find_device_number,found_volmap:%s') % (found_volmap))
+ LOG.debug(_('*****_find_device_number,map_num:%s') % (map_num))
+ # end of for found_volmaplist
+ # end of if
+
+ if map_num is None:
+ msg = (_('_find_device_number,'
+ 'Device number not found for volume'
+ '%(volumename)s %(vol_instance)s.')
+ % {'volumename': volumename,
+ 'vol_instance': str(vol_instance.path)})
+ LOG.info(msg)
+ else:
+ LOG.debug(_('*****_find_device_number,'
+ 'Found device number %(device)d for volume'
+ ' %(volumename)s %(vol_instance)s.')
+ % {'device': map_num,
+ 'volumename': volumename,
+ 'vol_instance': str(vol_instance.path)})
+ # end of if
+
+
+ if self.protocol == 'iSCSI':
+ iqn = self._get_iqn()
+
+ LOG.debug(_('*****_find_device_number,'
+ 'iqn:%(iqn)s')
+ % {'iqn':iqn})
+ target_portal = '%s:%s' % (self.configuration.iscsi_ip_address,
+ self.configuration.iscsi_port)
+ mapdata = {'target_lun': map_num,
+ 'target_iqn': iqn,
+ 'target_portal': target_portal}
+
+ elif self.protocol == 'fc':
+ if len(targetlist) == 0:
+ targetlist = self._get_target_portid(connector)
+ # end of if
+
+ LOG.debug(_('*****_find_device_number,'
+ 'targetlist:%(targetlist)s')
+ % {'targetlist':targetlist})
+
+ mapdata = {'target_lun': map_num,
+ 'target_wwn': targetlist}
+ # end of if
+
+ LOG.debug(_('*****_find_device_number,Device info: %(mapdata)s.')
+ % {'mapdata': mapdata})
+
+ return mapdata
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _get_drvcfg #
+ # summary : read parameter from driver configuration file #
+ # parameters : tagname, filename #
+ # return-value : value of tagname #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _get_drvcfg(self,tagname,filename=None):
+ '''
+ read from driver configuration file.
+ '''
+ # filename : driver configuration file name
+ # tagname : xml tagname
+ # tree : element tree from driver configuration file
+ # elem : root element
+ # ret : return value
+
+ LOG.debug(_('*****_get_drvcfg,Enter method'))
+
+ # initialize
+ tree = None
+ elem = None
+ ret = None
+
+ # main processing
+ if filename is None:
+ # set default configuration file name
+ filename = self.configuration.cinder_eternus_config_file
+ # end of if
+
+ LOG.debug(_("*****_get_drvcfg input[%s][%s]") %(filename, tagname))
+
+ tree = parse(filename)
+ elem = tree.getroot()
+ ret = elem.findtext(".//"+tagname)
+
+ if ret is None or ret == "":
+ msg = (_('_get_drvcfg,'
+ 'filename:%(filename)s,'
+ 'tagname:%(tagname)s,'
+ 'data is None!! '
+ 'Please edit driver configuration file and correct an error. ')
+ % {'filename':filename,
+ 'tagname':tagname})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_("*****_get_drvcfg output[%s]") %(ret))
+
+ return ret
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _get_eternus_connection #
+ # summary : return WBEM connection #
+ # parameters : filename #
+ # return-value : WBEM connection #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _get_eternus_connection(self, filename=None):
+ '''
+ return WBEM connection
+ '''
+ # filename : driver configuration file name
+ # ip : SMI-S IP address
+ # port : SMI-S port
+ # user : SMI-S username
+ # password : SMI-S password
+ # url : SMI-S connection url
+ # conn : WBEM connection
+
+ LOG.debug(_("*****_get_eternus_connection [%s],"
+ "Enter method")
+ % filename)
+
+ # initialize
+ ip = None
+ port = None
+ user = None
+ password = None
+ url = None
+ conn = None
+
+ # main processing
+ ip = self._get_drvcfg('EternusIP', filename)
+ port = self._get_drvcfg('EternusPort', filename)
+ user = self._get_drvcfg('EternusUser', filename)
+ passwd = self._get_drvcfg('EternusPassword', filename)
+ url = 'http://'+ip+':'+port
+
+ conn = pywbem.WBEMConnection(url, (user, passwd),
+ default_namespace='root/eternus')
+
+ if conn is None:
+ msg = (_('_get_eternus_connection,'
+ 'filename:%(filename)s,'
+ 'ip:%(ip)s,'
+ 'port:%(port)s,'
+ 'user:%(user)s,'
+ 'passwd:%(passwd)s,'
+ 'url:%(url)s,'
+ 'FAILED!!.')
+ % {'filename':filename,
+ 'ip':ip,
+ 'port':port,
+ 'user':user,
+ 'passwd':passwd,
+ 'url':url})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****_get_eternus_connection,[%s],Exit method') % (conn))
+
+ return conn
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _create_volume_name #
+ # summary : create volume_name on ETERNUS from id on OpenStack. #
+ # parameters : id_code #
+ # return-value : volumename on ETERNUS #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _create_volume_name(self, id_code):
+ '''
+ create volume_name on ETERNUS from id on OpenStack.
+ '''
+ # id_code : volume_id, snapshot_id etc..
+ # m : hashlib.md5 instance
+ # ret : volumename on ETERNUS
+ # systemnamelist : ETERNUS information list
+ # systemname : ETERNUS model information
+
+ LOG.debug(_('*****_create_volume_name [%s],Enter method.')
+ % id_code)
+
+ # initialize
+ m = None
+ ret = None
+ systemnamelist = None
+ systemname = None
+
+ # main processing
+ if id_code is None:
+ msg=(_('_create_volume_name,'
+ 'id_code is None.'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ m = hashlib.md5()
+ m.update(id_code)
+ ret = VOL_PREFIX + str(base64.urlsafe_b64encode(m.digest()))
+
+ # get eternus model for volumename length
+ # systemname = systemnamelist[0]['IdentifyingNumber']
+ # ex) ET092DC4511133A10
+ try:
+ systemnamelist = self.conn.EnumerateInstances(
+ 'FUJITSU_StorageProduct')
+ except:
+ msg=(_('create_volume_name,'
+ 'id_code:%(id_code)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'id_code':id_code})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ systemname = systemnamelist[0]['IdentifyingNumber']
+
+ LOG.debug(_('*****_create_volume_name,'
+ 'systemname:%(systemname)s,'
+ 'storage is DX S%(model)s')
+ % {'systemname':systemname,
+ 'model':systemname[4]})
+
+ # shorten volumename when storage is DX S2 series
+ if str(systemname[4]) == '2':
+ LOG.debug(_('*****_create_volume_name,'
+ 'volumename is 16 digit.'))
+ ret = ret[:16]
+ # end of if
+
+ LOG.debug(_('*****_create_volume_name,'
+ 'ret:%(ret)s,'
+ 'Exit method.')
+ % {'ret':ret})
+
+ return ret
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _get_pool_instance_id #
+ # summary : get pool instacne_id from pool name on ETERNUS #
+ # parameters : eternus_pool #
+ # return-value : pool instance id #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _get_pool_instance_id(self, eternus_pool):
+ '''
+ get pool instacne_id from pool name on ETERNUS
+ '''
+ # eternus_pool : pool name on ETERNUS.
+ # poolinstanceid: ETERNUS pool instance id(return value)
+ # tppoollist : list of thinprovisioning pool on ETERNUS.
+ # rgpoollist : list of raid group on ETERNUS.
+ # tppool : Thinprovisioning Pool
+ # rgpool : RAID Group
+ # msg : message
+
+ LOG.debug(_('*****_get_pool_instance_id,'
+ 'Enter method'))
+
+ # initialize
+ poolinstanceid = None
+ tppoollist = []
+ rgpoollist = []
+ tppool = None
+ rgpool = None
+ poolname = None
+ msg = None
+
+
+ # main processing
+ try:
+ rgpoollist = self.conn.EnumerateInstances(
+ 'FUJITSU_RAIDStoragePool')
+ tppoollist = self.conn.EnumerateInstances(
+ 'FUJITSU_ThinProvisioningPool')
+ except:
+ msg=(_('_get_pool_instance_id,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'eternus_pool':eternus_pool})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+
+ for rgpool in rgpoollist:
+ poolname = rgpool['ElementName']
+ if str(eternus_pool) == str(poolname):
+ poolinstanceid = rgpool['InstanceID']
+ break
+ # end of if
+ else:
+ for tppool in tppoollist:
+ poolname = tppool['ElementName']
+ if str(eternus_pool) == str(poolname):
+ poolinstanceid = tppool['InstanceID']
+ break
+ # end of if
+ # end of for tppoollist
+ # end of for rgpoollist
+
+ if poolinstanceid is None:
+ msg = (_('_get_pool_instance_id,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'poolinstanceid is None.')
+ % {'eternus_pool': eternus_pool})
+ LOG.info(msg)
+ # end of if
+
+ LOG.debug(_('*****_get_pool_instance_id,'
+ 'Exit method'))
+
+ return poolinstanceid
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _create_pool #
+ # summary : create raidgroup on ETERNUS #
+ # parameters : eternus_pool #
+ # return-value : None #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _create_pool(self, eternus_pool):
+ '''
+ create raidgroup on ETERNUS.
+ '''
+ # create raidgroup on ETERNUS.
+ # raidgroup name is eternus_pool.
+ # raidlevel and diskdrives are automatically selected.
+ #
+ # eternus_pool : poolname on ETERNUS
+ # configservice: FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****_create_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'Enter method.')
+ % {'eternus_pool': eternus_pool})
+
+ # initialize
+ poolinstance = None
+ configservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ configservice = self._find_eternus_service(STOR_CONF)
+ if configservice is None:
+ msg = (_('_create_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'configservice is None.')
+ % {'eternus_pool': eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # Invoke method for create pool
+ # Raid Level and DiskDrives are automatically selected.
+ rc, errordesc, job = self._exec_eternus_service(
+ 'CreateOrModifyStoragePool',
+ configservice,
+ ElementName=eternus_pool)
+
+ if rc != 0L and rc != 4096L:
+ msg=(_('_create_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'eternus_pool':eternus_pool,
+ 'rc':rc,
+ 'errordesc':errordesc})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ LOG.debug(_('*****_create_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'Exit method.')
+ % {'eternus_pool': eternus_pool})
+
+ return
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_pool #
+ # summary : find Instance or Name of pool by pool name on ETERNUS. #
+ # parameters : eternus_pool, detail #
+ # return-value : pool instance or instance name #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_pool(self, eternus_pool, detail=False):
+ '''
+ find Instance or InstanceName of pool by pool name on ETERNUS.
+ '''
+ # eternus_pool : poolname
+ # detail : False >return EnumerateInstanceNames
+ # : True >return EnumerateInstances
+ # poolinstanceid: pool instance id
+ # poolinstance : pool instance
+ # msg : message
+ # tppoollist : list of thinprovisioning pool on ETERNUS.
+ # rgpoollist : list of raid group on ETERNUS.
+
+ LOG.debug(_('*****_find_pool,Enter method'))
+
+ # initialize
+ poolinstanceid = None
+ poolinstance = None
+ msg = None
+ tppoollist = []
+ rgpoollist = []
+
+ #main processing
+ poolinstanceid = self._get_pool_instance_id(eternus_pool)
+ #if pool instance is None then create pool on ETERNUS.
+ if poolinstanceid is None:
+ msg = (_('_find_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'poolinstanceid is None.')
+ % {'eternus_pool': eternus_pool})
+ LOG.info(msg)
+
+ else:
+
+ if detail is True:
+ try:
+ tppoollist = self.conn.EnumerateInstances(
+ 'FUJITSU_ThinProvisioningPool')
+ rgpoollist = self.conn.EnumerateInstances(
+ 'FUJITSU_RAIDStoragePool')
+ except:
+ msg=(_('_find_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'EnumerateInstances,'
+ 'cannot connect to ETERNUS.')
+ % {'eternus_pool':eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ else:
+ try:
+ tppoollist = self.conn.EnumerateInstanceNames(
+ 'FUJITSU_ThinProvisioningPool')
+ rgpoollist = self.conn.EnumerateInstanceNames(
+ 'FUJITSU_RAIDStoragePool')
+ except:
+ msg=(_('_find_pool,'
+ 'eternus_pool:%(eternus_pool)s,'
+ 'EnumerateInstanceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'eternus_pool':eternus_pool})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ for tppool in tppoollist:
+ if str(poolinstanceid) == str(tppool['InstanceID']):
+ poolinstance = tppool
+ break
+ # end of if
+ else:
+ for rgpool in rgpoollist:
+ if str(poolinstanceid) == str(rgpool['InstanceID']):
+ poolinstance = rgpool
+ break
+ # end of if
+ # end of for rgpoollist
+ # end of for tppoollist
+ # end of if
+ LOG.debug(_('*****_find_pool,'
+ 'poolinstance: %(poolinstance)s,'
+ 'Exit method.')
+ % {'poolinstance': str(poolinstance)})
+
+ return poolinstance
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_eternus_service #
+ # summary : find CIM instance #
+ # parameters : classname #
+ # return-value : CIM instance #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_eternus_service(self, classname):
+ '''
+ find CIM instance
+ '''
+ # ret : CIM instance
+ # services : CIM instance service name
+
+ LOG.debug(_('*****_find_eternus_service,'
+ 'classname:%(a)s,'
+ 'Enter method')
+ % {'a':str(classname)})
+
+ # initialize
+ ret = None
+ services = None
+
+ # main processing
+ try:
+ services = self.conn.EnumerateInstanceNames(
+ str(classname))
+ except:
+ msg=(_('_find_eternus_service,'
+ 'classname:%(classname)s,'
+ 'EnumerateInstanceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'classname':str(classname)})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ ret = services[0]
+ LOG.debug(_('*****_find_eternus_service,'
+ 'classname:%(classname)s,'
+ 'ret:%(ret)s,'
+ 'Exit method')
+ % {'classname':classname,
+ 'ret':(str(ret))})
+ return ret
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _exec_eternus_service #
+ # summary : Execute SMI-S Method #
+ # parameters : classname, instanceNameList, param_dict #
+ # return-value : status code, error description, data #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _exec_eternus_service(self, classname, instanceNameList, **param_dict):
+ '''
+ Execute SMI-S Method
+ '''
+ # rc : result of InvokeMethod
+ # retdata : return data
+ # errordesc: error description
+
+ LOG.debug(_('*****_exec_eternus_service,'
+ 'classname:%(a)s,'
+ 'instanceNameList:%(b)s,'
+ 'paramters:%(c)s,'
+ 'Enter method')
+ % {'a':str(classname),
+ 'b':str(instanceNameList),
+ 'c':str(param_dict)})
+
+ # initialize
+ rc = None
+ retdata = None
+ errordesc = None
+
+ # main processing
+ # use InvokeMethod
+ try:
+ rc, retdata = self.conn.InvokeMethod(
+ classname,
+ instanceNameList,
+ **param_dict)
+ except:
+ if rc is None:
+ msg=(_('_exec_eternus_service,'
+ 'classname:%(classname)s,'
+ 'InvokeMethod,'
+ 'cannot connect to ETERNUS.')
+ % {'classname':str(classname)})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ # convert errorcode to error description
+ try:
+ errordesc = RETCODE_dic[str(rc)]
+ except:
+ errordesc = 'Undefined Error!!'
+ ret = (rc, errordesc, retdata)
+
+ LOG.debug(_('*****_exec_eternus_service,'
+ 'classname:%(a)s,'
+ 'instanceNameList:%(b)s,'
+ 'paramters:%(c)s,'
+ 'Return code:%(rc)s,'
+ 'Error:%(errordesc)s,'
+ 'Exit method')
+ % {'a':str(classname),
+ 'b':str(instanceNameList),
+ 'c':str(param_dict),
+ 'rc':str(rc),
+ 'errordesc':errordesc})
+
+ return ret
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_lun #
+ # summary : find lun instance from volume class or volumename on ETERNUS. #
+ # parameters : volume #
+ # return-value : volume instance #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_lun(self, volumename):
+ '''
+ find lun instance from volume class or volumename on ETERNUS.
+ '''
+ # volumename : volume name on ETERNUS
+ # namelist : volume list
+ # name : volume instanceName
+ # vol_instance : volume instance for temp
+ # volumeinstance: volume instance for return
+
+ LOG.debug(_('*****_find_lun,Enter method'))
+
+ # initialize
+ namelist = []
+ name = None
+ vol_instance = None
+ volumeinstance = None
+
+ # main processing
+ LOG.debug(_('*****_find_lun,'
+ 'volumename:%(volumename)s')
+ % {'volumename':volumename})
+
+ # get volume instance from volumename on ETERNUS
+ try:
+ namelist = self.conn.EnumerateInstanceNames(
+ 'FUJITSU_StorageVolume')
+ except:
+ msg=(_('_find_lun,'
+ 'volumename:%(volumename)s,'
+ 'EnumerateInstanceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'volumename':volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ for name in namelist:
+ try:
+ vol_instance = self.conn.GetInstance(
+ name)
+ except:
+ msg=(_('_find_lun,'
+ 'volumename:%(volumename)s,'
+ 'GetInstance,'
+ 'cannot connect to ETERNUS.')
+ % {'volumename':volumename})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ if vol_instance['ElementName'] == volumename:
+ volumeinstance = vol_instance
+
+ LOG.debug(_('*****_find_lun,'
+ 'volumename:%(volumename)s,'
+ 'vol_instance:%(vol_instance)s.')
+ % {'volumename': volumename,
+ 'vol_instance': str(volumeinstance.path)})
+ break
+ # end of if
+ else:
+ LOG.debug(_('*****_find_lun,'
+ 'volumename:%(volumename)s,'
+ 'volume not found on ETERNUS.')
+ % {'volumename': volumename})
+ # end of for namelist
+
+ LOG.debug(_('*****_find_lun,Exit method'))
+
+ #return volume instance
+ return volumeinstance
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_copysession #
+ # summary : find copysession from volumename on ETERNUS #
+ # parameters : volumename #
+ # return-value : volume instance #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_copysession(self, volumename):
+ '''
+ find copysession from volumename on ETERNUS
+ '''
+ # cpsession : copysession
+ # vol_instance : volume instance
+ # repservice : FUJITSU_ReplicationService
+ # rc : Invoke Method return code
+ # replicarellist : copysession information list
+ # replicales : copysession information
+ # snapshot_vol_instance : snapshot volume instance
+ # msg : message
+ # errordesc : error description
+ # cpsession_instance : copysession instance
+
+ LOG.debug(_('*****_find_copysession,'
+ 'volumename:%s,'
+ 'Enter method')
+ % volumename)
+
+ # initialize
+ cpsession = None
+ vol_instance = None
+ repservice = None
+ rc = 0
+ replicarellist = None
+ replicarel = None
+ snapshot_vol_instance = None
+ msg = None
+ errordesc = None
+ cpsession_instance = None
+ # main processing
+ vol_instance = self._find_lun(volumename)
+ if vol_instance is not None:
+ # find target_volume
+
+ # get copysession list
+ repservice = self._find_eternus_service(REPL)
+ if repservice is None:
+ msg = (_('_find_copysession,'
+ 'Cannot find Replication Service to '
+ 'find copysession'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+
+ # find copysession for source_volume
+ while True:
+ LOG.debug(_('*****_find_copysession,source_volume while copysession'))
+ cpsession = None
+
+ rc, errordesc, replicarellist = self._exec_eternus_service(
+ 'GetReplicationRelationships',
+ repservice,
+ Type=pywbem.Uint16(2),
+ Mode=pywbem.Uint16(2),
+ Locality=pywbem.Uint16(2))
+
+ if rc != 0L and rc != 4096L:
+ 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)
+ # end of if
+
+ 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:
+ 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': str(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:
+ 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)
+ # end of if
+ time.sleep(10)
+ break
+ # end of if
+ else:
+ LOG.debug(_('*****_find_copysession,'
+ 'volumename:%(volumename)s,'
+ 'Storage Synchronized not found.')
+ % {'volumename': volumename})
+ # end of for replicarellist
+ if cpsession is None:
+ break
+ # end of while
+
+ # 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:
+ 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': str(cpsession)})
+ break
+ # end of if
+
+ else:
+ LOG.debug(_('*****_find_copysession,'
+ 'volumename:%(volumename)s,'
+ 'Storage Synchronized not found.')
+ % {'volumename': volumename})
+ # end of for replicarellist
+
+ else:
+ # does not find target_volume of copysession
+ msg = (_('_find_copysession,'
+ 'volumename:%(volumename)s,'
+ 'not found.')
+ % {'volumename':volumename})
+ LOG.info(msg)
+ # end of if
+
+ LOG.debug(_('*****_find_copysession,Exit method'))
+
+ return cpsession
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _delete_copysession #
+ # summary : delete copysession #
+ # parameters : copysession #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _delete_copysession(self,cpsession):
+ '''
+ delete copysession
+ '''
+ # cpsession : copysession
+ # snapshot_instance : copysession instance
+ # operation : 8 stop OPC and EC
+ # : 19 stop SnapOPC
+ # repjservice : FUJITSU_ReplicationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****_delete_copysession,Entering'))
+ LOG.debug(_('*****_delete_copysession,[%s]') % cpsession)
+
+ # initialize
+ operation = 0
+ snapshot_instance = None
+ repservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+
+ # get copysession type
+ # 4:SnapOPC, 5:OPC
+ try:
+ snapshot_instance = self.conn.GetInstance(
+ cpsession,
+ LocalOnly=False)
+ except:
+ 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
+ # 19:SnapOPC. 8:OPC
+ operation = OPERATION_dic[copytype]
+
+ repservice = self._find_eternus_service(REPL)
+ if repservice is None:
+ msg = (_('_delete_copysession,'
+ 'Cannot find Replication Service to '
+ 'delete copysession'))
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+
+ # Invoke method for delete copysession
+ rc, errordesc, job = self._exec_eternus_service(
+ 'ModifyReplicaSynchronization',
+ repservice,
+ Operation=pywbem.Uint16(operation),
+ Synchronization=cpsession,
+ Force=True,
+ WaitForCopyState=pywbem.Uint16(15))
+
+ 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 and rc != 4096L:
+ 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)
+ # end of if
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _get_target_portid #
+ # summary : return target_portid #
+ # parameters : connector #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _get_target_portid(self, connector):
+ '''
+ return target_portid
+ '''
+ # target_portidlist : target_portid list
+ # tgtportlist : target port list
+ # tgtport : target port
+
+ LOG.debug(_('*****_get_target_portid,Enter method'))
+
+ # initialize
+ target_portidlist = []
+ tgtportlist = []
+ tgtport = None
+
+ # main processing
+ if self.protocol == 'fc':
+ # Protocol id FibreChannel
+ try:
+ tgtportlist = self.conn.EnumerateInstances(
+ 'FUJITSU_SCSIProtocolEndpoint')
+ except:
+ 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'] == 2:
+ target_portidlist.append(tgtport['Name'])
+
+ LOG.debug(_('*****_get_target_portid,'
+ 'wwn:%(wwn)s,'
+ 'connection type:%(cont)s,'
+ 'ramode:%(ramode)s')
+ % {'wwn': tgtport['Name'],
+ 'cont': tgtport['ConnectionType'],
+ 'ramode': tgtport['RAMode']})
+ # end of for tgtportlist
+
+ LOG.debug(_('*****_get_target_portid,'
+ 'target wwns: %(target_portid)s ')
+ % {'target_portid': target_portidlist})
+
+ elif self.protocol == 'iSCSI':
+ # Protocol is iSCSI
+ try:
+ tgtportlist = self.conn.EnumerateInstances(
+ 'FUJITSU_iSCSIProtocolEndpoint')
+ except:
+ 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'] == 7:
+ target_portidlist.append(tgtport['Name'])
+ LOG.debug(_('*****_get_target_portid,'
+ 'iSCSIname:%(iscsiname)s,'
+ 'connection type:%(cont)s,'
+ 'ramode: %(ramode)s')
+ % {'iscsiname': tgtport['Name'],
+ 'cont': tgtport['ConnectionType'],
+ 'ramode': tgtport['RAMode']})
+ # end of for tgtportlist
+
+ LOG.debug(_('*****_get_target_portid,'
+ 'target iSCSIname: %(target_portid)s ')
+ % {'target_portid': target_portidlist})
+ # end of if
+
+ 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)
+ # end of if
+
+ LOG.debug(_('*****_get_target_portid,Exit method'))
+
+ return target_portidlist
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _map_lun #
+ # summary : map volume to host #
+ # parameters : volume, connector, targetlist #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _map_lun(self, volume, connector, targetlist = []):
+ '''
+ map volume to host.
+ '''
+ # vol_instance : volume instance
+ # volumename : volume name on ETERNUS
+ # volume_uid : volume UID
+ # ex)600000E00D110000001104EC00DB0000
+ # initiatorlist: inisiator id
+ # ex)[u'10000000c978c574', u'10000000c978c575']
+ # targetlist : ETERNUS target id
+ # ex)[u'500000E0D444EC80', u'500000E0D444EC81']
+ # aglist : assigned AffinityGroup list
+ # ag : AffinityGroup
+ # configservice: FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****_map_lun,'
+ 'volume:%(volume)s,'
+ 'connector:%(con)s,'
+ 'Enter method')
+ % {'volume': volume['display_name'],
+ 'con': connector})
+
+ # initialize
+ vol_instance = None
+ volumename = None
+ volume_uid = None
+ initiatorlist = []
+ target = None
+ aglist = []
+ ag = None
+ configservice = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ volumename = self._create_volume_name(volume['id'])
+ vol_instance = self._find_lun(volumename)
+ volume_uid = vol_instance['Name']
+ initiatorlist = self._find_initiator_names(connector)
+ aglist = self._find_affinity_group(connector)
+ configservice = self._find_eternus_service(CTRL_CONF)
+
+ if len(targetlist) == 0:
+ targetlist = self._get_target_portid(connector)
+ # end of if
+
+ if configservice is None:
+ msg = (_('_map_lun,'
+ 'vol_instance.path:%(vol)s,'
+ 'volumename:%(volumename)s,'
+ 'volume_uid:%(uid)s,'
+ 'initiator:%(initiator)s,'
+ 'target:%(tgt)s',
+ 'aglist:%(aglist)s',
+ 'Cannot find Controller Configuration')
+ % {'vol': str(vol_instance.path),
+ 'volumename': [volumename],
+ 'uid': [volume_uid],
+ 'initiator': initiatorlist,
+ 'tgt': targetlist,
+ 'aglist': aglist})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ LOG.debug(_('*****_map_lun,'
+ 'vol_instance.path:%(vol)s,'
+ 'volumename:%(volumename)s,'
+ 'initiator:%(initiator)s,'
+ 'target:%(tgt)s')
+ % {'vol': str(vol_instance.path),
+ 'volumename': [volumename],
+ 'initiator': initiatorlist,
+ 'tgt': targetlist})
+
+ if len(aglist) == 0:
+ # create new affinity group
+ for target in targetlist:
+ LOG.debug(_('*****_map_lun,'
+ 'lun_name:%(volume_uid)s,'
+ 'Initiator:%(initiator)s,'
+ 'target:%(tgt)s')
+ % {'volume_uid': [volume_uid],
+ 'initiator': initiatorlist,
+ 'tgt': target})
+
+ rc, errordesc, job = self._exec_eternus_service(
+ 'ExposePaths',
+ configservice,
+ LUNames=[volume_uid],
+ InitiatorPortIDs=initiatorlist,
+ TargetPortIDs=[target],
+ DeviceAccesses=[pywbem.Uint16(2)])
+
+ LOG.debug(_('*****_map_lun,'
+ 'Error:%(errordesc)s,'
+ 'Return code:%(rc)lu,'
+ 'Create new affinitygroup')
+ % {'errordesc':errordesc,
+ 'rc':rc})
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('_map_lun,'
+ 'lun_name:%(volume_uid)s,'
+ 'Initiator:%(initiator)s,'
+ 'target:%(tgt)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volume_uid': [volume_uid],
+ 'initiator': initiatorlist,
+ 'tgt': target,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.warn(msg)
+ # end of if
+ # end of for targetlist
+ else:
+ # add lun to affinity group
+ for ag in aglist:
+ LOG.debug(_('*****_map_lun,'
+ 'ag:%(ag)s,'
+ 'lun_name:%(volume_uid)s')
+ % {'ag': str(ag),
+ 'volume_uid':volume_uid})
+
+ rc, errordesc, job = self._exec_eternus_service(
+ 'ExposePaths',
+ configservice, LUNames=[volume_uid],
+ DeviceAccesses=[pywbem.Uint16(2)],
+ ProtocolControllers=[ag])
+
+ LOG.debug(_('*****_map_lun,'
+ 'Error:%(errordesc)s,'
+ 'Return code:%(rc)lu,'
+ 'Add lun affinitygroup')
+ % {'errordesc':errordesc,
+ 'rc':rc})
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('_map_lun,'
+ 'lun_name:%(volume_uid)s,'
+ 'Initiator:%(initiator)s,'
+ 'target:%(tgt)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volume_uid': [volume_uid],
+ 'initiator': initiatorlist,
+ 'tgt': target,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.warn(msg)
+ # end of if
+ # end of for aglist
+ # end of if
+ LOG.debug(_('*****_map_lun,'
+ 'volumename:%(volumename)s,'
+ 'Exit method')
+ % {'volumename':volumename})
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_initiator_names #
+ # summary : return initiator names #
+ # parameters : connector #
+ # return-value : initiator name #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_initiator_names(self, connector):
+ '''
+ return initiator names
+ '''
+ # initiatornamelist : initiator name
+ # msg : None
+
+ LOG.debug(_('*****_find_initiator_names,Enter method'))
+
+ # initialize
+ initiatornamelist = []
+ msg = None
+
+ # main processing
+ if self.protocol == 'iSCSI' and connector['initiator'] is not None:
+ initiatornamelist.append(connector['initiator'])
+ elif self.protocol == 'fc' and connector['wwpns'] is not None:
+ initiatornamelist = connector['wwpns']
+ # end of if
+ if len(initiatornamelist) == 0:
+ msg = (_('_find_initiator_names,'
+ 'connector:%(connector)s,'
+ 'not found initiator')
+ % {'connector':connector})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ LOG.debug(_('*****_find_initiator_names,'
+ 'initiator:%(initiator)s.'
+ 'Exit method')
+ % {'initiator': initiatornamelist})
+
+ return initiatornamelist
+
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _find_affinity_group #
+ # summary : return affinity group from connector #
+ # parameters : connector, vol_instance #
+ # return-value : initiator name #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _find_affinity_group(self,connector,vol_instance=None):
+ '''
+ find affinity group from connector
+ '''
+ # affinity_grouplist: affinity group list(return value)
+ # initiatorlist : initiator list
+ # initiator : initiator
+ # aglist : affinity group list(temp)
+ # ag : affinity group
+ # hostaglist : host affinity group information listr
+ # hostag : host affinity group information
+
+ LOG.debug(_('*****_find_affinity_group,'
+ 'Enter method'))
+
+ # initialize
+ affinity_grouplist = []
+ initiatorlist = []
+ initiator = None
+ aglist = []
+ ag = None
+ hostaglist = []
+ hostag = None
+
+ # main processing
+ initiatorlist = self._find_initiator_names(connector)
+
+ if vol_instance is None:
+ try:
+ aglist = self.conn.EnumerateInstanceNames(
+ 'FUJITSU_AffinityGroupController')
+ except:
+ msg=(_('_find_affinity_group,'
+ 'connector:%(connector)s,'
+ 'EnumerateInstanceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'connector':connector})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ LOG.debug(_('*****_find_affinity_group,'
+ 'affinity_groups:%s')
+ % aglist)
+ else:
+ try:
+ aglist = self.conn.AssociatorNames(
+ vol_instance.path,
+ AssocClass ='CIM_ProtocolControllerForUnit',
+ ResultClass='FUJITSU_AffinityGroupController')
+ except:
+ msg=(_('_find_affinity_group,'
+ 'connector:%(connector)s,'
+ 'AssociatorNames,'
+ 'cannot connect to ETERNUS.')
+ % {'connector':connector})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ LOG.debug(_('*****_find_affinity_group,'
+ 'vol_instance.path:%(vol)s,'
+ 'affinity_groups:%(aglist)s')
+ % {'vol':vol_instance.path,
+ 'aglist':aglist})
+ # end of if
+ for ag in aglist:
+ try:
+ hostaglist = self.conn.Associators(
+ ag,
+ AssocClass ='CIM_AuthorizedTarget',
+ ResultClass='FUJITSU_AuthorizedPrivilege')
+ except:
+ msg=(_('_find_affinity_group,'
+ 'connector:%(connector)s,'
+ 'Associators,'
+ 'cannot connect to ETERNUS.')
+ % {'connector':connector})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ for hostag in hostaglist:
+ for initiator in initiatorlist:
+ if initiator.lower() not in hostag['InstanceID'].lower():
+ continue
+ # end of if
+ LOG.debug(_('*****_find_affinity_group,'
+ 'AffinityGroup:%(ag)s')
+ % {'ag':ag})
+ affinity_grouplist.append(ag)
+ break
+ # end of for initiatorlist
+ break
+ # end of for hostaglist
+ # end of for aglist
+ LOG.debug(_('*****_find_affinity_group,'
+ 'initiators:%(initiator)s,'
+ 'affinity_group:%(affinity_group)s.'
+ 'Exit method')
+ % {'initiator': initiatorlist,
+ 'affinity_group': affinity_grouplist})
+
+ return affinity_grouplist
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _unmap_lun #
+ # summary : unmap volume from host #
+ # parameters : volume, connector #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _unmap_lun(self, volume, connector):
+ '''
+ unmap volume from host
+ '''
+
+ # vol_instance : volume instance
+ # volumename : volume name on ETERNUS
+ # volume_uid : volume UID
+ # ex)600000E00D110000001104EC00DB0000
+ # volmap : volume map information
+ # aglist : assigned AffinityGroup list
+ # ag : AffinityGroup
+ # configservice: FUJITSU_StorageConfigurationService
+ # msg : message
+ # rc : result of invoke method
+ # errordesc : error message
+ # job : unused
+
+ LOG.debug(_('*****_unmap_lun,Enter method'))
+
+ # initialize
+ vol_instance = None
+ volumename = None
+ volume_uid = None
+ volmap = {}
+ device_number = None
+ configservice = None
+ msg = None
+ aglist = None
+ ag = None
+ msg = None
+ rc = 0
+ errordesc = None
+ job = None
+
+ # main processing
+ volumename = self._create_volume_name(volume['id'])
+ vol_instance = self._find_lun(volumename)
+ if vol_instance is None:
+ LOG.info(_('_unmap_lun,'
+ 'volumename:%(volumename)s,'
+ 'volume not found.'
+ 'Exit method')
+ % {'volumename':volumename})
+ return
+ # end of if
+ volume_uid = vol_instance['Name']
+ volmap = self._find_device_number(volume, connector)
+ configservice = self._find_eternus_service(CTRL_CONF)
+ aglist = self._find_affinity_group(connector,vol_instance)
+
+ device_number = volmap['target_lun']
+ if device_number is None:
+ LOG.info(_('_unmap_lun,'
+ 'volumename:%(volumename)s,'
+ 'volume is not mapped.'
+ 'Exit method')
+ % {'volumename':volumename})
+ return
+ # end of if
+ if configservice is None:
+ msg = (_('_unmap_lun,'
+ 'vol_instance.path:%(vol)s,'
+ 'volumename:%(volumename)s,'
+ 'volume_uid:%(uid)s,'
+ 'aglist:%(aglist)s',
+ 'Cannot find Controller Configuration')
+ % {'vol': str(vol_instance.path),
+ 'volumename': [volumename],
+ 'uid': [volume_uid],
+ 'aglist': aglist})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ for ag in aglist:
+ LOG.debug(_('*****_unmap_lun,'
+ 'volumename:%(volumename)s,'
+ 'volume_uid:%(volume_uid)s,'
+ 'AffinityGroup:%(ag)s')
+ % {'volumename': volumename,
+ 'volume_uid': volume_uid,
+ 'ag': ag})
+
+ rc, errordesc, job = self._exec_eternus_service(
+ 'HidePaths',
+ configservice,
+ LUNames=[volume_uid],
+ ProtocolControllers=[ag])
+
+ LOG.debug(_('*****_unmap_lun,'
+ 'Error:%(errordesc)s,'
+ 'Return code:%(rc)lu')
+ % {'errordesc':errordesc,
+ 'rc':rc})
+
+ if rc != 0L and rc != 4096L:
+ msg = (_('_unmap_lun,'
+ 'volumename:%(volumename)s,'
+ 'volume_uid:%(volume_uid)s,'
+ 'AffinityGroup:%(ag)s,'
+ 'Return code:%(rc)lu,'
+ 'Error:%(errordesc)s')
+ % {'volumename': volumename,
+ 'volume_uid': volume_uid,
+ 'ag': ag,
+ 'rc': rc,
+ 'errordesc':errordesc})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of if
+ # end of for aglist
+ LOG.debug(_('*****_unmap_lun,'
+ 'volumename:%(volumename)s,'
+ 'Exit method')
+ % {'volumename':volumename})
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : _get_iqn #
+ # summary : get target iqn #
+ # parameters : iscsi ip address #
+ # return-value : iqn #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def _get_iqn(self):
+ '''
+ get target port iqn
+ '''
+ # iscsiip : target iscsi ip address
+ # ip_endpointlist : ip protocol endpoint list
+ # ip_endpoint : ip protocol endpoint
+ # tcp_endpointlist : tcp protocol endpoint list
+ # tcp_endpoint : tcp protocol endpoint
+ # iscsi_endpointlist : iscsi protocol endpoint list
+ # iscsi_endpoint : iscsi protocol endpoint
+ # ip_endpoint_instance : ip protocol endpoint instance
+
+ LOG.debug(_('*****_get_iqn,Enter method'))
+
+ # initialize
+ iscsiip = self.configuration.iscsi_ip_address
+ ip_endpointlist = []
+ ip_endpoint = None
+ tcp_endpointlist = []
+ tcp_endpoint = None
+ iscsi_endpointlist = []
+ iscsi_endpoint = None
+ ip_endpoint_instance = None
+
+ if iscsiip is None:
+ iscsiip = self._get_drvcfg('EternusISCSIIP')
+ # end of if
+ try:
+ ip_endpointlist = self.conn.EnumerateInstanceNames(
+ 'FUJITSU_IPProtocolEndpoint')
+ except:
+ msg=(_('_get_iqn,'
+ 'iscsiip:%(iscsiip)s,'
+ 'EnumerateInstanceNames,'
+ 'cannot connect to ETERNUS.')
+ % {'iscsiip':iscsiip})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ for ip_endpoint in ip_endpointlist:
+ try:
+ ip_endpoint_instance = self.conn.GetInstance(
+ ip_endpoint)
+ LOG.debug(_('*****_get_iqn,'
+ 'ip_endpoint_instance[IPv4Address]:%(ip_endpoint_instance)s,'
+ 'iscsiip:%(iscsiip)s')
+ % {'ip_endpoint_instance':ip_endpoint_instance['IPv4Address'],
+ 'iscsiip':iscsiip})
+ except:
+ msg=(_('_get_iqn,'
+ 'iscsiip:%(iscsiip)s,'
+ 'GetInstance,'
+ 'cannot connect to ETERNUS.')
+ % {'iscsiip':iscsiip})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ if ip_endpoint_instance['IPv4Address'] != iscsiip:
+ continue
+ else:
+ LOG.debug(_('*****_get_iqn,find iscsiip'))
+ try:
+ tcp_endpointlist = self.conn.AssociatorNames(
+ ip_endpoint,
+ ResultClass='FUJITSU_TCPProtocolEndpoint')
+ except:
+ msg=(_('_get_iqn,'
+ 'iscsiip:%(iscsiip)s,'
+ 'AssociatorNames,'
+ 'cannot connect to ETERNUS.')
+ % {'iscsiip':iscsiip})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ for tcp_endpoint in tcp_endpointlist:
+ try:
+ iscsi_endpointlist = self.conn.Associators(
+ tcp_endpoint,
+ ResultClass='FUJITSU_iSCSIProtocolEndpoint')
+ except:
+ msg=(_('_get_iqn,'
+ 'iscsiip:%(iscsiip)s,'
+ 'AssociatorNames,'
+ 'cannot connect to ETERNUS.')
+ % {'iscsiip':iscsiip})
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+
+ for iscsi_endpoint in iscsi_endpointlist:
+ iqn = iscsi_endpoint['Name'].split(',')[0]
+ LOG.debug(_('*****_get_iqn,'
+ 'iscsi_endpoint[Name]:%(iscsi_endpoint)s')
+ % {'iscsi_endpoint':iscsi_endpoint['Name']})
+ break
+ # end of for iscsi_endpointlist
+ break
+ # end of for tcp_endpointlist
+ # end of if
+ break
+ # end of for ip_endpoint
+ else:
+ msg = (_('_get_iqn,'
+ 'iscsiip:%(iscsiip)s,'
+ 'not found iqn')
+ % {'iscsiip':iscsiip})
+
+ LOG.error(msg)
+ raise exception.VolumeBackendAPIException(data=msg)
+ # end of for ip_endpointlist
+ LOG.debug(_('*****_get_iqn,%s,Exit method') % iqn )
+ return iqn
+
--- cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_fc.py
+++ cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_fc.py
@@ -0,0 +1,430 @@
+# Copyright (c) 2014 FUJITSU LIMITED
+# Copyright (c) 2012 EMC Corporation.
+# Copyright (c) 2012 OpenStack Foundation
+# 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.
+#
+
+'''
+FibreChannel Cinder Volume driver for Fujitsu ETERNUS DX S2 and S3 series.
+'''
+
+##------------------------------------------------------------------------------------------------##
+## ##
+## ETERNUS OpenStack Volume Driver ##
+## ##
+## Note : ##
+## File Name : fujitsu_eternus_dx_fc.py ##
+## Copyright 2014 FUJITSU LIMITED ##
+## ##
+## history : ##
+## 2014.03 : 1.0.0 : volume(create,delete,attach,detach,create from snapshot) ##
+## snapshot(create,delete) ##
+## 2014.04 : 1.0.1 : Fix comment ##
+## 2014.06 : 1.1.0 : Support 4 features ##
+## Extend volume ##
+## Clone Volume ##
+## Copy Image to Volume ##
+## Copy Volume to Image ##
+## 2014.11 : 1.1.1 : Support ETERNUS DX V10L30 Firmware ##
+##------------------------------------------------------------------------------------------------##
+
+from oslo.config import cfg
+from cinder.openstack.common import log as logging
+from cinder import exception
+from cinder.volume import driver
+from cinder.openstack.common import lockutils
+from cinder.volume.drivers.fujitsu import fujitsu_eternus_dx_common
+import time
+
+LOG = logging.getLogger(__name__)
+
+#--------------------------------------------------------------------------------------------------#
+# Class : FJDXFCDriver #
+# summary : fibrechannel cinder volume driver for Fujitsu ETERNUS DX #
+#--------------------------------------------------------------------------------------------------#
+class FJDXFCDriver(driver.FibreChannelDriver):
+ '''
+ ETERNUS Cinder Volume Driver version1.0
+ for Fujitsu ETERNUS DX S2 and S3 series
+ '''
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : __init__ #
+ # summary : #
+ # parameters : #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def __init__(self, *args, **kwargs):
+ '''
+ Constructor
+ '''
+ super(FJDXFCDriver, self).__init__(*args, **kwargs)
+ self.common = fujitsu_eternus_dx_common.FJDXCommon(
+ 'fc',
+ configuration=self.configuration)
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : check_for_setup_error #
+ # summary : #
+ # parameters : #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def check_for_setup_error(self):
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume #
+ # summary : create volume on ETERNUS #
+ # parameters : volume #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_volume(self, volume):
+ '''
+ Create volume
+ '''
+ LOG.debug(_('*****create_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_volume(volume)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume_from_snapshot #
+ # summary : create volume from snapshot #
+ # parameters : volume, snapshot #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_volume_from_snapshot(self, volume, snapshot):
+ '''
+ Creates a volume from a snapshot.
+ '''
+ LOG.debug(_('*****creaet_volume_from_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_volume_from_snapshot(volume, snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_volume_from_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_cloned_volume #
+ # summary : create cloned volume on ETERNUS #
+ # parameters : volume, src_vref #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_cloned_volume(self, volume, src_vref):
+ """Create cloned volume."""
+ LOG.debug(_('*****create_cloned_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_cloned_volume(volume, src_vref)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_cloned_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_volume #
+ # summary : delete volume on ETERNUS #
+ # parameters : volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def delete_volume(self, volume):
+ '''
+ Delete volume on ETERNUS.
+ '''
+ LOG.debug(_('*****delete_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.delete_volume(volume)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****delete_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_snapshot #
+ # summary : create snapshot using SnapOPC #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_snapshot(self, snapshot):
+ '''
+ Creates a snapshot.
+ '''
+ LOG.debug(_('*****create_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.create_snapshot(snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_snapshot #
+ # summary : delete snapshot #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def delete_snapshot(self, snapshot):
+ '''
+ Deletes a snapshot.
+ '''
+ LOG.debug(_('*****delete_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.delete_snapshot(snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****delete_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : ensure_export #
+ # summary : Driver entry point to get the export info for an existing volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def ensure_export(self, context, volume):
+ """Driver entry point to get the export info for an existing volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_export #
+ # summary : Driver entry point to get the export info for a new volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_export(self, context, volume):
+ """Driver entry point to get the export info for a new volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : remove_export #
+ # summary : Driver entry point to remove an export for a volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def remove_export(self, context, volume):
+ """Driver entry point to remove an export for a volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : initialize_connection #
+ # summary : set HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : connection info #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def initialize_connection(self, volume, connector):
+ '''
+ Allow connection to connector and return connection info.
+ '''
+ LOG.debug(_('*****initialize_connection,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ info = self.common.initialize_connection(volume, connector)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****initialize_connection,'
+ 'processing time:%s sec') % processing_time)
+
+ return info
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : terminate_connection #
+ # summary : remove HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def terminate_connection(self, volume, connector, **kwargs):
+ '''
+ Disallow connection from connector.
+ '''
+ LOG.debug(_('*****terminate_connection,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.terminate_connection(volume, connector)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****terminate_connection,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : get_volume_stats #
+ # summary : get pool capacity #
+ # parameters : refresh #
+ # return-value : self.stats #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def get_volume_stats(self, refresh=False):
+ '''
+ Get volume stats.
+ If 'refresh' is True, run update the stats first.
+ '''
+ LOG.debug(_('*****get_volume_stats,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ if refresh == True:
+ data = self.common.refresh_volume_stats()
+ backend_name = self.configuration.safe_get('volume_backend_name')
+ data['volume_backend_name'] = backend_name or 'FJDXFCDriver'
+ data['storage_protocol'] = 'fibre_channel'
+ self._stats = data
+ # end of if
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****get_volume_stats,'
+ 'processing time:%s sec') % processing_time)
+
+ return self._stats
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : extend_volume #
+ # summary : extend volume on ETERNUS #
+ # parameters : volume, new_size #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def extend_volume(self, volume, new_size):
+ '''
+ Extend volume.
+ '''
+ LOG.debug(_('*****extend_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+
+ enter_time = time.time()
+ self.common.extend_volume(volume, new_size)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****extend_volume,'
+ 'processing time:%s sec') % processing_time)
+ return
--- cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_iscsi.py
+++ cinder/volume/drivers/fujitsu/fujitsu_eternus_dx_iscsi.py
@@ -0,0 +1,440 @@
+# Copyright (c) 2014 FUJITSU LIMITED
+# Copyright (c) 2012 EMC Corporation.
+# Copyright (c) 2012 OpenStack Foundation
+# 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 Cinder Volume driver for Fujitsu ETERNUS DX S2 and S3 series.
+'''
+
+##------------------------------------------------------------------------------------------------##
+## ##
+## ETERNUS OpenStack Volume Driver ##
+## ##
+## Note : ##
+## File Name : fujitsu_eternus_dx_iscsi.py ##
+## Copyright 2014 FUJITSU LIMITED ##
+## ##
+## history : ##
+## 2014.03 : 1.0.0 : volume(create,delete,attach,detach,create from snapshot) ##
+## snapshot(create,delete) ##
+## 2014.04 : 1.0.1 : Fix comment ##
+## 2014.06 : 1.1.0 : Support 4 features ##
+## Extend volume ##
+## Clone Volume ##
+## Copy Image to Volume ##
+## Copy Volume to Image ##
+## 2014.11 : 1.1.1 : Support ETERNUS DX V10L30 Firmware ##
+##------------------------------------------------------------------------------------------------##
+
+from oslo.config import cfg
+from cinder.openstack.common import log as logging
+from cinder import exception
+from cinder.volume import driver
+from cinder.openstack.common import lockutils
+from cinder.volume.drivers.fujitsu import fujitsu_eternus_dx_common
+import time
+
+LOG = logging.getLogger(__name__)
+
+#--------------------------------------------------------------------------------------------------#
+# Class : FJDXISCSIDriver #
+# summary : iSCSI cinder volume driver for Fujitsu ETERNUS DX #
+#--------------------------------------------------------------------------------------------------#
+class FJDXISCSIDriver(driver.ISCSIDriver):
+ '''
+ ETERNUS Cinder Volume Driver version1.0
+ for Fujitsu ETERNUS DX S2 and S3 series
+ '''
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : __init__ #
+ # summary : #
+ # parameters : #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def __init__(self, *args, **kwargs):
+ '''
+ Constructor
+ '''
+ super(FJDXISCSIDriver, self).__init__(*args, **kwargs)
+ self.common = fujitsu_eternus_dx_common.FJDXCommon(
+ 'iSCSI',
+ configuration=self.configuration)
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : check_for_setup_error #
+ # summary : #
+ # parameters : #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def check_for_setup_error(self):
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume #
+ # summary : create volume on ETERNUS #
+ # parameters : volume #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_volume(self, volume):
+ '''
+ Create volume
+ '''
+ LOG.debug(_('*****create_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_volume(volume)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'provider_location': "%s:%s" %
+ (self.configuration.iscsi_ip_address,
+ self.configuration.iscsi_port),
+ 'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_volume_from_snapshot #
+ # summary : create volume from snapshot #
+ # parameters : volume, snapshot #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_volume_from_snapshot(self, volume, snapshot):
+ '''
+ Creates a volume from a snapshot.
+ '''
+ LOG.debug(_('*****creaet_volume_from_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_volume_from_snapshot(volume, snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_volume_from_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'provider_location': "%s:%s" %
+ (self.configuration.iscsi_ip_address,
+ self.configuration.iscsi_port),
+ 'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_cloned_volume #
+ # summary : create cloned volume on ETERNUS #
+ # parameters : volume, src_vref #
+ # return-value : volume metadata #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_cloned_volume(self, volume, src_vref):
+ """Create cloned volume."""
+ LOG.debug(_('*****creaet_cloned_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ metadata = None
+ v_metadata = None
+ data = None
+
+ enter_time = time.time()
+ metadata = self.common.create_cloned_volume(volume, src_vref)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_cloned_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ v_metadata = volume.get('volume_metadata')
+ for data in v_metadata:
+ metadata[data['key']] = data['value']
+
+ return {'provider_location': "%s:%s" %
+ (self.configuration.iscsi_ip_address,
+ self.configuration.iscsi_port),
+ 'metadata': metadata}
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_volume #
+ # summary : delete volume on ETERNUS #
+ # parameters : volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def delete_volume(self, volume):
+ '''
+ Delete volume on ETERNUS.
+ '''
+ LOG.debug(_('*****delete_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.delete_volume(volume)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****delete_volume,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_snapshot #
+ # summary : create snapshot using SnapOPC #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def create_snapshot(self, snapshot):
+ '''
+ Creates a snapshot.
+ '''
+ LOG.debug(_('*****create_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.create_snapshot(snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****create_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : delete_snapshot #
+ # summary : delete snapshot #
+ # parameters : snapshot #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def delete_snapshot(self, snapshot):
+ '''
+ Deletes a snapshot.
+ '''
+ LOG.debug(_('*****delete_snapshot,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.delete_snapshot(snapshot)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****delete_snapshot,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : ensure_export #
+ # summary : Driver entry point to get the export info for an existing volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def ensure_export(self, context, volume):
+ """Driver entry point to get the export info for an existing volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : create_export #
+ # summary : Driver entry point to get the export info for a new volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def create_export(self, context, volume):
+ """Driver entry point to get the export info for a new volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : remove_export #
+ # summary : Driver entry point to remove an export for a volume. #
+ # parameters : context, volume #
+ # return-value : none #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ def remove_export(self, context, volume):
+ """Driver entry point to remove an export for a volume."""
+ pass
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : initialize_connection #
+ # summary : set HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : connection info #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def initialize_connection(self, volume, connector):
+ '''
+ Allow connection to connector and return connection info.
+ '''
+ LOG.debug(_('*****initialize_connection,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ info=self.common.initialize_connection(volume, connector)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****initialize_connection,'
+ 'processing time:%s sec') % processing_time)
+
+ return info
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : terminate_connection #
+ # summary : remove HostAffinityGroup on ETERNUS #
+ # parameters : volume, connector #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def terminate_connection(self, volume, connector, **kwargs):
+ '''
+ Disallow connection from connector.
+ '''
+ LOG.debug(_('*****terminate_connection,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ self.common.terminate_connection(volume, connector)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****terminate_connection,'
+ 'processing time:%s sec') % processing_time)
+
+ return
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : get_volume_stats #
+ # summary : get pool capacity #
+ # parameters : refresh #
+ # return-value : self.stats #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def get_volume_stats(self, refresh=False):
+ '''
+ Get volume stats.
+ If 'refresh' is True, run update the stats first.
+ '''
+ LOG.debug(_('*****get_volume_stats,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+ enter_time = time.time()
+
+ if refresh == True:
+ data = self.common.refresh_volume_stats()
+ backend_name = self.configuration.safe_get('volume_backend_name')
+ data['volume_backend_name'] = backend_name or 'FJDXISCSIDriver'
+ data['storage_protocol'] = 'iSCSI'
+ self._stats = data
+ # end of if
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****get_volume_stats,'
+ 'processing time:%s sec') % processing_time)
+
+ return self._stats
+
+ #----------------------------------------------------------------------------------------------#
+ # Method : extend_volume #
+ # summary : extend volume on ETERNUS #
+ # parameters : volume, new_size #
+ # return-value : #
+ # exceptions : #
+ #----------------------------------------------------------------------------------------------#
+ @lockutils.synchronized('ETERNUS_DX-vol', 'cinder-', True)
+ def extend_volume(self, volume, new_size):
+ '''
+ Extend volume.
+ '''
+ LOG.debug(_('*****extend_volume,Enter method'))
+ processing_time = 0
+ enter_time = 0
+ exit_time = 0
+
+ enter_time = time.time()
+ self.common.extend_volume(volume, new_size)
+
+ exit_time = time.time()
+ processing_time = exit_time-enter_time
+ processing_time = str(processing_time)
+ LOG.debug(_('*****extend_volume,'
+ 'processing time:%s sec') % processing_time)
+ return
+
--- cinder/volume/drivers/fujitsu/__init__.py
+++ cinder/volume/drivers/fujitsu/__init__.py
@@ -0,0 +1,14 @@
+# Copyright 2012 OpenStack Foundation
+#
+# 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.
+