**** CubicPower OpenStack Study ****
# Copyright (c) 2012 - 2014 EMC Corporation.
# All Rights Reserved.
#
#    Licensed under the Apache License, Version 2.0 (the "License"); you may
#    not use this file except in compliance with the License. You may obtain
#    a copy of the License at
#
#         http://www.apache.org/licenses/LICENSE-2.0
#
#    Unless required by applicable law or agreed to in writing, software
#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
#    License for the specific language governing permissions and limitations
#    under the License.
"""
Common class for SMI-S based EMC volume drivers.
This common class is for EMC volume drivers based on SMI-S.
It supports VNX and VMAX arrays.
"""
import time
from oslo.config import cfg
from xml.dom.minidom import parseString
from cinder import exception
from cinder.openstack.common import log as logging
from cinder import units
from cinder.volume import volume_types
LOG = logging.getLogger(__name__)
CONF = cfg.CONF
try:
    import pywbem
except ImportError:
    LOG.info(_('Module PyWBEM not installed.  '
               'Install PyWBEM using the python-pywbem package.'))
CINDER_EMC_CONFIG_FILE = '/etc/cinder/cinder_emc_config.xml'
EMC_ROOT = 'root/emc'
PROVISIONING = 'storagetype:provisioning'
POOL = 'storagetype:pool'
emc_opts = [
    cfg.StrOpt('cinder_emc_config_file',
               default=CINDER_EMC_CONFIG_FILE,
               help='use this file for cinder emc plugin '
                    'config data'), ]
CONF.register_opts(emc_opts)
**** CubicPower OpenStack Study ****
class EMCSMISCommon():
    """Common code that can be used by ISCSI and FC drivers."""
    stats = {'driver_version': '1.0',
             'free_capacity_gb': 0,
             'reserved_percentage': 0,
             'storage_protocol': None,
             'total_capacity_gb': 0,
             'vendor_name': 'EMC',
             'volume_backend_name': None}
    
**** CubicPower OpenStack Study ****
    def __init__(self, prtcl, configuration=None):
        self.protocol = prtcl
        self.configuration = configuration
        self.configuration.append_config_values(emc_opts)
        ip, port = self._get_ecom_server()
        self.user, self.passwd = self._get_ecom_cred()
        self.url = 'http://' + ip + ':' + port
        self.conn = self._get_ecom_connection()
**** CubicPower OpenStack Study ****
    def create_volume(self, volume):
        """Creates a EMC(VMAX/VNX) volume."""
        LOG.debug(_('Entering create_volume.'))
        volumesize = int(volume['size']) * units.GiB
        volumename = volume['name']
        LOG.info(_('Create Volume: %(volume)s  Size: %(size)lu')
                 % {'volume': volumename,
                    'size': volumesize})
        self.conn = self._get_ecom_connection()
        storage_type = self._get_storage_type(volume)
        LOG.debug(_('Create Volume: %(volume)s  '
                  'Storage type: %(storage_type)s')
                  % {'volume': volumename,
                     'storage_type': storage_type})
        pool, storage_system = self._find_pool(storage_type[POOL])
        LOG.debug(_('Create Volume: %(volume)s  Pool: %(pool)s  '
                  'Storage System: %(storage_system)s')
                  % {'volume': volumename,
                     'pool': pool,
                     'storage_system': storage_system})
        configservice = self._find_storage_configuration_service(
            storage_system)
        if configservice is None:
            exception_message = (_("Error Create Volume: %(volumename)s. "
                                 "Storage Configuration Service not found for "
                                 "pool %(storage_type)s.")
                                 % {'volumename': volumename,
                                    'storage_type': storage_type})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        provisioning = self._get_provisioning(storage_type)
        LOG.debug(_('Create Volume: %(name)s  Method: '
                  'CreateOrModifyElementFromStoragePool  ConfigServicie: '
                  '%(service)s  ElementName: %(name)s  InPool: %(pool)s  '
                  'ElementType: %(provisioning)s  Size: %(size)lu')
                  % {'service': configservice,
                     'name': volumename,
                     'pool': pool,
                     'provisioning': provisioning,
                     'size': volumesize})
        rc, job = self.conn.InvokeMethod(
            'CreateOrModifyElementFromStoragePool',
            configservice, ElementName=volumename, InPool=pool,
            ElementType=self._getnum(provisioning, '16'),
            Size=self._getnum(volumesize, '64'))
        LOG.debug(_('Create Volume: %(volumename)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                LOG.error(_('Error Create Volume: %(volumename)s.  '
                          'Return code: %(rc)lu.  Error: %(error)s')
                          % {'volumename': volumename,
                             'rc': rc,
                             'error': errordesc})
                raise exception.VolumeBackendAPIException(data=errordesc)
        # Find the newly created volume
        associators = self.conn.Associators(
            job['Job'],
            resultClass='EMC_StorageVolume')
        volpath = associators[0].path
        name = {}
        name['classname'] = volpath.classname
        keys = {}
        keys['CreationClassName'] = volpath['CreationClassName']
        keys['SystemName'] = volpath['SystemName']
        keys['DeviceID'] = volpath['DeviceID']
        keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
        name['keybindings'] = keys
        LOG.debug(_('Leaving create_volume: %(volumename)s  '
                  'Return code: %(rc)lu '
                  'volume instance: %(name)s')
                  % {'volumename': volumename,
                     'rc': rc,
                     'name': name})
        return name
