Merge "ProphetStor: Support generic group"

This commit is contained in:
Jenkins 2017-07-21 03:17:49 +00:00 committed by Gerrit Code Review
commit 9d301b67c7
3 changed files with 384 additions and 192 deletions

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations
# under the License.
import copy
import errno
import re
@ -20,18 +19,21 @@ import mock
from oslo_utils import units
from six.moves import http_client
from cinder import context
from cinder import exception
from cinder.objects import fields
from cinder import test
from cinder.tests.unit import fake_constants
from cinder.tests.unit import fake_snapshot
from cinder.tests.unit import utils as test_utils
from cinder.volume import configuration as conf
from cinder.volume.drivers.prophetstor import dpl_iscsi as DPLDRIVER
from cinder.volume.drivers.prophetstor import dplcommon as DPLCOMMON
from cinder.volume import group_types
POOLUUID = 'ac33fc6e417440d5a1ef27d7231e1cc4'
VOLUMEUUID = 'a000000000000000000000000000001'
INITIATOR = 'iqn.2013-08.org.debian:01:aaaaaaaa'
DATA_IN_VOLUME = {'id': VOLUMEUUID}
DATA_IN_CONNECTOR = {'initiator': INITIATOR}
DATA_SERVER_INFO = 0, {
'metadata': {'vendor': 'ProphetStor',
@ -101,17 +103,17 @@ DATA_IN_GROUP = {'id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'description': 'des123',
'status': ''}
DATA_IN_VOLUME = {'id': 'abc123',
DATA_IN_VOLUME = {'id': 'c11e902-87e9-348d-0b48-89695f1ec4be5',
'display_name': 'abc123',
'display_description': '',
'size': 10,
'host': "hostname@backend#%s" % POOLUUID}
DATA_IN_VOLUME_VG = {'id': 'abc123',
DATA_IN_VOLUME_VG = {'id': 'fe2dbc5-1581-0451-dab2-f8c8a48d15bee',
'display_name': 'abc123',
'display_description': '',
'size': 10,
'consistencygroup_id':
'group_id':
'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'status': 'available',
'host': "hostname@backend#%s" % POOLUUID}
@ -121,35 +123,35 @@ DATA_IN_REMOVE_VOLUME_VG = {
'display_name': 'fe2dbc515810451dab2f8c8a48d15bee',
'display_description': '',
'size': 10,
'consistencygroup_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'group_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'status': 'available',
'host': "hostname@backend#%s" % POOLUUID}
DATA_IN_VOLUME1 = {'id': 'abc456',
DATA_IN_VOLUME1 = {'id': 'c11e902-87e9-348d-0b48-89695f1ec4bef',
'display_name': 'abc456',
'display_description': '',
'size': 10,
'host': "hostname@backend#%s" % POOLUUID}
DATA_IN_CG_SNAPSHOT = {
'consistencygroup_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'group_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
'id': 'cgsnapshot1',
'name': 'cgsnapshot1',
'description': 'cgsnapshot1',
'status': ''}
DATA_IN_SNAPSHOT = {'id': 'snapshot1',
'volume_id': 'abc123',
DATA_IN_SNAPSHOT = {'id': 'fe2dbc5-1581-0451-dab2-f8c8a48d15bee',
'volume_id': 'c11e902-87e9-348d-0b48-89695f1ec4be5',
'display_name': 'snapshot1',
'display_description': '',
'volume_size': 5}
DATA_OUT_SNAPSHOT_CG = {
'id': 'snapshot1',
'volume_id': 'abc123',
'volume_id': 'c11e902-87e9-348d-0b48-89695f1ec4be5',
'display_name': 'snapshot1',
'display_description': '',
'cgsnapshot_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee'}
'group_snapshot_id': 'fe2dbc51-5810-451d-ab2f-8c8a48d15bee'}
DATA_OUT_CG = {
"objectType": "application/cdmi-container",
@ -183,7 +185,7 @@ DATA_OUT_CG = {
"childrenrange": "<range>",
"children":
[
"fe2dbc515810451dab2f8c8a48d15bee",
'fe2dbc515810451dab2f8c8a48d15bee',
],
}
@ -491,7 +493,7 @@ class TestProphetStorDPLDriver(test.TestCase):
self.configuration.san_thin_provision = True
self.configuration.driver_ssl_cert_verify = False
self.configuration.driver_ssl_cert_path = None
self.context = ''
self.context = context.get_admin_context()
self.DPL_MOCK = mock.MagicMock()
self.DB_MOCK = mock.MagicMock()
self.dpldriver = DPLDRIVER.DPLISCSIDriver(
@ -513,99 +515,164 @@ class TestProphetStorDPLDriver(test.TestCase):
self.assertFalse(pool['QoS_support'])
def test_create_volume(self):
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME['id'],
display_name=DATA_IN_VOLUME['display_name'],
size=DATA_IN_VOLUME['size'],
host=DATA_IN_VOLUME['host'])
self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT
self.dpldriver.create_volume(DATA_IN_VOLUME)
self.dpldriver.create_volume(volume)
self.DPL_MOCK.create_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
DATA_IN_VOLUME['display_name'],
DATA_IN_VOLUME['display_description'],
self._conver_uuid2hex(volume.id),
volume.display_name,
volume.display_description,
self.configuration.dpl_pool,
int(DATA_IN_VOLUME['size']) * units.Gi,
int(volume.size) * units.Gi,
True)
def test_create_volume_without_pool(self):
fake_volume = copy.deepcopy(DATA_IN_VOLUME)
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME['id'],
display_name=DATA_IN_VOLUME['display_name'],
size=DATA_IN_VOLUME['size'],
host=DATA_IN_VOLUME['host'])
self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT
self.configuration.dpl_pool = ""
fake_volume['host'] = "host@backend" # missing pool
volume.host = "host@backend" # missing pool
self.assertRaises(exception.InvalidHost, self.dpldriver.create_volume,
volume=fake_volume)
volume=volume)
def test_create_volume_with_configuration_pool(self):
fake_volume = copy.deepcopy(DATA_IN_VOLUME)
fake_volume['host'] = "host@backend" # missing pool
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME['id'],
display_name=DATA_IN_VOLUME['display_name'],
size=DATA_IN_VOLUME['size'],
host="host@backend")
self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT
self.dpldriver.create_volume(fake_volume)
self.dpldriver.create_volume(volume)
self.DPL_MOCK.create_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
DATA_IN_VOLUME['display_name'],
DATA_IN_VOLUME['display_description'],
self.configuration.dpl_pool,
int(DATA_IN_VOLUME['size']) * units.Gi,
True)
self._conver_uuid2hex(volume.id),
volume.display_name, volume.display_description,
self.configuration.dpl_pool, int(volume.size) * units.Gi, True)
def test_create_volume_of_group(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
self.DPL_MOCK.create_vdev.return_value = DATA_OUTPUT
self.DPL_MOCK.join_vg.return_value = DATA_OUTPUT
self.dpldriver.create_volume(DATA_IN_VOLUME_VG)
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME_VG['id'],
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
group_id=group.id,
host=DATA_IN_VOLUME_VG['host'])
self.dpldriver.create_volume(volume)
self.DPL_MOCK.create_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
DATA_IN_VOLUME['display_name'],
DATA_IN_VOLUME['display_description'],
self._conver_uuid2hex(volume.id),
volume.display_name,
volume.display_description,
self.configuration.dpl_pool,
int(DATA_IN_VOLUME['size']) * units.Gi,
int(volume.size) * units.Gi,
True)
self.DPL_MOCK.join_vg.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME_VG['id']),
self._conver_uuid2hex(
DATA_IN_VOLUME_VG['consistencygroup_id']))
self._conver_uuid2hex(volume.id),
self._conver_uuid2hex(volume.group_id))
def test_delete_volume(self):
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME['id'],
display_name=DATA_IN_VOLUME['display_name'],
size=DATA_IN_VOLUME['size'],
host=DATA_IN_VOLUME['host'])
self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT
self.dpldriver.delete_volume(DATA_IN_VOLUME)
self.dpldriver.delete_volume(volume)
self.DPL_MOCK.delete_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']))
self._conver_uuid2hex(volume.id))
def test_delete_volume_of_group(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME_VG['id'],
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
group_id=group.id,
host=DATA_IN_VOLUME_VG['host'])
self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT
self.DPL_MOCK.leave_vg.return_volume = DATA_OUTPUT
self.dpldriver.delete_volume(DATA_IN_VOLUME_VG)
self.dpldriver.delete_volume(volume)
self.DPL_MOCK.leave_vg.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME_VG['id']),
self._conver_uuid2hex(DATA_IN_GROUP['id'])
self._conver_uuid2hex(volume.id),
self._conver_uuid2hex(volume.group_id)
)
self.DPL_MOCK.delete_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']))
self._conver_uuid2hex(volume.id))
def test_create_volume_from_snapshot(self):
self.DPL_MOCK.create_vdev_from_snapshot.return_value = DATA_OUTPUT
self.DPL_MOCK.extend_vdev.return_value = DATA_OUTPUT
self.dpldriver.create_volume_from_snapshot(DATA_IN_VOLUME,
DATA_IN_SNAPSHOT)
volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME_VG['id'],
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
host=DATA_IN_VOLUME_VG['host'])
self.dpldriver.create_volume_from_snapshot(
volume, DATA_IN_SNAPSHOT)
self.DPL_MOCK.create_vdev_from_snapshot.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
DATA_IN_VOLUME['display_name'],
DATA_IN_VOLUME['display_description'],
self._conver_uuid2hex(DATA_IN_SNAPSHOT['id']),
self._conver_uuid2hex(volume.id),
volume.display_name,
volume.display_description,
self._conver_uuid2hex(volume.id),
self.configuration.dpl_pool,
True)
self.DPL_MOCK.extend_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
DATA_IN_VOLUME['display_name'],
DATA_IN_VOLUME['display_description'],
DATA_IN_VOLUME['size'] * units.Gi)
self._conver_uuid2hex(volume.id),
volume.display_name,
volume.display_description,
volume.size * units.Gi)
def test_create_cloned_volume(self):
new_volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME1['id'],
display_name=DATA_IN_VOLUME1['display_name'],
size=DATA_IN_VOLUME1['size'],
host=DATA_IN_VOLUME1['host'])
src_volume = test_utils.create_volume(
self.context,
id=DATA_IN_VOLUME['id'])
self.DPL_MOCK.clone_vdev.return_value = DATA_OUTPUT
self.dpldriver.create_cloned_volume(DATA_IN_VOLUME1, DATA_IN_VOLUME)
self.dpldriver.create_cloned_volume(new_volume, src_volume)
self.DPL_MOCK.clone_vdev.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_VOLUME['id']),
self._conver_uuid2hex(DATA_IN_VOLUME1['id']),
self._conver_uuid2hex(src_volume.id),
self._conver_uuid2hex(new_volume.id),
self.configuration.dpl_pool,
DATA_IN_VOLUME1['display_name'],
DATA_IN_VOLUME1['display_description'],
int(DATA_IN_VOLUME1['size']) *
new_volume.display_name,
new_volume.display_description,
int(new_volume.size) *
units.Gi,
True)
@ -686,95 +753,179 @@ class TestProphetStorDPLDriver(test.TestCase):
self.assertEqual(4294967296, res['metadata']['total_capacity'])
self.assertEqual('8173612007304181810', res['metadata']['zpool_guid'])
def test_create_consistency_group(self):
def test_create_group(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
self.DPL_MOCK.create_vg.return_value = DATA_OUTPUT
model_update = self.dpldriver.create_consistencygroup(self.context,
DATA_IN_GROUP)
model_update = self.dpldriver.create_group(self.context, group)
self.DPL_MOCK.create_vg.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_GROUP['id']), DATA_IN_GROUP['name'],
DATA_IN_GROUP['description'])
self._conver_uuid2hex(fake_constants.CONSISTENCY_GROUP_ID),
'test_group',
'this is a test group')
self.assertDictEqual({'status': (
fields.ConsistencyGroupStatus.AVAILABLE)}, model_update)
def test_delete_consistency_group(self):
def test_delete_group(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
self.DB_MOCK.volume_get_all_by_group.return_value = (
[DATA_IN_VOLUME_VG])
self.DPL_MOCK.delete_vdev.return_value = DATA_OUTPUT
self.DPL_MOCK.delete_cg.return_value = DATA_OUTPUT
model_update, volumes = self.dpldriver.delete_consistencygroup(
self.context, DATA_IN_GROUP, [])
model_update, volumes = self.dpldriver.delete_group(
self.context, group, [])
self.DPL_MOCK.delete_vg.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_GROUP['id']))
self._conver_uuid2hex(fake_constants.CONSISTENCY_GROUP_ID))
self.DPL_MOCK.delete_vdev.assert_called_once_with(
self._conver_uuid2hex((DATA_IN_VOLUME_VG['id'])))
self.assertDictEqual({'status': (
fields.ConsistencyGroupStatus.DELETED)}, model_update)
def test_update_consistencygroup(self):
def test_update_group(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.join_vg.return_value = DATA_OUTPUT
self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT
add_vol = DATA_IN_VOLUME_VG
remove_vol = DATA_IN_REMOVE_VOLUME_VG
group = test_utils.create_group(
self.context,
id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
vol_add = test_utils.create_volume(
self.context,
id=fake_constants.VOLUME2_ID,
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
group_id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
host=DATA_IN_VOLUME_VG['host'])
vol_del = test_utils.create_volume(
self.context,
id=DATA_IN_REMOVE_VOLUME_VG['id'],
display_name=DATA_IN_REMOVE_VOLUME_VG['display_name'],
size=DATA_IN_REMOVE_VOLUME_VG['size'],
group_id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
host=DATA_IN_REMOVE_VOLUME_VG['host'])
(model_update, add_vols, remove_vols) = (
self.dpldriver.update_consistencygroup(self.context,
DATA_IN_GROUP,
[add_vol],
[remove_vol]))
self.dpldriver.update_group(
self.context, group, [vol_add], [vol_del]))
self.DPL_MOCK.join_vg.assert_called_once_with(
self._conver_uuid2hex(add_vol['id']),
self._conver_uuid2hex(DATA_IN_GROUP['id']))
self._conver_uuid2hex(vol_add.id),
self._conver_uuid2hex(group.id))
self.DPL_MOCK.leave_vg.assert_called_once_with(
self._conver_uuid2hex(remove_vol['id']),
self._conver_uuid2hex(DATA_IN_GROUP['id']))
self._conver_uuid2hex(vol_del.id),
self._conver_uuid2hex(group.id))
self.assertDictEqual({'status': (
fields.ConsistencyGroupStatus.AVAILABLE)}, model_update)
def test_update_consistencygroup_exception_join(self):
def test_update_group_exception_join(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.join_vg.return_value = -1, None
self.DPL_MOCK.leave_vg.return_value = DATA_OUTPUT
add_vol = DATA_IN_VOLUME_VG
volume = test_utils.create_volume(
self.context,
id=fake_constants.VOLUME2_ID,
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
host=DATA_IN_VOLUME_VG['host'])
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
self.assertRaises(exception.VolumeBackendAPIException,
self.dpldriver.update_consistencygroup,
self.dpldriver.update_group,
context=None,
group=DATA_IN_GROUP,
add_volumes=[add_vol],
group=group,
add_volumes=[volume],
remove_volumes=None)
def test_update_consistencygroup_exception_leave(self):
def test_update_group_exception_leave(self):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
self.DPL_MOCK.get_vg.return_value = (0, DATA_OUT_CG)
self.DPL_MOCK.leave_vg.return_value = -1, None
remove_vol = DATA_IN_REMOVE_VOLUME_VG
volume = test_utils.create_volume(
self.context,
id='fe2dbc51-5810-451d-ab2f-8c8a48d15bee',
display_name=DATA_IN_VOLUME_VG['display_name'],
size=DATA_IN_VOLUME_VG['size'],
host=DATA_IN_VOLUME_VG['host'])
group = test_utils.create_group(
self.context,
id=fake_constants.CONSISTENCY_GROUP_ID,
host='host@backend#unit_test_pool',
group_type_id=group_type.id)
self.assertRaises(exception.VolumeBackendAPIException,
self.dpldriver.update_consistencygroup,
self.dpldriver.update_group,
context=None,
group=DATA_IN_GROUP,
group=group,
add_volumes=None,
remove_volumes=[remove_vol])
remove_volumes=[volume])
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
def test_create_consistency_group_snapshot(self, get_all_for_cgsnapshot):
@mock.patch(
'cinder.objects.snapshot.SnapshotList.get_all_for_group_snapshot')
def test_create_group_snapshot(self, get_all_for_group_snapshot):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context)
snapshot_obj.consistencygroup_id = \
DATA_IN_CG_SNAPSHOT['consistencygroup_id']
get_all_for_cgsnapshot.return_value = [snapshot_obj]
snapshot_obj.group_id = \
DATA_IN_CG_SNAPSHOT['group_id']
snapshot_obj.group_type_id = group_type.id
get_all_for_group_snapshot.return_value = [snapshot_obj]
self.DPL_MOCK.create_vdev_snapshot.return_value = DATA_OUTPUT
model_update, snapshots = self.dpldriver.create_cgsnapshot(
model_update, snapshots = self.dpldriver.create_group_snapshot(
self.context, snapshot_obj, [])
self.assertDictEqual({'status': 'available'}, model_update)
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')
def test_delete_consistency_group_snapshot(self, get_all_for_cgsnapshot):
@mock.patch(
'cinder.objects.snapshot.SnapshotList.get_all_for_group_snapshot')
def test_delete_group_snapshot(self, get_all_for_group_snapshot):
group_type = group_types.create(
self.context,
'group',
{'consistent_group_snapshot_enabled': '<is> True'}
)
snapshot_obj = fake_snapshot.fake_snapshot_obj(self.context)
snapshot_obj.consistencygroup_id = \
DATA_IN_CG_SNAPSHOT['consistencygroup_id']
get_all_for_cgsnapshot.return_value = [snapshot_obj]
self.DPL_MOCK.delete_cgsnapshot.return_value = DATA_OUTPUT
model_update, snapshots = self.dpldriver.delete_cgsnapshot(
self.context, DATA_IN_CG_SNAPSHOT, [])
snapshot_obj.group_id = \
DATA_IN_CG_SNAPSHOT['group_id']
snapshot_obj.group_type_id = group_type.id
get_all_for_group_snapshot.return_value = [snapshot_obj]
self.DPL_MOCK.delete_group_snapshot.return_value = DATA_OUTPUT
model_update, snapshots = self.dpldriver.delete_group_snapshot(
self.context, snapshot_obj, [])
self.DPL_MOCK.delete_vdev_snapshot.assert_called_once_with(
self._conver_uuid2hex(DATA_IN_CG_SNAPSHOT['consistencygroup_id']),
self._conver_uuid2hex(DATA_IN_CG_SNAPSHOT['id']),
self._conver_uuid2hex(snapshot_obj.group_id),
self._conver_uuid2hex(snapshot_obj.id),
True)
self.assertDictEqual({'status': 'deleted'}, model_update)

View File

@ -844,44 +844,44 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
def remove_export(self, context, volume):
pass
def create_consistencygroup(self, context, group):
def _create_consistencygroup(self, context, group):
"""Creates a consistencygroup."""
LOG.info('Start to create consistency group: %(group_name)s '
'id: %(id)s',
{'group_name': group['name'], 'id': group['id']})
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
{'group_name': group.name, 'id': group.id})
model_update = {'status': fields.GroupStatus.AVAILABLE}
try:
ret, output = self.dpl.create_vg(
self._conver_uuid2hex(group['id']),
group['name'],
group['description'])
self._conver_uuid2hex(group.id),
group.name,
group.description)
if ret:
msg = _('Failed to create consistency group '
'%(id)s:%(ret)s.') % {'id': group['id'],
'%(id)s:%(ret)s.') % {'id': group.id,
'ret': ret}
raise exception.VolumeBackendAPIException(data=msg)
else:
return model_update
except Exception as e:
msg = _('Failed to create consistency group '
'%(id)s due to %(reason)s.') % {'id': group['id'],
'%(id)s due to %(reason)s.') % {'id': group.id,
'reason': six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
def delete_consistencygroup(self, context, group, volumes):
def _delete_consistencygroup(self, context, group, volumes):
"""Delete a consistency group."""
ret = 0
volumes = self.db.volume_get_all_by_group(
context, group['id'])
context, group.id)
model_update = {}
model_update['status'] = group['status']
model_update['status'] = group.status
LOG.info('Start to delete consistency group: %(cg_name)s',
{'cg_name': group['id']})
{'cg_name': group.id})
try:
self.dpl.delete_vg(self._conver_uuid2hex(group['id']))
self.dpl.delete_vg(self._conver_uuid2hex(group.id))
except Exception as e:
msg = _('Failed to delete consistency group %(id)s '
'due to %(reason)s.') % {'id': group['id'],
'due to %(reason)s.') % {'id': group.id,
'reason': six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
@ -893,31 +893,31 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
ret = errno.EFAULT
volume_ref['status'] = 'error_deleting'
model_update['status'] = (
fields.ConsistencyGroupStatus.ERROR_DELETING)
fields.GroupStatus.ERROR_DELETING)
if ret == 0:
model_update['status'] = fields.ConsistencyGroupStatus.DELETED
model_update['status'] = fields.GroupStatus.DELETED
return model_update, volumes
def create_cgsnapshot(self, context, cgsnapshot, snapshots):
def _create_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Creates a cgsnapshot."""
snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
context, cgsnapshot['id'])
snapshots = objects.SnapshotList().get_all_for_group_snapshot(
context, cgsnapshot.id)
model_update = {}
LOG.info('Start to create cgsnapshot for consistency group'
': %(group_name)s',
{'group_name': cgsnapshot['consistencygroup_id']})
{'group_name': cgsnapshot.group_id})
try:
self.dpl.create_vdev_snapshot(
self._conver_uuid2hex(cgsnapshot['consistencygroup_id']),
self._conver_uuid2hex(cgsnapshot['id']),
cgsnapshot['name'],
cgsnapshot.get('description', ''),
self._conver_uuid2hex(cgsnapshot.group_id),
self._conver_uuid2hex(cgsnapshot.id),
cgsnapshot.name,
'',
True)
for snapshot in snapshots:
snapshot.status = fields.SnapshotStatus.AVAILABLE
except Exception as e:
msg = _('Failed to create cg snapshot %(id)s '
'due to %(reason)s.') % {'id': cgsnapshot['id'],
'due to %(reason)s.') % {'id': cgsnapshot.id,
'reason': six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
@ -925,38 +925,40 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
return model_update, snapshots
def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
def _delete_cgsnapshot(self, context, cgsnapshot, snapshots):
"""Deletes a cgsnapshot."""
snapshots = objects.SnapshotList().get_all_for_cgsnapshot(
context, cgsnapshot['id'])
snapshots = objects.SnapshotList().get_all_for_group_snapshot(
context, cgsnapshot.id)
model_update = {}
model_update['status'] = cgsnapshot['status']
model_update['status'] = cgsnapshot.status
LOG.info('Delete cgsnapshot %(snap_name)s for consistency group: '
'%(group_name)s',
{'snap_name': cgsnapshot['id'],
'group_name': cgsnapshot['consistencygroup_id']})
{'snap_name': cgsnapshot.id,
'group_name': cgsnapshot.group_id})
try:
self.dpl.delete_vdev_snapshot(
self._conver_uuid2hex(cgsnapshot['consistencygroup_id']),
self._conver_uuid2hex(cgsnapshot['id']), True)
self._conver_uuid2hex(cgsnapshot.group_id),
self._conver_uuid2hex(cgsnapshot.id), True)
for snapshot in snapshots:
snapshot.status = fields.SnapshotStatus.DELETED
except Exception as e:
msg = _('Failed to delete cgsnapshot %(id)s due to '
'%(reason)s.') % {'id': cgsnapshot['id'],
'%(reason)s.') % {'id': cgsnapshot.id,
'reason': six.text_type(e)}
raise exception.VolumeBackendAPIException(data=msg)
model_update['status'] = 'deleted'
return model_update, snapshots
def update_consistencygroup(self, context, group, add_volumes=None,
remove_volumes=None):
def update_group(self, context, group, add_volumes=None,
remove_volumes=None):
addvollist = []
removevollist = []
cgid = group['id']
cgid = group.id
vid = ''
model_update = {'status': fields.ConsistencyGroupStatus.AVAILABLE}
model_update = {'status': fields.GroupStatus.AVAILABLE}
if not volume_utils.is_group_a_cg_snapshot_type(group):
raise NotImplementedError()
# Get current group info in backend storage.
ret, output = self.dpl.get_vg(self._conver_uuid2hex(cgid))
if ret == 0:
@ -995,6 +997,33 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
raise exception.VolumeBackendAPIException(data=msg)
return model_update, None, None
def create_group(self, context, group):
if volume_utils.is_group_a_cg_snapshot_type(group):
return self._create_consistencygroup(context, group)
raise NotImplementedError()
def delete_group(self, context, group, volumes):
if volume_utils.is_group_a_cg_snapshot_type(group):
return self._delete_consistencygroup(context, group, volumes)
raise NotImplementedError()
def create_group_snapshot(self, context, group_snapshot, snapshots):
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self._create_cgsnapshot(context, group_snapshot, snapshots)
raise NotImplementedError()
def delete_group_snapshot(self, context, group_snapshot, snapshots):
if volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
return self._delete_cgsnapshot(context, group_snapshot, snapshots)
raise NotImplementedError()
def create_group_from_src(self, context, group, volumes,
group_snapshot=None, snapshots=None,
source_group=None, source_vols=None):
err_msg = _("Prophet Storage doesn't support create_group_from_src.")
LOG.error(err_msg)
raise exception.VolumeBackendAPIException(data=err_msg)
def create_volume(self, volume):
"""Create a volume."""
pool = volume_utils.extract_host(volume['host'],
@ -1039,17 +1068,19 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
LOG.info('Flexvisor succeeded to create volume %(id)s.',
{'id': volume['id']})
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
msg = _('Flexvisor failed to create volume %(id)s in the '
'group %(vgid)s.') % {
'id': volume['id'],
'vgid': volume['consistencygroup_id']}
raise exception.VolumeBackendAPIException(data=msg)
if volume.group_id:
group = volume_utils.group_get_by_id(volume.group_id)
if volume_utils.is_group_a_cg_snapshot_type(group):
try:
self._join_volume_group(volume, volume.group_id)
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
msg = _('Flexvisor failed to create volume %(id)s in the '
'group %(vgid)s.') % {
'id': volume['id'],
'vgid': volume.group_id}
raise exception.VolumeBackendAPIException(data=msg)
def create_volume_from_snapshot(self, volume, snapshot):
"""Creates a volume from a snapshot."""
@ -1059,7 +1090,7 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
snapshotID = snapshot['id']
# Try to get cgid if volume belong in the group.
src_volumeID = snapshot['volume_id']
cgsnapshotID = snapshot.get('cgsnapshot_id', None)
cgsnapshotID = snapshot.get('group_snapshot_id', None)
if cgsnapshotID:
try:
src_volume = self.db.volume_get(src_volumeID)
@ -1068,7 +1099,7 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
"%(id)s info.") % {'id': src_volumeID}
raise exception.VolumeBackendAPIException(data=msg)
if src_volume:
vgID = src_volume.get('consistencygroup_id', None)
vgID = src_volume.group_id
# Get the volume origin snapshot id if the source snapshot is group
# snapshot.
@ -1125,13 +1156,15 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
if volume['size'] > snapshot['volume_size']:
self.extend_volume(volume, volume['size'])
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
raise
if volume.group_id:
group = volume_utils.group_get_by_id(volume.group_id)
if volume_utils.is_group_a_cg_snapshot_type(group):
try:
self._join_volume_group(volume, volume.group_id)
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
raise
def spawn_volume_from_snapshot(self, volume, snapshot):
"""Spawn a REFERENCED volume from a snapshot."""
@ -1213,37 +1246,41 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
LOG.info('Flexvisor succeeded to clone volume %(id)s.',
{'id': volume['id']})
if volume.get('consistencygroup_id', None):
try:
self._join_volume_group(volume, volume['consistencygroup_id'])
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
msg = _('Flexvisor volume %(id)s failed to join group '
'%(vgid)s.') % {'id': volume['id'],
'vgid': volume['consistencygroup_id']}
raise exception.VolumeBackendAPIException(data=msg)
if volume.group_id:
group = volume_utils.group_get_by_id(volume.group_id)
if volume_utils.is_group_a_cg_snapshot_type(group):
try:
self._join_volume_group(volume, volume.group_id)
except Exception:
# Delete volume if volume failed to join group.
self.dpl.delete_vdev(self._conver_uuid2hex(volume['id']))
msg = _('Flexvisor volume %(id)s failed to join group '
'%(vgid)s.') % {'id': volume['id'],
'vgid': volume.group_id}
raise exception.VolumeBackendAPIException(data=msg)
def delete_volume(self, volume):
"""Deletes a volume."""
ret = 0
if volume.get('consistencygroup_id', None):
msg = ''
try:
ret, out = self.dpl.leave_vg(
self._conver_uuid2hex(volume['id']),
self._conver_uuid2hex(volume['consistencygroup_id']))
if ret:
LOG.warning('Flexvisor failed to delete volume '
'%(id)s from the group %(vgid)s.',
if volume.group_id:
group = volume_utils.group_get_by_id(volume.group_id)
if group and volume_utils.is_group_a_cg_snapshot_type(group):
msg = ''
try:
ret, out = self.dpl.leave_vg(
self._conver_uuid2hex(volume['id']),
self._conver_uuid2hex(volume.group_id))
if ret:
LOG.warning('Flexvisor failed to delete volume '
'%(id)s from the group %(vgid)s.',
{'id': volume['id'],
'vgid': volume.group_id})
except Exception as e:
LOG.warning('Flexvisor failed to delete volume %(id)s '
'from group %(vgid)s due to %(status)s.',
{'id': volume['id'],
'vgid': volume['consistencygroup_id']})
except Exception as e:
LOG.warning('Flexvisor failed to delete volume %(id)s '
'from group %(vgid)s due to %(status)s.',
{'id': volume['id'],
'vgid': volume['consistencygroup_id'],
'status': e})
'vgid': volume.group_id,
'status': e})
if ret:
ret = 0
@ -1435,6 +1472,7 @@ class DPLCOMMONDriver(driver.CloneableImageVD,
data['storage_protocol'] = 'iSCSI'
data['location_info'] = location_info
data['consistencygroup_support'] = True
data['consistent_group_snapshot_enabled'] = True
data['pools'] = pools
self._stats = data
except Exception as e:

View File

@ -0,0 +1,3 @@
---
features:
- Added consistent group capability to generic volume groups in ProphetStor driver.