Merge "VMAX driver - volume and snapshot treated as dicts in attach snapshot" into stable/ocata
This commit is contained in:
commit
16852f9048
|
@ -33,6 +33,9 @@ from cinder.objects import consistencygroup
|
|||
from cinder.objects import fields
|
||||
from cinder.objects import qos_specs
|
||||
from cinder import test
|
||||
from cinder.tests.unit import fake_constants
|
||||
from cinder.tests.unit import fake_snapshot
|
||||
from cinder.tests.unit import fake_volume
|
||||
from cinder.tests.unit import utils as unit_utils
|
||||
from cinder import utils as cinder_utils
|
||||
|
||||
|
@ -753,6 +756,17 @@ class VMAXCommonData(object):
|
|||
UNSYNCHRONIZED = 3
|
||||
multiPoolSupportEnabled = True
|
||||
|
||||
test_vol_obj = fake_volume.fake_volume_obj(
|
||||
context='context', expected_attrs=[], name='vol1', size=2,
|
||||
provider_auth=None, host=fake_host,
|
||||
volume_type_id=fake_constants.VOLUME_TYPE_ID,
|
||||
provider_location=six.text_type(provider_location))
|
||||
|
||||
test_snap_obj = fake_snapshot.fake_snapshot_obj(
|
||||
context='context', name='ss1', size=2, id=fake_constants.SNAPSHOT_ID,
|
||||
provider_location=six.text_type(provider_location),
|
||||
host=fake_host, volume=test_vol_obj)
|
||||
|
||||
|
||||
class FakeLookupService(object):
|
||||
def get_device_mapping_from_network(self, initiator_wwns, target_wwns):
|
||||
|
@ -8506,7 +8520,7 @@ class VMAXFCTest(test.TestCase):
|
|||
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'initialize_connection',
|
||||
'initialize_connection_snapshot',
|
||||
return_value=VMAXCommonData.fc_device_info)
|
||||
@mock.patch.object(
|
||||
fc.VMAXFCDriver,
|
||||
|
@ -8515,13 +8529,14 @@ class VMAXFCTest(test.TestCase):
|
|||
VMAXCommonData.end_point_map))
|
||||
def test_initialize_connection_snapshot(self, mock_map, mock_conn):
|
||||
data = self.driver.initialize_connection_snapshot(
|
||||
self.data.test_snapshot_v3, self.data.connector)
|
||||
self.data.test_snap_obj,
|
||||
self.data.connector)
|
||||
self.assertEqual('fibre_channel', data['driver_volume_type'])
|
||||
self.assertEqual(3, data['data']['target_lun'])
|
||||
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'_unmap_lun')
|
||||
'_unmap_lun_snapshot')
|
||||
@mock.patch.object(
|
||||
fc.VMAXFCDriver,
|
||||
'_get_zoning_mappings',
|
||||
|
@ -8535,7 +8550,7 @@ class VMAXFCTest(test.TestCase):
|
|||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
data = self.driver.terminate_connection_snapshot(
|
||||
self.data.test_snapshot_v3, self.data.connector)
|
||||
self.data.test_snap_obj, self.data.connector)
|
||||
self.assertEqual('fibre_channel', data['driver_volume_type'])
|
||||
self.assertEqual(2, len(data['data']['target_wwn']))
|
||||
|
||||
|
@ -10116,24 +10131,25 @@ class VMAXISCSITest(test.TestCase):
|
|||
False, {}))
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'initialize_connection',
|
||||
'initialize_connection_snapshot',
|
||||
return_value=VMAXCommonData.iscsi_device_info)
|
||||
def test_initialize_connection_snapshot(self, mock_conn, mock_num):
|
||||
data = self.driver.initialize_connection_snapshot(
|
||||
self.data.test_snapshot_v3, self.data.connector)
|
||||
self.data.test_snap_obj, self.data.connector)
|
||||
self.assertEqual('iscsi', data['driver_volume_type'])
|
||||
self.assertEqual(1, data['data']['target_lun'])
|
||||
|
||||
@mock.patch.object(
|
||||
common.VMAXCommon,
|
||||
'_unmap_lun')
|
||||
'_unmap_lun_snapshot')
|
||||
def test_terminate_connection_snapshot(self, mock_unmap):
|
||||
common = self.driver.common
|
||||
common.conn = FakeEcomConnection()
|
||||
self.driver.terminate_connection_snapshot(
|
||||
self.data.test_snapshot_v3, self.data.connector)
|
||||
common._unmap_lun.assert_called_once_with(
|
||||
self.data.test_snapshot_v3, self.data.connector)
|
||||
self.data.test_snap_obj, self.data.connector)
|
||||
common._unmap_lun_snapshot.assert_called_once_with(
|
||||
self.data.test_snap_obj, self.data.test_vol_obj,
|
||||
self.data.connector)
|
||||
|
||||
@mock.patch.object(
|
||||
masking.VMAXMasking,
|
||||
|
|
|
@ -514,6 +514,27 @@ class VMAXCommon(object):
|
|||
if self.utils.is_volume_failed_over(volume):
|
||||
extraSpecs = self._get_replication_extraSpecs(
|
||||
extraSpecs, self.rep_config)
|
||||
self._unmap_lun_common(volume, connector, extraSpecs)
|
||||
|
||||
def _unmap_lun_snapshot(self, snapshot, volume, connector):
|
||||
"""Unmaps a snapshot from the host.
|
||||
|
||||
:param snapshot: the snapshot Object
|
||||
:param volume: the volume Object
|
||||
:param connector: the connector Object
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
extraSpecs = self._initial_setup(volume)
|
||||
self._unmap_lun_common(snapshot, connector, extraSpecs)
|
||||
|
||||
def _unmap_lun_common(self, volume, connector, extraSpecs):
|
||||
"""Unmaps a volume from the host.
|
||||
|
||||
:param volume: the volume Object
|
||||
:param connector: the connector Object
|
||||
:param extraSpecs: extra specifications
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
volumename = volume['name']
|
||||
LOG.info(_LI("Unmap volume: %(volume)s."),
|
||||
{'volume': volumename})
|
||||
|
@ -569,6 +590,23 @@ class VMAXCommon(object):
|
|||
def initialize_connection(self, volume, connector):
|
||||
"""Initializes the connection and returns device and connection info.
|
||||
|
||||
:param volume: volume Object
|
||||
:param connector: the connector Object
|
||||
:returns: dict -- deviceInfoDict - device information dict
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
extraSpecs = self._initial_setup(volume)
|
||||
|
||||
if self.utils.is_volume_failed_over(volume):
|
||||
extraSpecs = self._get_replication_extraSpecs(
|
||||
extraSpecs, self.rep_config)
|
||||
|
||||
return self.initialize_connection_common(
|
||||
volume, connector, extraSpecs)
|
||||
|
||||
def initialize_connection_common(self, volume, connector, extraSpecs):
|
||||
"""Initializes the connection and returns device and connection info.
|
||||
|
||||
The volume may be already mapped, if this is so the deviceInfo tuple
|
||||
is returned. If the volume is not already mapped then we need to
|
||||
gather information to either 1. Create an new masking view or 2. Add
|
||||
|
@ -592,11 +630,10 @@ class VMAXCommon(object):
|
|||
|
||||
:param volume: volume Object
|
||||
:param connector: the connector Object
|
||||
:param extraSpecs: extra specifications
|
||||
:returns: dict -- deviceInfoDict - device information dict
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
portGroupName = None
|
||||
extraSpecs = self._initial_setup(volume)
|
||||
is_multipath = connector.get('multipath', False)
|
||||
|
||||
volumeName = volume['name']
|
||||
|
@ -604,9 +641,6 @@ class VMAXCommon(object):
|
|||
{'volume': volumeName})
|
||||
self.conn = self._get_ecom_connection()
|
||||
|
||||
if self.utils.is_volume_failed_over(volume):
|
||||
extraSpecs = self._get_replication_extraSpecs(
|
||||
extraSpecs, self.rep_config)
|
||||
deviceInfoDict, isLiveMigration, sourceInfoDict = (
|
||||
self._wrap_find_device_number(
|
||||
volume, connector['host']))
|
||||
|
@ -1835,10 +1869,10 @@ class VMAXCommon(object):
|
|||
name = ast.literal_eval(loc)
|
||||
keys = name['keybindings']
|
||||
systemName = keys['SystemName']
|
||||
admin_metadata = {}
|
||||
admin_metadata = None
|
||||
if 'admin_metadata' in volume:
|
||||
admin_metadata = volume.admin_metadata
|
||||
if 'targetVolumeName' in admin_metadata:
|
||||
if admin_metadata and 'targetVolumeName' in admin_metadata:
|
||||
targetVolName = admin_metadata['targetVolumeName']
|
||||
prefix1 = 'SYMMETRIX+'
|
||||
prefix2 = 'SYMMETRIX-+-'
|
||||
|
@ -6059,3 +6093,32 @@ class VMAXCommon(object):
|
|||
if self.multiPoolSupportEnabled:
|
||||
self.multiPoolSupportEnabled = False
|
||||
return secondaryInfo
|
||||
|
||||
def initialize_connection_snapshot(
|
||||
self, snapshot, volume, connector):
|
||||
"""Initializes the connection and returns device and connection info.
|
||||
|
||||
:param snapshot: snapshot Object
|
||||
:param volume: volume Object
|
||||
:param connector: the connector Object
|
||||
:returns: dict -- deviceInfoDict - device information dict
|
||||
:raises: VolumeBackendAPIException
|
||||
"""
|
||||
extraSpecs = self._initial_setup(volume)
|
||||
|
||||
return self.initialize_connection_common(
|
||||
snapshot, connector, extraSpecs)
|
||||
|
||||
def terminate_connection_snapshot(self, snapshot, volume, connector):
|
||||
"""Disallow connection from connector.
|
||||
|
||||
:param snapshot: the snapshot Object
|
||||
:param volume: the volume Object
|
||||
:param connector: the connector Object
|
||||
"""
|
||||
if not connector:
|
||||
exception_message = (_("The connector object from nova "
|
||||
"cannot be None."))
|
||||
raise exception.VolumeBackendAPIException(
|
||||
data=exception_message)
|
||||
self._unmap_lun_snapshot(snapshot, volume, connector)
|
||||
|
|
|
@ -496,10 +496,10 @@ class VMAXFCDriver(driver.FibreChannelDriver):
|
|||
:param kwargs: additional parameters
|
||||
:returns: data dict
|
||||
"""
|
||||
src_volume = snapshot['volume']
|
||||
snapshot['host'] = src_volume['host']
|
||||
|
||||
return self.initialize_connection(snapshot, connector)
|
||||
src_volume = snapshot.volume
|
||||
device_info = self.common.initialize_connection_snapshot(
|
||||
snapshot, src_volume, connector)
|
||||
return self.populate_data(device_info, snapshot, connector)
|
||||
|
||||
def terminate_connection_snapshot(self, snapshot, connector, **kwargs):
|
||||
"""Disallows connection to snapshot.
|
||||
|
@ -508,9 +508,17 @@ class VMAXFCDriver(driver.FibreChannelDriver):
|
|||
:param connector: the connector object
|
||||
:param kwargs: additional parameters
|
||||
"""
|
||||
src_volume = snapshot['volume']
|
||||
snapshot['host'] = src_volume['host']
|
||||
return self.terminate_connection(snapshot, connector, **kwargs)
|
||||
src_volume = snapshot.volume
|
||||
data = {'driver_volume_type': 'fibre_channel',
|
||||
'data': {}}
|
||||
zoning_mappings = (
|
||||
self._get_zoning_mappings(snapshot, connector))
|
||||
|
||||
if zoning_mappings:
|
||||
self.common.terminate_connection_snapshot(
|
||||
snapshot, src_volume, connector)
|
||||
data = self._cleanup_zones(zoning_mappings)
|
||||
return data
|
||||
|
||||
def backup_use_temp_snapshot(self):
|
||||
return True
|
||||
|
|
|
@ -418,10 +418,9 @@ class VMAXISCSIDriver(driver.ISCSIDriver):
|
|||
:param kwargs: additional parameters
|
||||
:returns: iscsi dict
|
||||
"""
|
||||
src_volume = snapshot['volume']
|
||||
snapshot['host'] = src_volume['host']
|
||||
device_info = self.common.initialize_connection(
|
||||
snapshot, connector)
|
||||
src_volume = snapshot.volume
|
||||
device_info = self.common.initialize_connection_snapshot(
|
||||
snapshot, src_volume, connector)
|
||||
return self.get_iscsi_dict(
|
||||
device_info, snapshot, connector)
|
||||
|
||||
|
@ -432,10 +431,9 @@ class VMAXISCSIDriver(driver.ISCSIDriver):
|
|||
:param connector: the connector object
|
||||
:param kwargs: additional parameters
|
||||
"""
|
||||
src_volume = snapshot['volume']
|
||||
snapshot['host'] = src_volume['host']
|
||||
return self.common.terminate_connection(snapshot,
|
||||
connector)
|
||||
src_volume = snapshot.volume
|
||||
return self.common.terminate_connection_snapshot(
|
||||
snapshot, src_volume, connector)
|
||||
|
||||
def backup_use_temp_snapshot(self):
|
||||
return True
|
||||
|
|
Loading…
Reference in New Issue