**** CubicPower OpenStack Study ****
    def create_volume_from_snapshot(self, volume, snapshot):
        """Creates a volume from a snapshot."""
        LOG.debug(_('Entering create_volume_from_snapshot.'))
        snapshotname = snapshot['name']
        volumename = volume['name']
        LOG.info(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                 'Snapshot: %(snapshotname)s')
                 % {'volumename': volumename,
                    'snapshotname': snapshotname})
        self.conn = self._get_ecom_connection()
        snapshot_instance = self._find_lun(snapshot)
        storage_system = snapshot_instance['SystemName']
        LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s  Snapshot Instance: '
                  '%(snapshotinstance)s  Storage System: %(storage_system)s.')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'snapshotinstance': snapshot_instance.path,
                     'storage_system': storage_system})
        isVMAX = storage_system.find('SYMMETRIX')
        if isVMAX > -1:
            exception_message = (_('Error Create Volume from Snapshot: '
                                 'Volume: %(volumename)s  Snapshot: '
                                 '%(snapshotname)s. Create Volume '
                                 'from Snapshot is NOT supported on VMAX.')
                                 % {'volumename': volumename,
                                    'snapshotname': snapshotname})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        repservice = self._find_replication_service(storage_system)
        if repservice is None:
            exception_message = (_('Error Create Volume from Snapshot: '
                                 'Volume: %(volumename)s  Snapshot: '
                                 '%(snapshotname)s. Cannot find Replication '
                                 'Service to create volume from snapshot.')
                                 % {'volumename': volumename,
                                    'snapshotname': snapshotname})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s  Method: CreateElementReplica  '
                  'ReplicationService: %(service)s  ElementName: '
                  '%(elementname)s  SyncType: 8  SourceElement: '
                  '%(sourceelement)s')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'service': repservice,
                     'elementname': volumename,
                     'sourceelement': snapshot_instance.path})
        # Create a Clone from snapshot
        rc, job = self.conn.InvokeMethod(
            'CreateElementReplica', repservice,
            ElementName=volumename,
            SyncType=self._getnum(8, '16'),
            SourceElement=snapshot_instance.path)
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Create Volume from Snapshot: '
                                     'Volume: %(volumename)s  Snapshot:'
                                     '%(snapshotname)s.  Return code: %(rc)lu.'
                                     'Error: %(error)s')
                                     % {'volumename': volumename,
                                        'snapshotname': snapshotname,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        # Find the newly created volume
        associators = self.conn.Associators(
            job['Job'],
            resultClass='EMC_StorageVolume')
        volpath = associators[0].path
        name = {}
        name['classname'] = volpath.classname
        keys = {}
        keys['CreationClassName'] = volpath['CreationClassName']
        keys['SystemName'] = volpath['SystemName']
        keys['DeviceID'] = volpath['DeviceID']
        keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
        name['keybindings'] = keys
        LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s.  Successfully clone volume '
                  'from snapshot.  Finding the clone relationship.')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname})
        volume['provider_location'] = str(name)
        sync_name, storage_system = self._find_storage_sync_sv_sv(
            volume, snapshot)
        # Remove the Clone relationshop so it can be used as a regular lun
        # 8 - Detach operation
        LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s.  Remove the clone '
                  'relationship. Method: ModifyReplicaSynchronization '
                  'ReplicationService: %(service)s  Operation: 8  '
                  'Synchronization: %(sync_name)s')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'service': repservice,
                     'sync_name': sync_name})
        rc, job = self.conn.InvokeMethod(
            'ModifyReplicaSynchronization',
            repservice,
            Operation=self._getnum(8, '16'),
            Synchronization=sync_name)
        LOG.debug(_('Create Volume from Snapshot: Volume: %(volumename)s  '
                    'Snapshot: %(snapshotname)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Create Volume from Snapshot: '
                                     'Volume: %(volumename)s  '
                                     'Snapshot: %(snapshotname)s.  '
                                     'Return code: %(rc)lu.  Error: %(error)s')
                                     % {'volumename': volumename,
                                        'snapshotname': snapshotname,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        LOG.debug(_('Leaving create_volume_from_snapshot: Volume: '
                  '%(volumename)s Snapshot: %(snapshotname)s  '
                  'Return code: %(rc)lu.')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'rc': rc})
        return name
**** CubicPower OpenStack Study ****
    def create_cloned_volume(self, volume, src_vref):
        """Creates a clone of the specified volume."""
        LOG.debug(_('Entering create_cloned_volume.'))
        srcname = src_vref['name']
        volumename = volume['name']
        LOG.info(_('Create a Clone from Volume: Volume: %(volumename)s  '
                 'Source Volume: %(srcname)s')
                 % {'volumename': volumename,
                    'srcname': srcname})
        self.conn = self._get_ecom_connection()
        src_instance = self._find_lun(src_vref)
        storage_system = src_instance['SystemName']
        LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s  '
                  'Source Volume: %(srcname)s  Source Instance: '
                  '%(src_instance)s  Storage System: %(storage_system)s.')
                  % {'volumename': volumename,
                     'srcname': srcname,
                     'src_instance': src_instance.path,
                     'storage_system': storage_system})
        repservice = self._find_replication_service(storage_system)
        if repservice is None:
            exception_message = (_('Error Create Cloned Volume: '
                                 'Volume: %(volumename)s  Source Volume: '
                                 '%(srcname)s. Cannot find Replication '
                                 'Service to create cloned volume.')
                                 % {'volumename': volumename,
                                    'srcname': srcname})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s  '
                  'Source Volume: %(srcname)s  Method: CreateElementReplica  '
                  'ReplicationService: %(service)s  ElementName: '
                  '%(elementname)s  SyncType: 8  SourceElement: '
                  '%(sourceelement)s')
                  % {'volumename': volumename,
                     'srcname': srcname,
                     'service': repservice,
                     'elementname': volumename,
                     'sourceelement': src_instance.path})
        # Create a Clone from source volume
        rc, job = self.conn.InvokeMethod(
            'CreateElementReplica', repservice,
            ElementName=volumename,
            SyncType=self._getnum(8, '16'),
            SourceElement=src_instance.path)
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Create Cloned Volume: '
                                     'Volume: %(volumename)s  Source Volume:'
                                     '%(srcname)s.  Return code: %(rc)lu.'
                                     'Error: %(error)s')
                                     % {'volumename': volumename,
                                        'srcname': srcname,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        # Find the newly created volume
        associators = self.conn.Associators(
            job['Job'],
            resultClass='EMC_StorageVolume')
        volpath = associators[0].path
        name = {}
        name['classname'] = volpath.classname
        keys = {}
        keys['CreationClassName'] = volpath['CreationClassName']
        keys['SystemName'] = volpath['SystemName']
        keys['DeviceID'] = volpath['DeviceID']
        keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
        name['keybindings'] = keys
        LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s  '
                  'Source Volume: %(srcname)s.  Successfully cloned volume '
                  'from source volume.  Finding the clone relationship.')
                  % {'volumename': volumename,
                     'srcname': srcname})
        volume['provider_location'] = str(name)
        sync_name, storage_system = self._find_storage_sync_sv_sv(
            volume, src_vref)
        # Remove the Clone relationshop so it can be used as a regular lun
        # 8 - Detach operation
        LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s  '
                  'Source Volume: %(srcname)s.  Remove the clone '
                  'relationship. Method: ModifyReplicaSynchronization '
                  'ReplicationService: %(service)s  Operation: 8  '
                  'Synchronization: %(sync_name)s')
                  % {'volumename': volumename,
                     'srcname': srcname,
                     'service': repservice,
                     'sync_name': sync_name})
        rc, job = self.conn.InvokeMethod(
            'ModifyReplicaSynchronization',
            repservice,
            Operation=self._getnum(8, '16'),
            Synchronization=sync_name)
        LOG.debug(_('Create Cloned Volume: Volume: %(volumename)s  '
                  'Source Volume: %(srcname)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'srcname': srcname,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Create Cloned Volume: '
                                     'Volume: %(volumename)s  '
                                     'Source Volume: %(srcname)s.  '
                                     'Return code: %(rc)lu.  Error: %(error)s')
                                     % {'volumename': volumename,
                                        'srcname': srcname,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        LOG.debug(_('Leaving create_cloned_volume: Volume: '
                  '%(volumename)s Source Volume: %(srcname)s  '
                  'Return code: %(rc)lu.')
                  % {'volumename': volumename,
                     'srcname': srcname,
                     'rc': rc})
        return name
**** CubicPower OpenStack Study ****
    def delete_volume(self, volume):
        """Deletes an EMC volume."""
        LOG.debug(_('Entering delete_volume.'))
        volumename = volume['name']
        LOG.info(_('Delete Volume: %(volume)s')
                 % {'volume': volumename})
        self.conn = self._get_ecom_connection()
        vol_instance = self._find_lun(volume)
        if vol_instance is None:
            LOG.error(_('Volume %(name)s not found on the array. '
                      'No volume to delete.')
                      % {'name': volumename})
            return
        storage_system = vol_instance['SystemName']
        configservice =\
            self._find_storage_configuration_service(storage_system)
        if configservice is None:
            exception_message = (_("Error Delete Volume: %(volumename)s. "
                                 "Storage Configuration Service not found.")
                                 % {'volumename': volumename})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        device_id = vol_instance['DeviceID']
        LOG.debug(_('Delete Volume: %(name)s  DeviceID: %(deviceid)s')
                  % {'name': volumename,
                     'deviceid': device_id})
        LOG.debug(_('Delete Volume: %(name)s  Method: EMCReturnToStoragePool '
                  'ConfigServic: %(service)s  TheElement: %(vol_instance)s')
                  % {'service': configservice,
                     'name': volumename,
                     'vol_instance': vol_instance.path})
        rc, job =\
            self.conn.InvokeMethod('EMCReturnToStoragePool',
                                   configservice,
                                   TheElements=[vol_instance.path])
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Delete Volume: %(volumename)s.  '
                                     'Return code: %(rc)lu.  Error: %(error)s')
                                     % {'volumename': volumename,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        LOG.debug(_('Leaving delete_volume: %(volumename)s  Return code: '
                  '%(rc)lu')
                  % {'volumename': volumename,
                     'rc': rc})
**** CubicPower OpenStack Study ****
    def create_snapshot(self, snapshot, volume):
        """Creates a snapshot."""
        LOG.debug(_('Entering create_snapshot.'))
        snapshotname = snapshot['name']
        volumename = snapshot['volume_name']
        LOG.info(_('Create snapshot: %(snapshot)s: volume: %(volume)s')
                 % {'snapshot': snapshotname,
                    'volume': volumename})
        self.conn = self._get_ecom_connection()
        vol_instance = self._find_lun(volume)
        device_id = vol_instance['DeviceID']
        storage_system = vol_instance['SystemName']
        LOG.debug(_('Device ID: %(deviceid)s: Storage System: '
                  '%(storagesystem)s')
                  % {'deviceid': device_id,
                     'storagesystem': storage_system})
        repservice = self._find_replication_service(storage_system)
        if repservice is None:
            LOG.error(_("Cannot find Replication Service to create snapshot "
                      "for volume %s.") % volumename)
            exception_message = (_("Cannot find Replication Service to "
                                 "create snapshot for volume %s.")
                                 % volumename)
            raise exception.VolumeBackendAPIException(data=exception_message)
        LOG.debug(_("Create Snapshot:  Method: CreateElementReplica: "
                  "Target: %(snapshot)s  Source: %(volume)s  Replication "
                  "Service: %(service)s  ElementName: %(elementname)s  Sync "
                  "Type: 7  SourceElement: %(sourceelement)s.")
                  % {'snapshot': snapshotname,
                     'volume': volumename,
                     'service': repservice,
                     'elementname': snapshotname,
                     'sourceelement': vol_instance.path})
        rc, job =\
            self.conn.InvokeMethod('CreateElementReplica', repservice,
                                   ElementName=snapshotname,
                                   SyncType=self._getnum(7, '16'),
                                   SourceElement=vol_instance.path)
        LOG.debug(_('Create Snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Create Snapshot: %(snapshot)s '
                                     'Volume: %(volume)s Error: %(errordesc)s')
                                     % {'snapshot': snapshotname, 'volume':
                                        volumename, 'errordesc': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        # Find the newly created volume
        associators = self.conn.Associators(
            job['Job'],
            resultClass='EMC_StorageVolume')
        volpath = associators[0].path
        name = {}
        name['classname'] = volpath.classname
        keys = {}
        keys['CreationClassName'] = volpath['CreationClassName']
        keys['SystemName'] = volpath['SystemName']
        keys['DeviceID'] = volpath['DeviceID']
        keys['SystemCreationClassName'] = volpath['SystemCreationClassName']
        name['keybindings'] = keys
        LOG.debug(_('Leaving create_snapshot: Snapshot: %(snapshot)s '
                  'Volume: %(volume)s  Return code: %(rc)lu.') %
                  {'snapshot': snapshotname, 'volume': volumename, 'rc': rc})
        return name
**** CubicPower OpenStack Study ****
    def delete_snapshot(self, snapshot, volume):
        """Deletes a snapshot."""
        LOG.debug(_('Entering delete_snapshot.'))
        snapshotname = snapshot['name']
        volumename = snapshot['volume_name']
        LOG.info(_('Delete Snapshot: %(snapshot)s: volume: %(volume)s')
                 % {'snapshot': snapshotname,
                    'volume': volumename})
        self.conn = self._get_ecom_connection()
        LOG.debug(_('Delete Snapshot: %(snapshot)s: volume: %(volume)s. '
                  'Finding StorageSychronization_SV_SV.')
                  % {'snapshot': snapshotname,
                     'volume': volumename})
        sync_name, storage_system =\
            self._find_storage_sync_sv_sv(snapshot, volume, False)
        if sync_name is None:
            LOG.error(_('Snapshot: %(snapshot)s: volume: %(volume)s '
                      'not found on the array. No snapshot to delete.')
                      % {'snapshot': snapshotname,
                         'volume': volumename})
            return
        repservice = self._find_replication_service(storage_system)
        if repservice is None:
            exception_message = (_("Cannot find Replication Service to "
                                 "create snapshot for volume %s.")
                                 % volumename)
            raise exception.VolumeBackendAPIException(data=exception_message)
        # Delete snapshot - deletes both the target element
        # and the snap session
        LOG.debug(_("Delete Snapshot: Target: %(snapshot)s  "
                  "Source: %(volume)s.  Method: "
                  "ModifyReplicaSynchronization:  "
                  "Replication Service: %(service)s  Operation: 19  "
                  "Synchronization: %(sync_name)s.")
                  % {'snapshot': snapshotname,
                     'volume': volumename,
                     'service': repservice,
                     'sync_name': sync_name})
        rc, job =\
            self.conn.InvokeMethod('ModifyReplicaSynchronization',
                                   repservice,
                                   Operation=self._getnum(19, '16'),
                                   Synchronization=sync_name)
        LOG.debug(_('Delete Snapshot: Volume: %(volumename)s  Snapshot: '
                  '%(snapshotname)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                exception_message = (_('Error Delete Snapshot: Volume: '
                                     '%(volumename)s  Snapshot: '
                                     '%(snapshotname)s. Return code: %(rc)lu.'
                                     ' Error: %(error)s')
                                     % {'volumename': volumename,
                                        'snapshotname': snapshotname,
                                        'rc': rc,
                                        'error': errordesc})
                LOG.error(exception_message)
                raise exception.VolumeBackendAPIException(
                    data=exception_message)
        # It takes a while for the relationship between the snapshot
        # and the source volume gets cleaned up.  Needs to wait until
        # it is cleaned up.  Otherwise, the source volume can't be
        # deleted immediately after the snapshot deletion because it
        # still has snapshot.
        wait_timeout = int(self._get_timeout())
        wait_interval = 10
        start = int(time.time())
        while True:
            try:
                sync_name, storage_system =\
                    self._find_storage_sync_sv_sv(snapshot, volume, False)
                if sync_name is None:
                    LOG.info(_('Snapshot: %(snapshot)s: volume: %(volume)s. '
                             'Snapshot is deleted.')
                             % {'snapshot': snapshotname,
                                'volume': volumename})
                    break
                time.sleep(wait_interval)
                if int(time.time()) - start >= wait_timeout:
                    LOG.warn(_('Snapshot: %(snapshot)s: volume: %(volume)s. '
                               'Snapshot deleted but cleanup timed out.')
                             % {'snapshot': snapshotname,
                                'volume': volumename})
                    break
            except Exception as ex:
                if ex.args[0] == 6:
                    # 6 means object not found, so snapshot is deleted cleanly
                    LOG.info(_('Snapshot: %(snapshot)s: volume: %(volume)s. '
                             'Snapshot is deleted.')
                             % {'snapshot': snapshotname,
                                'volume': volumename})
                else:
                    LOG.warn(_('Snapshot: %(snapshot)s: volume: %(volume)s. '
                               'Snapshot deleted but error during cleanup. '
                               'Error: %(error)s')
                             % {'snapshot': snapshotname,
                                'volume': volumename,
                                'error': str(ex.args)})
                break
        LOG.debug(_('Leaving delete_snapshot: Volume: %(volumename)s  '
                  'Snapshot: %(snapshotname)s  Return code: %(rc)lu.')
                  % {'volumename': volumename,
                     'snapshotname': snapshotname,
                     'rc': rc})
    # Mapping method for VNX
**** CubicPower OpenStack Study ****
    def _expose_paths(self, configservice, vol_instance,
                      connector):
        """This method maps a volume to a host.
        It adds a volume and initiator to a Storage Group
        and therefore maps the volume to the host.
        """
        volumename = vol_instance['ElementName']
        lun_name = vol_instance['DeviceID']
        initiators = self._find_initiator_names(connector)
        storage_system = vol_instance['SystemName']
        lunmask_ctrl = self._find_lunmasking_scsi_protocol_controller(
            storage_system, connector)
        LOG.debug(_('ExposePaths: %(vol)s  ConfigServicie: %(service)s  '
                  'LUNames: %(lun_name)s  InitiatorPortIDs: %(initiator)s  '
                  'DeviceAccesses: 2')
                  % {'vol': vol_instance.path,
                     'service': configservice,
                     'lun_name': lun_name,
                     'initiator': initiators})
        if lunmask_ctrl is None:
            rc, controller =\
                self.conn.InvokeMethod('ExposePaths',
                                       configservice, LUNames=[lun_name],
                                       InitiatorPortIDs=initiators,
                                       DeviceAccesses=[self._getnum(2, '16')])
        else:
            LOG.debug(_('ExposePaths parameter '
                      'LunMaskingSCSIProtocolController: '
                      '%(lunmasking)s')
                      % {'lunmasking': lunmask_ctrl})
            rc, controller =\
                self.conn.InvokeMethod('ExposePaths',
                                       configservice, LUNames=[lun_name],
                                       DeviceAccesses=[self._getnum(2, '16')],
                                       ProtocolControllers=[lunmask_ctrl])
        if rc != 0L:
            msg = (_('Error mapping volume %s.') % volumename)
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)
        LOG.debug(_('ExposePaths for volume %s completed successfully.')
                  % volumename)
    # Unmapping method for VNX
**** CubicPower OpenStack Study ****
    def _hide_paths(self, configservice, vol_instance,
                    connector):
        """This method unmaps a volume from the host.
        Removes a volume from the Storage Group
        and therefore unmaps the volume from the host.
        """
        volumename = vol_instance['ElementName']
        device_id = vol_instance['DeviceID']
        lunmask_ctrl = self._find_lunmasking_scsi_protocol_controller_for_vol(
            vol_instance, connector)
        LOG.debug(_('HidePaths: %(vol)s  ConfigServicie: %(service)s  '
                  'LUNames: %(device_id)s  LunMaskingSCSIProtocolController: '
                  '%(lunmasking)s')
                  % {'vol': vol_instance.path,
                     'service': configservice,
                     'device_id': device_id,
                     'lunmasking': lunmask_ctrl})
        rc, controller = self.conn.InvokeMethod(
            'HidePaths', configservice,
            LUNames=[device_id], ProtocolControllers=[lunmask_ctrl])
        if rc != 0L:
            msg = (_('Error unmapping volume %s.') % volumename)
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)
        LOG.debug(_('HidePaths for volume %s completed successfully.')
                  % volumename)
    # Mapping method for VMAX
**** CubicPower OpenStack Study ****
    def _add_members(self, configservice, vol_instance):
        """This method maps a volume to a host.
        Add volume to the Device Masking Group that belongs to
        a Masking View.
        """
        volumename = vol_instance['ElementName']
        masking_group = self._find_device_masking_group()
        LOG.debug(_('AddMembers: ConfigServicie: %(service)s  MaskingGroup: '
                  '%(masking_group)s  Members: %(vol)s')
                  % {'service': configservice,
                     'masking_group': masking_group,
                     'vol': vol_instance.path})
        rc, job =\
            self.conn.InvokeMethod('AddMembers',
                                   configservice,
                                   MaskingGroup=masking_group,
                                   Members=[vol_instance.path])
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                msg = (_('Error mapping volume %(vol)s. %(error)s') %
                       {'vol': volumename, 'error': errordesc})
                LOG.error(msg)
                raise exception.VolumeBackendAPIException(data=msg)
        LOG.debug(_('AddMembers for volume %s completed successfully.')
                  % volumename)
    # Unmapping method for VMAX
**** CubicPower OpenStack Study ****
    def _remove_members(self, configservice, vol_instance):
        """This method unmaps a volume from a host.
        Removes volume from the Device Masking Group that belongs to
        a Masking View.
        """
        volumename = vol_instance['ElementName']
        masking_group = self._find_device_masking_group()
        LOG.debug(_('RemoveMembers: ConfigServicie: %(service)s  '
                  'MaskingGroup: %(masking_group)s  Members: %(vol)s')
                  % {'service': configservice,
                     'masking_group': masking_group,
                     'vol': vol_instance.path})
        rc, job = self.conn.InvokeMethod('RemoveMembers', configservice,
                                         MaskingGroup=masking_group,
                                         Members=[vol_instance.path])
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                msg = (_('Error unmapping volume %(vol)s. %(error)s')
                       % {'vol': volumename, 'error': errordesc})
                LOG.error(msg)
                raise exception.VolumeBackendAPIException(data=msg)
        LOG.debug(_('RemoveMembers for volume %s completed successfully.')
                  % volumename)
**** CubicPower OpenStack Study ****
    def _map_lun(self, volume, connector):
        """Maps a volume to the host."""
        volumename = volume['name']
        LOG.info(_('Map volume: %(volume)s')
                 % {'volume': volumename})
        vol_instance = self._find_lun(volume)
        storage_system = vol_instance['SystemName']
        configservice = self._find_controller_configuration_service(
            storage_system)
        if configservice is None:
            exception_message = (_("Cannot find Controller Configuration "
                                 "Service for storage system %s")
                                 % storage_system)
            raise exception.VolumeBackendAPIException(data=exception_message)
        isVMAX = storage_system.find('SYMMETRIX')
        if isVMAX > -1:
            self._add_members(configservice, vol_instance)
        else:
            self._expose_paths(configservice, vol_instance, connector)
**** CubicPower OpenStack Study ****
    def _unmap_lun(self, volume, connector):
        """Unmaps a volume from the host."""
        volumename = volume['name']
        LOG.info(_('Unmap volume: %(volume)s')
                 % {'volume': volumename})
        device_info = self.find_device_number(volume, connector)
        device_number = device_info['hostlunid']
        if device_number is None:
            LOG.info(_("Volume %s is not mapped. No volume to unmap.")
                     % (volumename))
            return
        vol_instance = self._find_lun(volume)
        storage_system = vol_instance['SystemName']
        configservice = self._find_controller_configuration_service(
            storage_system)
        if configservice is None:
            exception_message = (_("Cannot find Controller Configuration "
                                 "Service for storage system %s")
                                 % storage_system)
            raise exception.VolumeBackendAPIException(data=exception_message)
        isVMAX = storage_system.find('SYMMETRIX')
        if isVMAX > -1:
            self._remove_members(configservice, vol_instance)
        else:
            self._hide_paths(configservice, vol_instance, connector)
**** CubicPower OpenStack Study ****
    def initialize_connection(self, volume, connector):
        """Initializes the connection and returns connection info."""
        volumename = volume['name']
        LOG.info(_('Initialize connection: %(volume)s')
                 % {'volume': volumename})
        self.conn = self._get_ecom_connection()
        device_info = self.find_device_number(volume, connector)
        device_number = device_info['hostlunid']
        if device_number is not None:
            LOG.info(_("Volume %s is already mapped.")
                     % (volumename))
        else:
            self._map_lun(volume, connector)
            # Find host lun id again after the volume is exported to the host
            device_info = self.find_device_number(volume, connector)
        return device_info
**** CubicPower OpenStack Study ****
    def terminate_connection(self, volume, connector):
        """Disallow connection from connector."""
        volumename = volume['name']
        LOG.info(_('Terminate connection: %(volume)s')
                 % {'volume': volumename})
        self.conn = self._get_ecom_connection()
        self._unmap_lun(volume, connector)
**** CubicPower OpenStack Study ****
    def extend_volume(self, volume, new_size):
        """Extends an existing  volume."""
        LOG.debug(_('Entering extend_volume.'))
        volumesize = int(new_size) * units.GiB
        volumename = volume['name']
        LOG.info(_('Extend Volume: %(volume)s  New size: %(size)lu')
                 % {'volume': volumename,
                    'size': volumesize})
        self.conn = self._get_ecom_connection()
        storage_type = self._get_storage_type(volume)
        vol_instance = self._find_lun(volume)
        device_id = vol_instance['DeviceID']
        storage_system = vol_instance['SystemName']
        LOG.debug(_('Device ID: %(deviceid)s: Storage System: '
                  '%(storagesystem)s')
                  % {'deviceid': device_id,
                     'storagesystem': storage_system})
        configservice = self._find_storage_configuration_service(
            storage_system)
        if configservice is None:
            exception_message = (_("Error Extend Volume: %(volumename)s. "
                                 "Storage Configuration Service not found.")
                                 % {'volumename': volumename})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        provisioning = self._get_provisioning(storage_type)
        LOG.debug(_('Extend Volume: %(name)s  Method: '
                  'CreateOrModifyElementFromStoragePool  ConfigServicie: '
                  '%(service)s ElementType: %(provisioning)s  Size: %(size)lu'
                  'Volume path: %(volumepath)s')
                  % {'service': configservice,
                     'name': volumename,
                     'provisioning': provisioning,
                     'size': volumesize,
                     'volumepath': vol_instance.path})
        rc, job = self.conn.InvokeMethod(
            'CreateOrModifyElementFromStoragePool',
            configservice, ElementType=self._getnum(provisioning, '16'),
            Size=self._getnum(volumesize, '64'),
            TheElement=vol_instance.path)
        LOG.debug(_('Extend Volume: %(volumename)s  Return code: %(rc)lu')
                  % {'volumename': volumename,
                     'rc': rc})
        if rc != 0L:
            rc, errordesc = self._wait_for_job_complete(job)
            if rc != 0L:
                LOG.error(_('Error Extend Volume: %(volumename)s.  '
                          'Return code: %(rc)lu.  Error: %(error)s')
                          % {'volumename': volumename,
                             'rc': rc,
                             'error': errordesc})
                raise exception.VolumeBackendAPIException(data=errordesc)
        LOG.debug(_('Leaving extend_volume: %(volumename)s  '
                  'Return code: %(rc)lu ')
                  % {'volumename': volumename,
                     'rc': rc})
**** CubicPower OpenStack Study ****
    def update_volume_stats(self):
        """Retrieve stats info."""
        LOG.debug(_("Updating volume stats"))
        self.stats['total_capacity_gb'] = 'unknown'
        self.stats['free_capacity_gb'] = 'unknown'
        return self.stats
**** CubicPower OpenStack Study ****
    def _get_storage_type(self, volume, filename=None):
        """Get storage type.
        Look for user input volume type first.
        If not available, fall back to finding it in conf file.
        """
        specs = self._get_volumetype_extraspecs(volume)
        if not specs:
            specs = self._get_storage_type_conffile()
        LOG.debug(_("Storage Type: %s") % (specs))
        return specs
**** CubicPower OpenStack Study ****
    def _get_storage_type_conffile(self, filename=None):
        """Get the storage type from the config file."""
        if filename == None:
            filename = self.configuration.cinder_emc_config_file
        file = open(filename, 'r')
        data = file.read()
        file.close()
        dom = parseString(data)
        storageTypes = dom.getElementsByTagName('StorageType')
        if storageTypes is not None and len(storageTypes) > 0:
            storageType = storageTypes[0].toxml()
            storageType = storageType.replace('', '')            storageType = storageType.replace('
', '')
            LOG.debug(_("Found Storage Type in config file: %s")
                      % (storageType))
            specs = {}
            specs[POOL] = storageType
            return specs
        else:
            exception_message = (_("Storage type not found."))
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
**** CubicPower OpenStack Study ****
    def _get_masking_view(self, filename=None):
        if filename is None:
            filename = self.configuration.cinder_emc_config_file
        file = open(filename, 'r')
        data = file.read()
        file.close()
        dom = parseString(data)
        views = dom.getElementsByTagName('MaskingView')
        if views is not None and len(views) > 0:
            view = views[0].toxml().replace('', '')            view = view.replace('
', '')
            LOG.debug(_("Found Masking View: %s") % (view))
            return view
        else:
            LOG.debug(_("Masking View not found."))
            return None
**** CubicPower OpenStack Study ****
    def _get_timeout(self, filename=None):
        if filename is None:
            filename = self.configuration.cinder_emc_config_file
        file = open(filename, 'r')
        data = file.read()
        file.close()
        dom = parseString(data)
        timeouts = dom.getElementsByTagName('Timeout')
        if timeouts is not None and len(timeouts) > 0:
            timeout = timeouts[0].toxml().replace('', '')            timeout = timeout.replace('
', '')
            LOG.debug(_("Found Timeout: %s") % (timeout))
            return timeout
        else:
            LOG.debug(_("Timeout not specified."))
            return 10
**** CubicPower OpenStack Study ****
    def _get_ecom_cred(self, filename=None):
        if filename is None:
            filename = self.configuration.cinder_emc_config_file
        file = open(filename, 'r')
        data = file.read()
        file.close()
        dom = parseString(data)
        ecomUsers = dom.getElementsByTagName('EcomUserName')
        if ecomUsers is not None and len(ecomUsers) > 0:
            ecomUser = ecomUsers[0].toxml().replace('', '')            ecomUser = ecomUser.replace('
', '')
        ecomPasswds = dom.getElementsByTagName('EcomPassword')
        if ecomPasswds is not None and len(ecomPasswds) > 0:
            ecomPasswd = ecomPasswds[0].toxml().replace('', '')            ecomPasswd = ecomPasswd.replace('
', '')
        if ecomUser is not None and ecomPasswd is not None:
            return ecomUser, ecomPasswd
        else:
            LOG.debug(_("Ecom user not found."))
            return None
**** CubicPower OpenStack Study ****
    def _get_ecom_server(self, filename=None):
        if filename is None:
            filename = self.configuration.cinder_emc_config_file
        file = open(filename, 'r')
        data = file.read()
        file.close()
        dom = parseString(data)
        ecomIps = dom.getElementsByTagName('EcomServerIp')
        if ecomIps is not None and len(ecomIps) > 0:
            ecomIp = ecomIps[0].toxml().replace('', '')            ecomIp = ecomIp.replace('
', '')
        ecomPorts = dom.getElementsByTagName('EcomServerPort')
        if ecomPorts is not None and len(ecomPorts) > 0:
            ecomPort = ecomPorts[0].toxml().replace('', '')            ecomPort = ecomPort.replace('
', '')
        if ecomIp is not None and ecomPort is not None:
            LOG.debug(_("Ecom IP: %(ecomIp)s Port: %(ecomPort)s"),
                      {'ecomIp': ecomIp, 'ecomPort': ecomPort})
            return ecomIp, ecomPort
        else:
            LOG.debug(_("Ecom server not found."))
            return None
**** CubicPower OpenStack Study ****
    def _get_ecom_connection(self, filename=None):
        conn = pywbem.WBEMConnection(self.url, (self.user, self.passwd),
                                     default_namespace='root/emc')
        if conn is None:
            exception_message = (_("Cannot connect to ECOM server"))
            raise exception.VolumeBackendAPIException(data=exception_message)
        return conn
**** CubicPower OpenStack Study ****
    def _find_replication_service(self, storage_system):
        foundRepService = None
        repservices = self.conn.EnumerateInstanceNames(
            'EMC_ReplicationService')
        for repservice in repservices:
            if storage_system == repservice['SystemName']:
                foundRepService = repservice
                LOG.debug(_("Found Replication Service: %s")
                          % (repservice))
                break
        return foundRepService
**** CubicPower OpenStack Study ****
    def _find_storage_configuration_service(self, storage_system):
        foundConfigService = None
        configservices = self.conn.EnumerateInstanceNames(
            'EMC_StorageConfigurationService')
        for configservice in configservices:
            if storage_system == configservice['SystemName']:
                foundConfigService = configservice
                LOG.debug(_("Found Storage Configuration Service: %s")
                          % (configservice))
                break
        return foundConfigService
**** CubicPower OpenStack Study ****
    def _find_controller_configuration_service(self, storage_system):
        foundConfigService = None
        configservices = self.conn.EnumerateInstanceNames(
            'EMC_ControllerConfigurationService')
        for configservice in configservices:
            if storage_system == configservice['SystemName']:
                foundConfigService = configservice
                LOG.debug(_("Found Controller Configuration Service: %s")
                          % (configservice))
                break
        return foundConfigService
**** CubicPower OpenStack Study ****
    def _find_storage_hardwareid_service(self, storage_system):
        foundConfigService = None
        configservices = self.conn.EnumerateInstanceNames(
            'EMC_StorageHardwareIDManagementService')
        for configservice in configservices:
            if storage_system == configservice['SystemName']:
                foundConfigService = configservice
                LOG.debug(_("Found Storage Hardware ID Management Service: %s")
                          % (configservice))
                break
        return foundConfigService
    # Find pool based on storage_type
**** CubicPower OpenStack Study ****
    def _find_pool(self, storage_type, details=False):
        foundPool = None
        systemname = None
        # Only get instance names if details flag is False;
        # Otherwise get the whole instances
        if details is False:
            vpools = self.conn.EnumerateInstanceNames(
                'EMC_VirtualProvisioningPool')
            upools = self.conn.EnumerateInstanceNames(
                'EMC_UnifiedStoragePool')
        else:
            vpools = self.conn.EnumerateInstances(
                'EMC_VirtualProvisioningPool')
            upools = self.conn.EnumerateInstances(
                'EMC_UnifiedStoragePool')
        for upool in upools:
            poolinstance = upool['InstanceID']
            # Example: CLARiiON+APM00115204878+U+Pool 0
            poolname, systemname = self._parse_pool_instance_id(poolinstance)
            if poolname is not None and systemname is not None:
                if str(storage_type) == str(poolname):
                    foundPool = upool
                    break
        if foundPool is None:
            for vpool in vpools:
                poolinstance = vpool['InstanceID']
                # Example: SYMMETRIX+000195900551+TP+Sol_Innov
                poolname, systemname = self._parse_pool_instance_id(
                    poolinstance)
                if poolname is not None and systemname is not None:
                    if str(storage_type) == str(poolname):
                        foundPool = vpool
                        break
        if foundPool is None:
            exception_message = (_("Pool %(storage_type)s is not found.")
                                 % {'storage_type': storage_type})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        if systemname is None:
            exception_message = (_("Storage system not found for pool "
                                 "%(storage_type)s.")
                                 % {'storage_type': storage_type})
            LOG.error(exception_message)
            raise exception.VolumeBackendAPIException(data=exception_message)
        LOG.debug(_("Pool: %(pool)s  SystemName: %(systemname)s.")
                  % {'pool': foundPool,
                     'systemname': systemname})
        return foundPool, systemname
**** CubicPower OpenStack Study ****
    def _parse_pool_instance_id(self, instanceid):
        # Example of pool InstanceId: CLARiiON+APM00115204878+U+Pool 0
        poolname = None
        systemname = None
        endp = instanceid.rfind('+')
        if endp > -1:
            poolname = instanceid[endp + 1:]
        idarray = instanceid.split('+')
        if len(idarray) > 2:
            systemname = idarray[0] + '+' + idarray[1]
        LOG.debug(_("Pool name: %(poolname)s  System name: %(systemname)s.")
                  % {'poolname': poolname, 'systemname': systemname})
        return poolname, systemname
**** CubicPower OpenStack Study ****
    def _find_lun(self, volume):
        foundinstance = None
        volumename = volume['name']
        loc = volume['provider_location']
        name = eval(loc)
        instancename = self._getinstancename(name['classname'],
                                             name['keybindings'])
        foundinstance = self.conn.GetInstance(instancename)
        if foundinstance is None:
            LOG.debug(_("Volume %(volumename)s not found on the array.")
                      % {'volumename': volumename})
        else:
            LOG.debug(_("Volume name: %(volumename)s  Volume instance: "
                      "%(vol_instance)s.")
                      % {'volumename': volumename,
                         'vol_instance': foundinstance.path})
        return foundinstance
**** CubicPower OpenStack Study ****
    def _find_storage_sync_sv_sv(self, snapshot, volume,
                                 waitforsync=True):
        foundsyncname = None
        storage_system = None
        percent_synced = 0
        snapshotname = snapshot['name']
        volumename = volume['name']
        LOG.debug(_("Source: %(volumename)s  Target: %(snapshotname)s.")
                  % {'volumename': volumename, 'snapshotname': snapshotname})
        snapshot_instance = self._find_lun(snapshot)
        volume_instance = self._find_lun(volume)
        storage_system = volume_instance['SystemName']
        classname = 'SE_StorageSynchronized_SV_SV'
        bindings = {'SyncedElement': snapshot_instance.path,
                    'SystemElement': volume_instance.path}
        foundsyncname = self._getinstancename(classname, bindings)
        if foundsyncname is None:
            LOG.debug(_("Source: %(volumename)s  Target: %(snapshotname)s. "
                      "Storage Synchronized not found. ")
                      % {'volumename': volumename,
                         'snapshotname': snapshotname})
        else:
            LOG.debug(_("Storage system: %(storage_system)s  "
                      "Storage Synchronized instance: %(sync)s.")
                      % {'storage_system': storage_system,
                         'sync': foundsyncname})
            # Wait for SE_StorageSynchronized_SV_SV to be fully synced
            while waitforsync and percent_synced < 100:
                time.sleep(10)
                sync_instance = self.conn.GetInstance(foundsyncname,
                                                      LocalOnly=False)
                percent_synced = sync_instance['PercentSynced']
        return foundsyncname, storage_system
**** CubicPower OpenStack Study ****
    def _find_initiator_names(self, connector):
        foundinitiatornames = []
        iscsi = 'iscsi'
        fc = 'fc'
        name = 'initiator name'
        if self.protocol.lower() == iscsi and connector['initiator']:
            foundinitiatornames.append(connector['initiator'])
        elif self.protocol.lower() == fc and connector['wwpns']:
            for wwn in connector['wwpns']:
                foundinitiatornames.append(wwn)
            name = 'world wide port names'
        if foundinitiatornames is None or len(foundinitiatornames) == 0:
            msg = (_('Error finding %s.') % name)
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)
        LOG.debug(_("Found %(name)s: %(initiator)s.")
                  % {'name': name,
                     'initiator': foundinitiatornames})
        return foundinitiatornames
**** CubicPower OpenStack Study ****
    def _wait_for_job_complete(self, job):
        jobinstancename = job['Job']
        while True:
            jobinstance = self.conn.GetInstance(jobinstancename,
                                                LocalOnly=False)
            jobstate = jobinstance['JobState']
            # From ValueMap of JobState in CIM_ConcreteJob
            # 2L=New, 3L=Starting, 4L=Running, 32767L=Queue Pending
            # ValueMap("2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13..32767,
            # 32768..65535"),
            # Values("New, Starting, Running, Suspended, Shutting Down,
            # Completed, Terminated, Killed, Exception, Service,
            # Query Pending, DMTF Reserved, Vendor Reserved")]
            if jobstate in [2L, 3L, 4L, 32767L]:
                time.sleep(10)
            else:
                break
        rc = jobinstance['ErrorCode']
        errordesc = jobinstance['ErrorDescription']
        return rc, errordesc
    # Find LunMaskingSCSIProtocolController for the local host on the
    # specified storage system
**** CubicPower OpenStack Study ****
    def _find_lunmasking_scsi_protocol_controller(self, storage_system,
                                                  connector):
        foundCtrl = None
        initiators = self._find_initiator_names(connector)
        controllers = self.conn.EnumerateInstanceNames(
            'EMC_LunMaskingSCSIProtocolController')
        for ctrl in controllers:
            if storage_system != ctrl['SystemName']:
                continue
            associators =\
                self.conn.Associators(ctrl,
                                      resultClass='EMC_StorageHardwareID')
            for assoc in associators:
                # if EMC_StorageHardwareID matches the initiator,
                # we found the existing EMC_LunMaskingSCSIProtocolController
                # (Storage Group for VNX)
                # we can use for masking a new LUN
                hardwareid = assoc['StorageID']
                for initiator in initiators:
                    if hardwareid.lower() == initiator.lower():
                        foundCtrl = ctrl
                        break
                if foundCtrl is not None:
                    break
            if foundCtrl is not None:
                break
        LOG.debug(_("LunMaskingSCSIProtocolController for storage system "
                  "%(storage_system)s and initiator %(initiator)s is  "
                  "%(ctrl)s.")
                  % {'storage_system': storage_system,
                     'initiator': initiators,
                     'ctrl': foundCtrl})
        return foundCtrl
    # Find LunMaskingSCSIProtocolController for the local host and the
    # specified storage volume
**** CubicPower OpenStack Study ****
    def _find_lunmasking_scsi_protocol_controller_for_vol(self, vol_instance,
                                                          connector):
        foundCtrl = None
        initiators = self._find_initiator_names(connector)
        controllers =\
            self.conn.AssociatorNames(
                vol_instance.path,
                resultClass='EMC_LunMaskingSCSIProtocolController')
        for ctrl in controllers:
            associators =\
                self.conn.Associators(
                    ctrl,
                    resultClass='EMC_StorageHardwareID')
            for assoc in associators:
                # if EMC_StorageHardwareID matches the initiator,
                # we found the existing EMC_LunMaskingSCSIProtocolController
                # (Storage Group for VNX)
                # we can use for masking a new LUN
                hardwareid = assoc['StorageID']
                for initiator in initiators:
                    if hardwareid.lower() == initiator.lower():
                        foundCtrl = ctrl
                        break
                if foundCtrl is not None:
                    break
            if foundCtrl is not None:
                break
        LOG.debug(_("LunMaskingSCSIProtocolController for storage volume "
                  "%(vol)s and initiator %(initiator)s is  %(ctrl)s.")
                  % {'vol': vol_instance.path,
                     'initiator': initiators,
                     'ctrl': foundCtrl})
        return foundCtrl
    # Find out how many volumes are mapped to a host
    # assoociated to the LunMaskingSCSIProtocolController
**** CubicPower OpenStack Study ****
    def get_num_volumes_mapped(self, volume, connector):
        numVolumesMapped = 0
        volumename = volume['name']
        vol_instance = self._find_lun(volume)
        if vol_instance is None:
            msg = (_('Volume %(name)s not found on the array. '
                   'Cannot determine if there are volumes mapped.')
                   % {'name': volumename})
            LOG.error(msg)
            raise exception.VolumeBackendAPIException(data=msg)
        storage_system = vol_instance['SystemName']
        ctrl = self._find_lunmasking_scsi_protocol_controller(
            storage_system,
            connector)
        LOG.debug(_("LunMaskingSCSIProtocolController for storage system "
                  "%(storage)s and %(connector)s is %(ctrl)s.")
                  % {'storage': storage_system,
                     'connector': connector,
                     'ctrl': ctrl})
        associators = self.conn.Associators(
            ctrl,
            resultClass='EMC_StorageVolume')
        numVolumesMapped = len(associators)
        LOG.debug(_("Found %(numVolumesMapped)d volumes on storage system "
                  "%(storage)s mapped to %(initiator)s.")
                  % {'numVolumesMapped': numVolumesMapped,
                     'storage': storage_system,
                     'connector': connector})
        return numVolumesMapped
    # Find an available device number that a host can see
**** CubicPower OpenStack Study ****
    def _find_avail_device_number(self, storage_system):
        out_device_number = '000000'
        out_num_device_number = 0
        numlist = []
        myunitnames = []
        unitnames = self.conn.EnumerateInstanceNames(
            'CIM_ProtocolControllerForUnit')
        for unitname in unitnames:
            controller = unitname['Antecedent']
            if storage_system != controller['SystemName']:
                continue
            classname = controller['CreationClassName']
            index = classname.find('LunMaskingSCSIProtocolController')
            if index > -1:
                unitinstance = self.conn.GetInstance(unitname,
                                                     LocalOnly=False)
                numDeviceNumber = int(unitinstance['DeviceNumber'])
                numlist.append(numDeviceNumber)
                myunitnames.append(unitname)
        maxnum = max(numlist)
        out_num_device_number = maxnum + 1
        out_device_number = '%06d' % out_num_device_number
        LOG.debug(_("Available device number on %(storage)s: %(device)s.")
                  % {'storage': storage_system, 'device': out_device_number})
        return out_device_number
    # Find a device number that a host can see for a volume
**** CubicPower OpenStack Study ****
    def find_device_number(self, volume, connector):
        out_num_device_number = None
        volumename = volume['name']
        vol_instance = self._find_lun(volume)
        storage_system = vol_instance['SystemName']
        sp = None
        try:
            sp = vol_instance['EMCCurrentOwningStorageProcessor']
        except KeyError:
            # VMAX LUN doesn't have this property
            pass
        indexVMAX = storage_system.find('SYMMETRIX')
        if indexVMAX == -1:
            # find out whether the volume is already attached to the host
            ctrl = self._find_lunmasking_scsi_protocol_controller_for_vol(
                vol_instance,
                connector)
            LOG.debug(_("LunMaskingSCSIProtocolController for "
                      "volume %(vol)s and connector %(connector)s "
                      "is %(ctrl)s.")
                      % {'vol': vol_instance.path,
                         'connector': connector,
                         'ctrl': ctrl})
        if indexVMAX > -1 or ctrl:
            unitnames = self.conn.ReferenceNames(
                vol_instance.path,
                ResultClass='CIM_ProtocolControllerForUnit')
            for unitname in unitnames:
                controller = unitname['Antecedent']
                classname = controller['CreationClassName']
                index = classname.find('LunMaskingSCSIProtocolController')
                if index > -1:  # VNX
                    if ctrl['DeviceID'] != controller['DeviceID']:
                        continue
                    # Get an instance of CIM_ProtocolControllerForUnit
                    unitinstance = self.conn.GetInstance(unitname,
                                                         LocalOnly=False)
                    numDeviceNumber = int(unitinstance['DeviceNumber'], 16)
                    out_num_device_number = numDeviceNumber
                    break
                else:
                    index = classname.find('Symm_LunMaskingView')
                    if index > -1:  # VMAX
                        unitinstance = self.conn.GetInstance(unitname,
                                                             LocalOnly=False)
                        numDeviceNumber = int(unitinstance['DeviceNumber'],
                                              16)
                        out_num_device_number = numDeviceNumber
                        break
        if out_num_device_number is None:
            LOG.info(_("Device number not found for volume "
                     "%(volumename)s %(vol_instance)s.") %
                     {'volumename': volumename,
                      'vol_instance': vol_instance.path})
        else:
            LOG.debug(_("Found device number %(device)d for volume "
                      "%(volumename)s %(vol_instance)s.") %
                      {'device': out_num_device_number,
                       'volumename': volumename,
                       'vol_instance': vol_instance.path})
        data = {'hostlunid': out_num_device_number,
                'storagesystem': storage_system,
                'owningsp': sp}
        LOG.debug(_("Device info: %(data)s.") % {'data': data})
        return data
**** CubicPower OpenStack Study ****
    def _find_device_masking_group(self):
        """Finds the Device Masking Group in a masking view."""
        foundMaskingGroup = None
        maskingview_name = self._get_masking_view()
        maskingviews = self.conn.EnumerateInstanceNames(
            'EMC_LunMaskingSCSIProtocolController')
        for view in maskingviews:
            instance = self.conn.GetInstance(view, LocalOnly=False)
            if maskingview_name == instance['ElementName']:
                foundView = view
                break
        groups = self.conn.AssociatorNames(
            foundView,
            ResultClass='SE_DeviceMaskingGroup')
        foundMaskingGroup = groups[0]
        LOG.debug(_("Masking view: %(view)s DeviceMaskingGroup: %(masking)s.")
                  % {'view': maskingview_name,
                     'masking': foundMaskingGroup})
        return foundMaskingGroup
    # Find a StorageProcessorSystem given sp and storage system
**** CubicPower OpenStack Study ****
    def _find_storage_processor_system(self, owningsp, storage_system):
        foundSystem = None
        systems = self.conn.EnumerateInstanceNames(
            'EMC_StorageProcessorSystem')
        for system in systems:
            # Clar_StorageProcessorSystem.CreationClassName=
            # "Clar_StorageProcessorSystem",Name="CLARiiON+APM00123907237+SP_A"
            idarray = system['Name'].split('+')
            if len(idarray) > 2:
                storsystemname = idarray[0] + '+' + idarray[1]
                sp = idarray[2]
            if (storage_system == storsystemname and
                    owningsp == sp):
                foundSystem = system
                LOG.debug(_("Found Storage Processor System: %s")
                          % (system))
                break
        return foundSystem
    # Find EMC_iSCSIProtocolEndpoint for the specified sp
**** CubicPower OpenStack Study ****
    def _find_iscsi_protocol_endpoints(self, owningsp, storage_system):
        foundEndpoints = []
        processor = self._find_storage_processor_system(
            owningsp,
            storage_system)
        associators = self.conn.Associators(
            processor,
            resultClass='EMC_iSCSIProtocolEndpoint')
        for assoc in associators:
            # Name = iqn.1992-04.com.emc:cx.apm00123907237.a8,t,0x0001
            # SystemName = CLARiiON+APM00123907237+SP_A+8
            arr = assoc['SystemName'].split('+')
            if len(arr) > 2:
                processor_name = arr[0] + '+' + arr[1] + '+' + arr[2]
                if processor_name == processor['Name']:
                    arr2 = assoc['Name'].split(',')
                    if len(arr2) > 1:
                        foundEndpoints.append(arr2[0])
        LOG.debug(_("iSCSIProtocolEndpoint for storage system "
                  "%(storage_system)s and SP %(sp)s is  "
                  "%(endpoint)s.")
                  % {'storage_system': storage_system,
                     'sp': owningsp,
                     'endpoint': foundEndpoints})
        return foundEndpoints
**** CubicPower OpenStack Study ****
    def _getnum(self, num, datatype):
        try:
            result = {
                '8': pywbem.Uint8(num),
                '16': pywbem.Uint16(num),
                '32': pywbem.Uint32(num),
                '64': pywbem.Uint64(num)
            }
            result = result.get(datatype, num)
        except NameError:
            result = num
        return result
**** CubicPower OpenStack Study ****
    def _getinstancename(self, classname, bindings):
        instancename = None
        try:
            instancename = pywbem.CIMInstanceName(
                classname,
                namespace=EMC_ROOT,
                keybindings=bindings)
        except NameError:
            instancename = None
        return instancename
    # Find target WWNs
**** CubicPower OpenStack Study ****
    def get_target_wwns(self, storage_system, connector):
        target_wwns = []
        configservice = self._find_storage_hardwareid_service(
            storage_system)
        if configservice is None:
            exception_msg = (_("Error finding Storage Hardware ID Service."))
            LOG.error(exception_msg)
            raise exception.VolumeBackendAPIException(data=exception_msg)
        hardwareids = self._find_storage_hardwareids(connector)
        LOG.debug(_('EMCGetTargetEndpoints: Service: %(service)s  '
                  'Storage HardwareIDs: %(hardwareids)s.')
                  % {'service': configservice,
                     'hardwareids': hardwareids})
        for hardwareid in hardwareids:
            rc, targetendpoints = self.conn.InvokeMethod(
                'EMCGetTargetEndpoints',
                configservice,
                HardwareId=hardwareid)
            if rc != 0L:
                msg = (_('Error finding Target WWNs.'))
                LOG.error(msg)
                raise exception.VolumeBackendAPIException(data=msg)
            endpoints = targetendpoints['TargetEndpoints']
            for targetendpoint in endpoints:
                wwn = targetendpoint['Name']
                # Add target wwn to the list if it is not already there
                if not any(d == wwn for d in target_wwns):
                    target_wwns.append(wwn)
                LOG.debug(_('Add target WWN: %s.') % wwn)
        LOG.debug(_('Target WWNs: %s.') % target_wwns)
        return target_wwns
    # Find Storage Hardware IDs
**** CubicPower OpenStack Study ****
    def _find_storage_hardwareids(self, connector):
        foundInstances = []
        wwpns = self._find_initiator_names(connector)
        hardwareids = self.conn.EnumerateInstances(
            'SE_StorageHardwareID')
        for hardwareid in hardwareids:
            storid = hardwareid['StorageID']
            for wwpn in wwpns:
                if wwpn.lower() == storid.lower():
                    foundInstances.append(hardwareid.path)
        LOG.debug(_("Storage Hardware IDs for %(wwpns)s is "
                  "%(foundInstances)s.")
                  % {'wwpns': wwpns,
                     'foundInstances': foundInstances})
        return foundInstances
**** CubicPower OpenStack Study ****
    def _get_volumetype_extraspecs(self, volume):
        specs = {}
        type_id = volume['volume_type_id']
        if type_id is not None:
            specs = volume_types.get_volume_type_extra_specs(type_id)
            # If specs['storagetype:pool'] not defined,
            # set specs to {} so we can ready from config file later
            if POOL not in specs:
                specs = {}
        return specs
**** CubicPower OpenStack Study ****
    def _get_provisioning(self, storage_type):
        # provisioning is thin (5) by default
        provisioning = 5
        thick_str = 'thick'
        try:
            type_prov = storage_type[PROVISIONING]
            if type_prov.lower() == thick_str.lower():
                provisioning = 2
        except KeyError:
            # Default to thin if not defined
            pass
        return provisioning