Merge "SolidFire Generic Groups Support"

This commit is contained in:
Jenkins 2017-05-27 00:09:36 +00:00 committed by Gerrit Code Review
commit cbfc5e97ee
3 changed files with 225 additions and 37 deletions

View File

@ -1587,7 +1587,7 @@ class SolidFireVolumeTestCase(test.TestCase):
self.assertEqual(1, rem_vag.call_count)
rem_vag.assert_called_with(1)
def test_create_group_snapshot(self):
def test_sf_create_group_snapshot(self):
# Sunny day group snapshot creation.
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
name = 'great_gsnap_name'
@ -1598,7 +1598,7 @@ class SolidFireVolumeTestCase(test.TestCase):
with mock.patch.object(sfv,
'_issue_api_request',
return_value=fake_result) as fake_api:
res = sfv._create_group_snapshot(name, sf_volumes)
res = sfv._sf_create_group_snapshot(name, sf_volumes)
self.assertEqual('contrived_test', res)
fake_api.assert_called_with('CreateGroupSnapshot',
expected_params,
@ -1616,7 +1616,7 @@ class SolidFireVolumeTestCase(test.TestCase):
'_get_all_active_volumes',
return_value=active_vols),\
mock.patch.object(sfv,
'_create_group_snapshot',
'_sf_create_group_snapshot',
return_value=None) as create:
sfv._group_snapshot_creator(gsnap_name, vol_uuids)
create.assert_called_with(gsnap_name,
@ -1732,13 +1732,13 @@ class SolidFireVolumeTestCase(test.TestCase):
mock.patch.object(sfv,
'_do_clone_volume',
return_value=kek):
model, vol_models = sfv.create_consistencygroup_from_src(
model, vol_models = sfv._create_consistencygroup_from_src(
ctxt, group, volumes,
cgsnapshot, snapshots,
source_cg, source_vols)
get_snap.assert_called_with(name)
self.assertEqual(
{'status': fields.ConsistencyGroupStatus.AVAILABLE}, model)
{'status': fields.GroupStatus.AVAILABLE}, model)
def test_create_consisgroup_from_src_source_cg(self):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
@ -1768,14 +1768,14 @@ class SolidFireVolumeTestCase(test.TestCase):
return_value=kek),\
mock.patch.object(sfv,
'_delete_cgsnapshot_by_name'):
model, vol_models = sfv.create_consistencygroup_from_src(
model, vol_models = sfv._create_consistencygroup_from_src(
ctxt, group, volumes,
cgsnapshot, snapshots,
source_cg,
source_vols)
get_snap.assert_called_with(source_cg['id'])
self.assertEqual(
{'status': fields.ConsistencyGroupStatus.AVAILABLE}, model)
{'status': fields.GroupStatus.AVAILABLE}, model)
def test_create_cgsnapshot(self):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
@ -1790,8 +1790,8 @@ class SolidFireVolumeTestCase(test.TestCase):
'_get_all_active_volumes',
return_value=active_vols),\
mock.patch.object(sfv,
'_create_group_snapshot') as create_gsnap:
sfv.create_cgsnapshot(ctxt, cgsnapshot, snapshots)
'_sf_create_group_snapshot') as create_gsnap:
sfv._create_cgsnapshot(ctxt, cgsnapshot, snapshots)
create_gsnap.assert_called_with(pfx + cgsnapshot['id'],
active_vols)
@ -1807,9 +1807,9 @@ class SolidFireVolumeTestCase(test.TestCase):
'_get_all_active_volumes',
return_value=active_vols),\
mock.patch.object(sfv,
'_create_group_snapshot'):
'_sf_create_group_snapshot'):
self.assertRaises(exception.SolidFireDriverException,
sfv.create_cgsnapshot,
sfv._create_cgsnapshot,
ctxt,
cgsnapshot,
snapshots)
@ -1818,11 +1818,11 @@ class SolidFireVolumeTestCase(test.TestCase):
# cgsnaps on the backend yield numerous identically named snapshots.
# create_volume_from_snapshot now searches for the correct snapshot.
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
source = {'cgsnapshot_id': 'typical_cgsnap_id',
source = {'group_snapshot_id': 'typical_cgsnap_id',
'volume_id': 'typical_vol_id',
'id': 'no_id_4_u'}
name = (self.configuration.sf_volume_prefix
+ source.get('cgsnapshot_id'))
+ source.get('group_snapshot_id'))
with mock.patch.object(sfv,
'_get_group_snapshot_by_name',
return_value={}) as get,\
@ -1833,6 +1833,136 @@ class SolidFireVolumeTestCase(test.TestCase):
get.assert_called_once_with(name)
self.assertEqual('model', result)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_cg(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = True
group = mock.MagicMock()
result = sfv.create_group(self.ctxt, group)
self.assertEqual(result,
{'status': fields.GroupStatus.AVAILABLE})
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_rainy(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = False
group = mock.MagicMock()
self.assertRaises(NotImplementedError,
sfv.create_group,
self.ctxt, group)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_from_src_rainy(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = False
group = mock.MagicMock()
volumes = [mock.MagicMock()]
self.assertRaises(NotImplementedError,
sfv.create_group_from_src,
self.ctxt, group, volumes)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_from_src_cg(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = True
group = mock.MagicMock()
volumes = [mock.MagicMock()]
ret = 'things'
with mock.patch.object(sfv,
'_create_consistencygroup_from_src',
return_value=ret):
result = sfv.create_group_from_src(self.ctxt,
group,
volumes)
self.assertEqual(ret, result)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_snapshot_rainy(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = False
group_snapshot = mock.MagicMock()
snapshots = [mock.MagicMock()]
self.assertRaises(NotImplementedError,
sfv.create_group_snapshot,
self.ctxt,
group_snapshot,
snapshots)
group_cg_test.assert_called_once_with(group_snapshot)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_create_group_snapshot(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = True
group_snapshot = mock.MagicMock()
snapshots = [mock.MagicMock()]
ret = 'things'
with mock.patch.object(sfv,
'_create_cgsnapshot',
return_value=ret):
result = sfv.create_group_snapshot(self.ctxt,
group_snapshot,
snapshots)
self.assertEqual(ret, result)
group_cg_test.assert_called_once_with(group_snapshot)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_delete_group_rainy(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = False
group = mock.MagicMock()
volumes = [mock.MagicMock()]
self.assertRaises(NotImplementedError,
sfv.delete_group,
self.ctxt,
group,
volumes)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_delete_group(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = True
group = mock.MagicMock()
volumes = [mock.MagicMock()]
ret = 'things'
with mock.patch.object(sfv,
'_delete_consistencygroup',
return_value=ret):
result = sfv.delete_group(self.ctxt,
group,
volumes)
self.assertEqual(ret, result)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_update_group_rainy(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = False
group = mock.MagicMock()
self.assertRaises(NotImplementedError,
sfv.update_group,
self.ctxt,
group)
group_cg_test.assert_called_once_with(group)
@mock.patch('cinder.volume.utils.is_group_a_cg_snapshot_type')
def test_update_group(self, group_cg_test):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
group_cg_test.return_value = True
group = mock.MagicMock()
ret = 'things'
with mock.patch.object(sfv,
'_update_consistencygroup',
return_value=ret):
result = sfv.update_group(self.ctxt,
group)
self.assertEqual(ret, result)
group_cg_test.assert_called_once_with(group)
def test_getattr_failure(self):
sfv = solidfire.SolidFireDriver(configuration=self.configuration)
try:

View File

@ -42,6 +42,7 @@ from cinder import utils
from cinder.volume.drivers.san import san
from cinder.volume import qos_specs
from cinder.volume.targets import iscsi as iscsi_driver
from cinder.volume import utils as vol_utils
from cinder.volume import volume_types
LOG = logging.getLogger(__name__)
@ -1482,16 +1483,16 @@ class SolidFireDriver(san.SanISCSIDriver):
@locked_source_id_operation
def create_volume_from_snapshot(self, volume, source):
"""Create a volume from the specified snapshot."""
if source.get('cgsnapshot_id'):
if source.get('group_snapshot_id'):
# We're creating a volume from a snapshot that resulted from a
# consistency group snapshot. Because of the way that SolidFire
# creates cgsnaps, we have to search for the correct snapshot.
cgsnapshot_id = source.get('cgsnapshot_id')
group_snapshot_id = source.get('group_snapshot_id')
snapshot_id = source.get('volume_id')
sf_name = self.configuration.sf_volume_prefix + cgsnapshot_id
sf_name = self.configuration.sf_volume_prefix + group_snapshot_id
sf_group_snap = self._get_group_snapshot_by_name(sf_name)
return self._create_clone_from_sf_snapshot(snapshot_id,
cgsnapshot_id,
group_snapshot_id,
sf_group_snap,
volume)
@ -1502,7 +1503,7 @@ class SolidFireDriver(san.SanISCSIDriver):
return model
# Consistency group helpers
def _create_group_snapshot(self, name, sf_volumes):
def _sf_create_group_snapshot(self, name, sf_volumes):
# Group snapshot is our version of a consistency group snapshot.
vol_ids = [vol['volumeID'] for vol in sf_volumes]
params = {'name': name,
@ -1527,7 +1528,7 @@ class SolidFireDriver(san.SanISCSIDriver):
"des": len(src_vol_ids)})
raise exception.SolidFireDriverException(msg)
result = self._create_group_snapshot(gsnap_name, target_vols)
result = self._sf_create_group_snapshot(gsnap_name, target_vols)
return result
def _create_temp_group_snapshot(self, source_cg, source_vols):
@ -1607,17 +1608,68 @@ class SolidFireDriver(san.SanISCSIDriver):
self.configuration.sf_volume_prefix)[1]
return vlist
# Required consistency group functions
def create_consistencygroup(self, ctxt, group):
# SolidFire does not have a viable means for storing consistency group
# volume associations. So, we're just going to play along with the
# consistency group song and dance. There will be a lot of no-ops
# because of this.
return {'status': fields.ConsistencyGroupStatus.AVAILABLE}
# Generic Volume Groups.
def create_group(self, ctxt, group):
# SolidFire does not have the concept of volume groups. We're going to
# play along with the group song and dance. There will be a lot of
# no-ops because of this.
if vol_utils.is_group_a_cg_snapshot_type(group):
return {'status': fields.GroupStatus.AVAILABLE}
def create_consistencygroup_from_src(self, ctxt, group, volumes,
cgsnapshot, snapshots,
source_cg, source_vols):
# Blatantly ripping off this pattern from other drivers.
raise NotImplementedError()
def create_group_from_src(self, ctxt, group, volumes, group_snapshots=None,
snapshots=None, source_group=None,
source_vols=None):
# At this point this is just a pass-through.
if vol_utils.is_group_a_cg_snapshot_type(group):
return self._create_consistencygroup_from_src(
ctxt,
group,
volumes,
group_snapshots,
snapshots,
source_group,
source_vols)
# Default implementation handles other scenarios.
raise NotImplementedError()
def create_group_snapshot(self, ctxt, group_snapshot, snapshots):
# This is a pass-through to the old consistency group stuff.
if vol_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self._create_cgsnapshot(ctxt, group_snapshot, snapshots)
# Default implementation handles other scenarios.
raise NotImplementedError()
def delete_group(self, ctxt, group, volumes):
# Delete a volume group. SolidFire does not track volume groups,
# however we do need to actually remove the member volumes of the
# group. Right now only consistent volume groups are supported.
if vol_utils.is_group_a_cg_snapshot_type(group):
return self._delete_consistencygroup(ctxt, group, volumes)
# Default implementation handles other scenarios.
raise NotImplementedError()
def update_group(self, ctxt, group, add_volumes=None, remove_volumes=None):
# Regarding consistency groups SolidFire does not track volumes, so
# this is a no-op. In the future with replicated volume groups this
# might actually do something.
if vol_utils.is_group_a_cg_snapshot_type(group):
return self._update_consistencygroup(ctxt,
group,
add_volumes,
remove_volumes)
# Default implementation handles other scenarios.
raise NotImplementedError()
def _create_consistencygroup_from_src(self, ctxt, group, volumes,
cgsnapshot, snapshots,
source_cg, source_vols):
if cgsnapshot and snapshots:
sf_name = self.configuration.sf_volume_prefix + cgsnapshot['id']
sf_group_snap = self._get_group_snapshot_by_name(sf_name)
@ -1630,7 +1682,7 @@ class SolidFireDriver(san.SanISCSIDriver):
snap['id'],
sf_group_snap,
vol))
return ({'status': fields.ConsistencyGroupStatus.AVAILABLE},
return ({'status': fields.GroupStatus.AVAILABLE},
vol_models)
elif source_cg and source_vols:
@ -1649,9 +1701,9 @@ class SolidFireDriver(san.SanISCSIDriver):
vol))
finally:
self._delete_cgsnapshot_by_name(gsnap_name)
return {'status': 'available'}, vol_models
return {'status': fields.GroupStatus.AVAILABLE}, vol_models
def create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
def _create_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
vol_ids = [snapshot['volume_id'] for snapshot in snapshots]
vol_names = [self.configuration.sf_volume_prefix + vol_id
for vol_id in vol_ids]
@ -1665,21 +1717,23 @@ class SolidFireDriver(san.SanISCSIDriver):
"des": len(snapshots)})
raise exception.SolidFireDriverException(msg)
snap_name = self.configuration.sf_volume_prefix + cgsnapshot['id']
self._create_group_snapshot(snap_name, target_vols)
self._sf_create_group_snapshot(snap_name, target_vols)
return None, None
def update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
def _update_consistencygroup(self, context, group,
add_volumes=None, remove_volumes=None):
# Similar to create_consistencygroup, SolidFire's lack of a consistency
# group object means there is nothing to update on the cluster.
return None, None, None
def delete_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
def _delete_cgsnapshot(self, ctxt, cgsnapshot, snapshots):
snap_name = self.configuration.sf_volume_prefix + cgsnapshot['id']
self._delete_cgsnapshot_by_name(snap_name)
return None, None
def delete_consistencygroup(self, ctxt, group, volumes):
def _delete_consistencygroup(self, ctxt, group, volumes):
# TODO(chris_morrell): exception handling and return correctly updated
# volume_models.
for vol in volumes:
self.delete_volume(vol)
@ -1732,6 +1786,7 @@ class SolidFireDriver(san.SanISCSIDriver):
data["driver_version"] = self.VERSION
data["storage_protocol"] = 'iSCSI'
data['consistencygroup_support'] = True
data['consistent_group_snapshot_enabled'] = True
data['replication_enabled'] = self.replication_enabled
if self.replication_enabled:
data['replication'] = 'enabled'

View File

@ -0,0 +1,3 @@
---
features:
- Add consistent group capability to generic volume groups in the SolidFire driver.