Storwize: add backup snapshots support
This patch adds backup snapshots support for Storwize/SVC driver. The change implements attach and detach snapshot: initialize_connection_snapshot terminate_connection_snapshot Implements: blueprint storwize-backup-snapshots Change-Id: I65393a6a5f995d609152d4b8546c055d7bf0b253
This commit is contained in:
parent
6af48d7bd9
commit
f68847353e
@ -2758,6 +2758,12 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
|
||||
vol = testutils.create_volume(self.ctxt, **prop)
|
||||
return vol
|
||||
|
||||
def _generate_snap_info(self, vol_id, size=10):
|
||||
prop = {'volume_id': vol_id,
|
||||
'volume_size': size}
|
||||
snap = testutils.create_snapshot(self.ctxt, **prop)
|
||||
return snap
|
||||
|
||||
def _assert_vol_exists(self, name, exists):
|
||||
is_vol_defined = self.iscsi_driver._helpers.is_vdisk_defined(name)
|
||||
self.assertEqual(exists, is_vol_defined)
|
||||
@ -2797,6 +2803,43 @@ class StorwizeSVCISCSIDriverTestCase(test.TestCase):
|
||||
self.iscsi_driver.initialize_connection(volume_iSCSI, connector)
|
||||
self.iscsi_driver.terminate_connection(volume_iSCSI, connector)
|
||||
|
||||
def test_storwize_iscsi_connection_snapshot(self):
|
||||
# create a iSCSI volume
|
||||
volume_iSCSI = self._create_volume()
|
||||
snapshot = self._generate_snap_info(volume_iSCSI.id)
|
||||
self.iscsi_driver.create_snapshot(snapshot)
|
||||
connector = {'host': 'storwize-svc-host',
|
||||
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
|
||||
'wwpns': ['ff00000000000000', 'ff00000000000001'],
|
||||
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
|
||||
|
||||
self.iscsi_driver.initialize_connection_snapshot(snapshot, connector)
|
||||
self.iscsi_driver.terminate_connection_snapshot(snapshot, connector)
|
||||
|
||||
def test_storwize_replication_failover_iscsi_connection_snapshot(self):
|
||||
volume_iSCSI = self._create_volume()
|
||||
snapshot = self._generate_snap_info(volume_iSCSI.id)
|
||||
self.iscsi_driver.create_snapshot(snapshot)
|
||||
connector = {'host': 'storwize-svc-host',
|
||||
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
|
||||
'wwpns': ['ff00000000000000', 'ff00000000000001'],
|
||||
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
|
||||
# a snapshot of a replication failover volume. attach will be failed
|
||||
with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
|
||||
'_get_volume_replicated_type') as rep_type:
|
||||
rep_type.return_value = True
|
||||
with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
|
||||
'_get_vol_sys_info') as sys_info:
|
||||
sys_info.return_value = {'volume_name': 'voliscsi',
|
||||
'backend_helper':
|
||||
'self._aux_backend_helpers',
|
||||
'node_state': 'self._state'}
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.iscsi_driver.
|
||||
initialize_connection_snapshot,
|
||||
snapshot,
|
||||
connector)
|
||||
|
||||
@mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
|
||||
'_do_terminate_connection')
|
||||
@mock.patch.object(storwize_svc_iscsi.StorwizeSVCISCSIDriver,
|
||||
@ -3298,6 +3341,12 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
|
||||
vol = testutils.create_volume(self.ctxt, **prop)
|
||||
return vol
|
||||
|
||||
def _generate_snap_info(self, vol_id, size=10):
|
||||
prop = {'volume_id': vol_id,
|
||||
'volume_size': size}
|
||||
snap = testutils.create_snapshot(self.ctxt, **prop)
|
||||
return snap
|
||||
|
||||
def _assert_vol_exists(self, name, exists):
|
||||
is_vol_defined = self.fc_driver._helpers.is_vdisk_defined(name)
|
||||
self.assertEqual(exists, is_vol_defined)
|
||||
@ -3315,6 +3364,44 @@ class StorwizeSVCFcDriverTestCase(test.TestCase):
|
||||
|
||||
self.assertIsNotNone(host_name)
|
||||
|
||||
def test_storwize_fc_connection_snapshot(self):
|
||||
# create a iSCSI volume
|
||||
volume_fc = self._create_volume()
|
||||
snapshot = self._generate_snap_info(volume_fc.id)
|
||||
self.fc_driver.create_snapshot(snapshot)
|
||||
connector = {'host': 'storwize-svc-host',
|
||||
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
|
||||
'wwpns': ['ff00000000000000', 'ff00000000000001'],
|
||||
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
|
||||
|
||||
self.fc_driver.initialize_connection_snapshot(snapshot, connector)
|
||||
self.fc_driver.terminate_connection_snapshot(snapshot, connector)
|
||||
|
||||
def test_storwize_replication_failover_fc_connection_snapshot(self):
|
||||
volume_fc = self._create_volume()
|
||||
volume_fc['replication_status'] = fields.ReplicationStatus.FAILED_OVER
|
||||
snapshot = self._generate_snap_info(volume_fc.id)
|
||||
self.fc_driver.create_snapshot(snapshot)
|
||||
connector = {'host': 'storwize-svc-host',
|
||||
'wwnns': ['20000090fa17311e', '20000090fa17311f'],
|
||||
'wwpns': ['ff00000000000000', 'ff00000000000001'],
|
||||
'initiator': 'iqn.1993-08.org.debian:01:eac5ccc1aaa'}
|
||||
# a snapshot of a replication failover volume. attach will be failed
|
||||
with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
|
||||
'_get_volume_replicated_type') as rep_type:
|
||||
rep_type.return_value = True
|
||||
with mock.patch.object(storwize_svc_common.StorwizeSVCCommonDriver,
|
||||
'_get_vol_sys_info') as sys_info:
|
||||
sys_info.return_value = {'volume_name': 'volfc',
|
||||
'backend_helper':
|
||||
'self._aux_backend_helpers',
|
||||
'node_state': 'self._state'}
|
||||
self.assertRaises(exception.VolumeDriverException,
|
||||
self.fc_driver.
|
||||
initialize_connection_snapshot,
|
||||
snapshot,
|
||||
connector)
|
||||
|
||||
def test_storwize_get_host_with_fc_connection_with_volume(self):
|
||||
# create a FC volume
|
||||
volume_fc = self._generate_vol_info(None, None)
|
||||
|
@ -2578,6 +2578,13 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
def remove_export(self, ctxt, volume):
|
||||
pass
|
||||
|
||||
def create_export_snapshot(self, ctxt, snapshot, connector):
|
||||
model_update = None
|
||||
return model_update
|
||||
|
||||
def remove_export_snapshot(self, ctxt, snapshot):
|
||||
pass
|
||||
|
||||
def _get_vdisk_params(self, type_id, volume_type=None,
|
||||
volume_metadata=None):
|
||||
return self._helpers.get_vdisk_params(self.configuration,
|
||||
@ -3860,6 +3867,21 @@ class StorwizeSVCCommonDriver(san.SanDriver,
|
||||
|
||||
return tgt_vol, backend_helper, node_state
|
||||
|
||||
def _check_snapshot_replica_volume_status(self, snapshot):
|
||||
ctxt = context.get_admin_context()
|
||||
if self._get_volume_replicated_type(ctxt, None,
|
||||
snapshot.volume_type_id):
|
||||
LOG.debug('It is a replication volume snapshot for backup.')
|
||||
rep_volume = objects.Volume.get_by_id(ctxt, snapshot.volume_id)
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
rep_volume)
|
||||
if backend_helper != self._helpers or self._active_backend_id:
|
||||
msg = (_('The snapshot of the replication volume %s has '
|
||||
'failed over to the aux backend. It can not attach'
|
||||
' to the aux backend.') % volume_name)
|
||||
LOG.error(msg)
|
||||
raise exception.VolumeDriverException(message=msg)
|
||||
|
||||
def migrate_volume(self, ctxt, volume, host):
|
||||
"""Migrate directly if source and dest are managed by same storage.
|
||||
|
||||
|
@ -33,6 +33,7 @@ localized format.
|
||||
are of different sizes, is not supported.
|
||||
|
||||
"""
|
||||
import collections
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
@ -93,6 +94,7 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
2.2.1 - Add vdisk mirror/stretch cluster support
|
||||
2.2.2 - Add npiv support
|
||||
2.2.3 - Add replication group support
|
||||
2.2.4 - Add backup snapshots support
|
||||
"""
|
||||
|
||||
VERSION = "2.2.3"
|
||||
@ -114,6 +116,21 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
raise exception.InvalidConnectorException(
|
||||
missing='wwpns')
|
||||
|
||||
def initialize_connection_snapshot(self, snapshot, connector):
|
||||
"""Perform attach snapshot for backup snapshots."""
|
||||
# If the snapshot's source volume is a replication volume and the
|
||||
# replication volume has failed over to aux_backend,
|
||||
# attach the snapshot will be failed.
|
||||
self._check_snapshot_replica_volume_status(snapshot)
|
||||
|
||||
vol_attrs = ['id', 'name', 'display_name']
|
||||
Volume = collections.namedtuple('Volume', vol_attrs)
|
||||
volume = Volume(id=snapshot.id,
|
||||
name=snapshot.name,
|
||||
display_name='backup-snapshot')
|
||||
|
||||
return self.initialize_connection(volume, connector)
|
||||
|
||||
@fczm_utils.add_fc_zone
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Perform necessary work to make a FC connection."""
|
||||
@ -136,9 +153,16 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
|
||||
"""
|
||||
LOG.debug('enter: initialize_connection: volume %(vol)s with connector'
|
||||
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
' %(conn)s', {'vol': volume.id, 'conn': connector})
|
||||
if volume.display_name == 'backup-snapshot':
|
||||
LOG.debug('It is a virtual volume %(vol)s for attach snapshot.',
|
||||
{'vol': volume.id})
|
||||
volume_name = volume.name
|
||||
backend_helper = self._helpers
|
||||
node_state = self._state
|
||||
else:
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
|
||||
# Check if a host object is defined for this host name
|
||||
host_name = backend_helper.get_host_from_connector(connector)
|
||||
@ -192,7 +216,7 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
properties = {}
|
||||
properties['target_discovered'] = False
|
||||
properties['target_lun'] = lun_id
|
||||
properties['volume_id'] = volume['id']
|
||||
properties['volume_id'] = volume.id
|
||||
|
||||
conn_wwpns = backend_helper.get_conn_fc_wwpns(host_name)
|
||||
|
||||
@ -234,7 +258,7 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
|
||||
LOG.debug('leave: initialize_connection:\n volume: %(vol)s\n '
|
||||
'connector %(conn)s\n properties: %(prop)s',
|
||||
{'vol': volume['id'], 'conn': connector,
|
||||
{'vol': volume.id, 'conn': connector,
|
||||
'prop': properties})
|
||||
|
||||
return {'driver_volume_type': 'fibre_channel', 'data': properties, }
|
||||
@ -249,6 +273,16 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
|
||||
return i_t_map
|
||||
|
||||
def terminate_connection_snapshot(self, snapshot, connector, **kwargs):
|
||||
"""Perform detach snapshot for backup snapshots."""
|
||||
vol_attrs = ['id', 'name', 'display_name']
|
||||
Volume = collections.namedtuple('Volume', vol_attrs)
|
||||
volume = Volume(id=snapshot.id,
|
||||
name=snapshot.name,
|
||||
display_name='backup-snapshot')
|
||||
|
||||
return self.terminate_connection(volume, connector, **kwargs)
|
||||
|
||||
@fczm_utils.remove_fc_zone
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Cleanup after an FC connection has been terminated."""
|
||||
@ -276,8 +310,16 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
automatically by this driver when mappings are created)
|
||||
"""
|
||||
LOG.debug('enter: terminate_connection: volume %(vol)s with connector'
|
||||
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
||||
vol_name, backend_helper, node_state = self._get_vol_sys_info(volume)
|
||||
' %(conn)s', {'vol': volume.id, 'conn': connector})
|
||||
if volume.display_name == 'backup-snapshot':
|
||||
LOG.debug('It is a virtual volume %(vol)s for detach snapshot.',
|
||||
{'vol': volume.id})
|
||||
vol_name = volume.name
|
||||
backend_helper = self._helpers
|
||||
node_state = self._state
|
||||
else:
|
||||
vol_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
|
||||
info = {}
|
||||
if 'host' in connector:
|
||||
@ -324,6 +366,6 @@ class StorwizeSVCFCDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
backend_helper.delete_host(host_name)
|
||||
|
||||
LOG.debug('leave: terminate_connection: volume %(vol)s with '
|
||||
'connector %(conn)s', {'vol': volume['id'],
|
||||
'connector %(conn)s', {'vol': volume.id,
|
||||
'conn': connector})
|
||||
return info
|
||||
|
@ -33,6 +33,7 @@ localized format.
|
||||
are of different sizes, is not supported.
|
||||
|
||||
"""
|
||||
import collections
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
@ -92,6 +93,7 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
2.2 - Add CG capability to generic volume groups
|
||||
2.2.1 - Add vdisk mirror/stretch cluster support
|
||||
2.2.2 - Add replication group support
|
||||
2.2.3 - Add backup snapshots support
|
||||
"""
|
||||
|
||||
VERSION = "2.2.2"
|
||||
@ -113,6 +115,21 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
raise exception.InvalidConnectorException(
|
||||
missing='initiator')
|
||||
|
||||
def initialize_connection_snapshot(self, snapshot, connector):
|
||||
"""Perform attach snapshot for backup snapshots."""
|
||||
# If the snapshot's source volume is a replication volume and the
|
||||
# replication volume has failed over to aux_backend,
|
||||
# attach the snapshot will be failed.
|
||||
self._check_snapshot_replica_volume_status(snapshot)
|
||||
|
||||
vol_attrs = ['id', 'name', 'display_name']
|
||||
Volume = collections.namedtuple('Volume', vol_attrs)
|
||||
volume = Volume(id=snapshot.id,
|
||||
name=snapshot.name,
|
||||
display_name='backup-snapshot')
|
||||
|
||||
return self.initialize_connection(volume, connector)
|
||||
|
||||
def initialize_connection(self, volume, connector):
|
||||
"""Perform necessary work to make an iSCSI connection."""
|
||||
@utils.synchronized('storwize-host' + self._state['system_id'] +
|
||||
@ -133,9 +150,16 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
proper I/O group)
|
||||
"""
|
||||
LOG.debug('enter: initialize_connection: volume %(vol)s with connector'
|
||||
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
' %(conn)s', {'vol': volume.id, 'conn': connector})
|
||||
if volume.display_name == 'backup-snapshot':
|
||||
LOG.debug('It is a virtual volume %(vol)s for attach snapshot.',
|
||||
{'vol': volume.id})
|
||||
volume_name = volume.name
|
||||
backend_helper = self._helpers
|
||||
node_state = self._state
|
||||
else:
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
|
||||
# Check if a host object is defined for this host name
|
||||
host_name = backend_helper.get_host_from_connector(connector,
|
||||
@ -178,7 +202,7 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
|
||||
LOG.debug('leave: initialize_connection:\n volume: %(vol)s\n '
|
||||
'connector: %(conn)s\n properties: %(prop)s',
|
||||
{'vol': volume['id'], 'conn': connector,
|
||||
{'vol': volume.id, 'conn': connector,
|
||||
'prop': properties})
|
||||
|
||||
return {'driver_volume_type': 'iscsi', 'data': properties, }
|
||||
@ -186,11 +210,19 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
def _get_single_iscsi_data(self, volume, connector, lun_id, chap_secret):
|
||||
LOG.debug('enter: _get_single_iscsi_data: volume %(vol)s with '
|
||||
'connector %(conn)s lun_id %(lun_id)s',
|
||||
{'vol': volume['id'], 'conn': connector,
|
||||
{'vol': volume.id, 'conn': connector,
|
||||
'lun_id': lun_id})
|
||||
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
if volume.display_name == 'backup-snapshot':
|
||||
LOG.debug('It is a virtual volume %(vol)s for attach snapshot',
|
||||
{'vol': volume.name})
|
||||
volume_name = volume.name
|
||||
backend_helper = self._helpers
|
||||
node_state = self._state
|
||||
else:
|
||||
volume_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
|
||||
volume_attributes = backend_helper.get_vdisk_attributes(volume_name)
|
||||
if volume_attributes is None:
|
||||
msg = (_('_get_single_iscsi_data: Failed to get attributes'
|
||||
@ -311,6 +343,16 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
|
||||
return properties
|
||||
|
||||
def terminate_connection_snapshot(self, snapshot, connector, **kwargs):
|
||||
"""Perform detach snapshot for backup snapshots."""
|
||||
vol_attrs = ['id', 'name', 'display_name']
|
||||
Volume = collections.namedtuple('Volume', vol_attrs)
|
||||
volume = Volume(id=snapshot.id,
|
||||
name=snapshot.name,
|
||||
display_name='backup-snapshot')
|
||||
|
||||
return self.terminate_connection(volume, connector, **kwargs)
|
||||
|
||||
def terminate_connection(self, volume, connector, **kwargs):
|
||||
"""Cleanup after an iSCSI connection has been terminated."""
|
||||
# If a fake connector is generated by nova when the host
|
||||
@ -337,8 +379,16 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
automatically by this driver when mappings are created)
|
||||
"""
|
||||
LOG.debug('enter: terminate_connection: volume %(vol)s with connector'
|
||||
' %(conn)s', {'vol': volume['id'], 'conn': connector})
|
||||
vol_name, backend_helper, node_state = self._get_vol_sys_info(volume)
|
||||
' %(conn)s', {'vol': volume.id, 'conn': connector})
|
||||
if volume.display_name == 'backup-snapshot':
|
||||
LOG.debug('It is a virtual volume %(vol)s for detach snapshot.',
|
||||
{'vol': volume.id})
|
||||
vol_name = volume.name
|
||||
backend_helper = self._helpers
|
||||
node_state = self._state
|
||||
else:
|
||||
vol_name, backend_helper, node_state = self._get_vol_sys_info(
|
||||
volume)
|
||||
|
||||
info = {}
|
||||
if 'host' in connector:
|
||||
@ -366,6 +416,6 @@ class StorwizeSVCISCSIDriver(storwize_common.StorwizeSVCCommonDriver):
|
||||
backend_helper.delete_host(host_name)
|
||||
|
||||
LOG.debug('leave: terminate_connection: volume %(vol)s with '
|
||||
'connector %(conn)s', {'vol': volume['id'],
|
||||
'connector %(conn)s', {'vol': volume.id,
|
||||
'conn': connector})
|
||||
return info
|
||||
|
@ -0,0 +1,3 @@
|
||||
---
|
||||
features:
|
||||
- Add backup snapshots support for Storwize/SVC driver.
|
Loading…
Reference in New Issue
Block a user