Merge "Fix Infinidat driver consistency groups feature"
This commit is contained in:
commit
4c9b76b937
@ -59,15 +59,19 @@ TEST_SNAPSHOT_SOURCE_ID = 67890
|
|||||||
TEST_SNAPSHOT_METADATA = {'cinder_id': fake.SNAPSHOT_ID}
|
TEST_SNAPSHOT_METADATA = {'cinder_id': fake.SNAPSHOT_ID}
|
||||||
|
|
||||||
test_volume = mock.Mock(id=fake.VOLUME_ID, name_id=fake.VOLUME_ID, size=1,
|
test_volume = mock.Mock(id=fake.VOLUME_ID, name_id=fake.VOLUME_ID, size=1,
|
||||||
volume_type_id=fake.VOLUME_TYPE_ID,
|
volume_type_id=fake.VOLUME_TYPE_ID, group_id=None,
|
||||||
multiattach=False, volume_attachment=None)
|
multiattach=False, volume_attachment=None)
|
||||||
test_volume2 = mock.Mock(id=fake.VOLUME2_ID, name_id=fake.VOLUME2_ID, size=1,
|
test_volume2 = mock.Mock(id=fake.VOLUME2_ID, name_id=fake.VOLUME2_ID, size=1,
|
||||||
volume_type_id=fake.VOLUME_TYPE_ID,
|
volume_type_id=None, group_id=None,
|
||||||
multiattach=False, volume_attachment=None)
|
multiattach=False, volume_attachment=None)
|
||||||
test_snapshot = mock.Mock(id=fake.SNAPSHOT_ID, volume=test_volume,
|
test_volume3 = mock.Mock(id=fake.VOLUME3_ID, name_id=fake.VOLUME3_ID, size=1,
|
||||||
volume_id=test_volume.id)
|
volume_type_id=fake.VOLUME_TYPE_ID,
|
||||||
test_clone = mock.Mock(id=fake.VOLUME4_ID, size=1, multiattach=False,
|
group_id=fake.GROUP_ID, multiattach=True,
|
||||||
volume_attachment=None)
|
volume_attachment=None)
|
||||||
|
test_snapshot = mock.Mock(id=fake.SNAPSHOT_ID, volume=test_volume)
|
||||||
|
test_clone = mock.Mock(id=fake.VOLUME4_ID, name_id=fake.VOLUME4_ID, size=1,
|
||||||
|
volume_type_id=fake.VOLUME_TYPE_ID, group_id=None,
|
||||||
|
multiattach=False, volume_attachment=None)
|
||||||
test_group = mock.Mock(id=fake.GROUP_ID)
|
test_group = mock.Mock(id=fake.GROUP_ID)
|
||||||
test_snapgroup = mock.Mock(id=fake.GROUP_SNAPSHOT_ID, group=test_group)
|
test_snapgroup = mock.Mock(id=fake.GROUP_SNAPSHOT_ID, group=test_group)
|
||||||
test_connector = dict(wwpns=[TEST_WWN_1],
|
test_connector = dict(wwpns=[TEST_WWN_1],
|
||||||
@ -145,6 +149,7 @@ class InfiniboxDriverTestCaseBase(test.TestCase):
|
|||||||
self._mock_volume.get_all_metadata.return_value = {}
|
self._mock_volume.get_all_metadata.return_value = {}
|
||||||
self._mock_volume.create_snapshot.return_value = self._mock_volume
|
self._mock_volume.create_snapshot.return_value = self._mock_volume
|
||||||
self._mock_snapshot = mock.Mock()
|
self._mock_snapshot = mock.Mock()
|
||||||
|
self._mock_snapshot.get_parent.return_value = self._mock_volume
|
||||||
self._mock_host = mock.Mock()
|
self._mock_host = mock.Mock()
|
||||||
self._mock_host.get_luns.return_value = []
|
self._mock_host.get_luns.return_value = []
|
||||||
self._mock_host.map_volume().get_lun.return_value = TEST_LUN
|
self._mock_host.map_volume().get_lun.return_value = TEST_LUN
|
||||||
@ -389,6 +394,22 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
self._system.volumes.create.call_args[1]
|
self._system.volumes.create.call_args[1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs')
|
||||||
|
@mock.patch('cinder.volume.volume_utils.group_get_by_id')
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=True)
|
||||||
|
def test_create_volume_within_group(self, *mocks):
|
||||||
|
self.driver.create_volume(test_volume3)
|
||||||
|
self._mock_group.add_member.assert_called_once()
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_types.get_volume_type_qos_specs')
|
||||||
|
@mock.patch('cinder.volume.volume_utils.group_get_by_id')
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_create_volume_within_no_cg_group(self, *mocks):
|
||||||
|
self.driver.create_volume(test_volume3)
|
||||||
|
self._mock_group.add_member.assert_not_called()
|
||||||
|
|
||||||
def test_delete_volume(self):
|
def test_delete_volume(self):
|
||||||
self.driver.delete_volume(test_volume)
|
self.driver.delete_volume(test_volume)
|
||||||
|
|
||||||
@ -517,6 +538,13 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
def test_create_group(self, *mocks):
|
def test_create_group(self, *mocks):
|
||||||
self.driver.create_group(None, test_group)
|
self.driver.create_group(None, test_group)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_create_generic_group(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.create_group,
|
||||||
|
None, test_group)
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
def test_create_group_metadata(self, *mocks):
|
def test_create_group_metadata(self, *mocks):
|
||||||
@ -542,6 +570,13 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
def test_delete_group(self, *mocks):
|
def test_delete_group(self, *mocks):
|
||||||
self.driver.delete_group(None, test_group, [test_volume])
|
self.driver.delete_group(None, test_group, [test_volume])
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_delete_generic_group(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.delete_group,
|
||||||
|
None, test_group, [test_volume])
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
def test_delete_group_doesnt_exist(self, *mocks):
|
def test_delete_group_doesnt_exist(self, *mocks):
|
||||||
@ -562,6 +597,13 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
self.driver.update_group(None, test_group,
|
self.driver.update_group(None, test_group,
|
||||||
[test_volume], [test_volume])
|
[test_volume], [test_volume])
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_update_generic_group_add_and_remove(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.update_group,
|
||||||
|
None, test_group, [test_volume], [test_volume])
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
def test_update_group_api_fail(self, *mocks):
|
def test_update_group_api_fail(self, *mocks):
|
||||||
@ -583,6 +625,23 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
test_snapgroup, [test_snapshot],
|
test_snapgroup, [test_snapshot],
|
||||||
None, None)
|
None, None)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_create_genericgroup_from_src_snaps(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.create_group_from_src,
|
||||||
|
None, test_group, [test_volume],
|
||||||
|
test_snapgroup, [test_snapshot],
|
||||||
|
None, None)
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=True)
|
||||||
|
def test_create_group_from_empty_sources(self, *mocks):
|
||||||
|
self.assertRaises(exception.InvalidInput,
|
||||||
|
self.driver.create_group_from_src,
|
||||||
|
None, test_group, [test_volume],
|
||||||
|
None, None, None, None)
|
||||||
|
|
||||||
@mock.patch("cinder.volume.volume_utils.copy_volume")
|
@mock.patch("cinder.volume.volume_utils.copy_volume")
|
||||||
@mock.patch("cinder.volume.volume_utils.brick_get_connector")
|
@mock.patch("cinder.volume.volume_utils.brick_get_connector")
|
||||||
@mock.patch("cinder.volume.volume_utils.brick_get_connector_properties",
|
@mock.patch("cinder.volume.volume_utils.brick_get_connector_properties",
|
||||||
@ -599,13 +658,20 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
return_value=True)
|
return_value=True)
|
||||||
def test_create_group_snap(self, *mocks):
|
def test_create_group_snap(self, *mocks):
|
||||||
mock_snapgroup = mock.Mock()
|
mock_snapgroup = mock.Mock()
|
||||||
mock_snapgroup.get_members.return_value = [self._mock_volume]
|
mock_snapgroup.get_members.return_value = [self._mock_snapshot,
|
||||||
self._mock_volume.get_parent.return_value = self._mock_volume
|
self._mock_snapshot]
|
||||||
self._mock_volume.get_name.return_value = ''
|
self._mock_volume.get_name.side_effect = [fake.VOLUME_NAME,
|
||||||
|
fake.VOLUME2_NAME]
|
||||||
self._mock_group.create_snapshot.return_value = mock_snapgroup
|
self._mock_group.create_snapshot.return_value = mock_snapgroup
|
||||||
self.driver.create_group_snapshot(None,
|
self.driver.create_group_snapshot(None, test_snapgroup,
|
||||||
test_snapgroup,
|
[test_snapshot, test_snapshot])
|
||||||
[test_snapshot])
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_create_generic_group_snap(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.create_group_snapshot,
|
||||||
|
None, test_snapgroup, [test_snapshot])
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
@ -622,6 +688,13 @@ class InfiniboxDriverTestCase(InfiniboxDriverTestCaseBase):
|
|||||||
test_snapgroup,
|
test_snapgroup,
|
||||||
[test_snapshot])
|
[test_snapshot])
|
||||||
|
|
||||||
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
|
return_value=False)
|
||||||
|
def test_delete_generic_group_snap(self, *mocks):
|
||||||
|
self.assertRaises(NotImplementedError,
|
||||||
|
self.driver.delete_group_snapshot,
|
||||||
|
None, test_snapgroup, [test_snapshot])
|
||||||
|
|
||||||
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
@mock.patch('cinder.volume.volume_utils.is_group_a_cg_snapshot_type',
|
||||||
return_value=True)
|
return_value=True)
|
||||||
def test_delete_group_snap_does_not_exist(self, *mocks):
|
def test_delete_group_snap_does_not_exist(self, *mocks):
|
||||||
@ -1258,8 +1331,7 @@ class InfiniboxDriverTestCaseQoS(InfiniboxDriverTestCaseBase):
|
|||||||
'consumer': 'back-end',
|
'consumer': 'back-end',
|
||||||
'specs': {'maxIOPS': 1000,
|
'specs': {'maxIOPS': 1000,
|
||||||
'maxBWS': 10000}}}
|
'maxBWS': 10000}}}
|
||||||
test_volume = mock.Mock(id=1, size=1, volume_type_id=None)
|
self.driver.create_volume(test_volume2)
|
||||||
self.driver.create_volume(test_volume)
|
|
||||||
self._system.qos_policies.create.assert_not_called()
|
self._system.qos_policies.create.assert_not_called()
|
||||||
self._mock_qos_policy.assign_entity.assert_not_called()
|
self._mock_qos_policy.assign_entity.assert_not_called()
|
||||||
|
|
||||||
|
@ -127,10 +127,11 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
1.10 - added support for TLS/SSL communication
|
1.10 - added support for TLS/SSL communication
|
||||||
1.11 - fixed generic volume migration
|
1.11 - fixed generic volume migration
|
||||||
1.12 - fixed volume multi-attach
|
1.12 - fixed volume multi-attach
|
||||||
|
1.13 - fixed consistency groups feature
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
VERSION = '1.12'
|
VERSION = '1.13'
|
||||||
|
|
||||||
# ThirdPartySystems wiki page
|
# ThirdPartySystems wiki page
|
||||||
CI_WIKI_NAME = "INFINIDAT_CI"
|
CI_WIKI_NAME = "INFINIDAT_CI"
|
||||||
@ -304,6 +305,18 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
raise exception.GroupNotFound(group_id=group_name)
|
raise exception.GroupNotFound(group_id=group_name)
|
||||||
return infinidat_cg
|
return infinidat_cg
|
||||||
|
|
||||||
|
def _get_infinidat_sg(self, group_snapshot):
|
||||||
|
name = self._make_group_snapshot_name(group_snapshot)
|
||||||
|
infinidat_sg = self._system.cons_groups.safe_get(name=name)
|
||||||
|
if infinidat_sg is None:
|
||||||
|
raise exception.GroupSnapshotNotFound(
|
||||||
|
group_snapshot_id=group_snapshot.id)
|
||||||
|
if not infinidat_sg.is_snapgroup():
|
||||||
|
reason = (_('consistency group "%s" is not a snapshot group')
|
||||||
|
% name)
|
||||||
|
raise exception.InvalidGroupSnapshot(reason=reason)
|
||||||
|
return infinidat_sg
|
||||||
|
|
||||||
def _get_or_create_host(self, port):
|
def _get_or_create_host(self, port):
|
||||||
host_name = self._make_host_name(port)
|
host_name = self._make_host_name(port)
|
||||||
infinidat_host = self._system.hosts.safe_get(name=host_name)
|
infinidat_host = self._system.hosts.safe_get(name=host_name)
|
||||||
@ -600,6 +613,11 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
infinidat_volume = self._system.volumes.create(**create_kwargs)
|
infinidat_volume = self._system.volumes.create(**create_kwargs)
|
||||||
self._set_qos(volume, infinidat_volume)
|
self._set_qos(volume, infinidat_volume)
|
||||||
self._set_cinder_object_metadata(infinidat_volume, volume)
|
self._set_cinder_object_metadata(infinidat_volume, volume)
|
||||||
|
if volume.group_id:
|
||||||
|
group = volume_utils.group_get_by_id(volume.group_id)
|
||||||
|
if volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
|
infinidat_group = self._get_infinidat_cg(group)
|
||||||
|
infinidat_group.add_member(infinidat_volume)
|
||||||
return infinidat_volume
|
return infinidat_volume
|
||||||
|
|
||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
@ -797,18 +815,30 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
|
|
||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
def create_group(self, context, group):
|
def create_group(self, context, group):
|
||||||
"""Creates a group."""
|
"""Creates a group.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group: the Group object of the group to be created.
|
||||||
|
:returns: model_update
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
obj = self._system.cons_groups.create(name=self._make_cg_name(group),
|
name = self._make_cg_name(group)
|
||||||
pool=self._get_infinidat_pool())
|
pool = self._get_infinidat_pool()
|
||||||
self._set_cinder_object_metadata(obj, group)
|
infinidat_cg = self._system.cons_groups.create(name=name, pool=pool)
|
||||||
|
self._set_cinder_object_metadata(infinidat_cg, group)
|
||||||
return {'status': fields.GroupStatus.AVAILABLE}
|
return {'status': fields.GroupStatus.AVAILABLE}
|
||||||
|
|
||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
def delete_group(self, context, group, volumes):
|
def delete_group(self, context, group, volumes):
|
||||||
"""Deletes a group."""
|
"""Deletes a group.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group: the Group object of the group to be deleted.
|
||||||
|
:param volumes: a list of Volume objects in the group.
|
||||||
|
:returns: model_update, volumes_model_update
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
@ -825,18 +855,25 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
def update_group(self, context, group,
|
def update_group(self, context, group,
|
||||||
add_volumes=None, remove_volumes=None):
|
add_volumes=None, remove_volumes=None):
|
||||||
"""Updates a group."""
|
"""Updates a group.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group: the Group object of the group to be updated.
|
||||||
|
:param add_volumes: a list of Volume objects to be added.
|
||||||
|
:param remove_volumes: a list of Volume objects to be removed.
|
||||||
|
:returns: model_update, add_volumes_update, remove_volumes_update
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
add_volumes = add_volumes if add_volumes else []
|
add_volumes = add_volumes if add_volumes else []
|
||||||
remove_volumes = remove_volumes if remove_volumes else []
|
remove_volumes = remove_volumes if remove_volumes else []
|
||||||
infinidat_cg = self._get_infinidat_cg(group)
|
infinidat_cg = self._get_infinidat_cg(group)
|
||||||
for vol in add_volumes:
|
for volume in add_volumes:
|
||||||
infinidat_volume = self._get_infinidat_volume(vol)
|
infinidat_volume = self._get_infinidat_volume(volume)
|
||||||
infinidat_cg.add_member(infinidat_volume)
|
infinidat_cg.add_member(infinidat_volume)
|
||||||
for vol in remove_volumes:
|
for volume in remove_volumes:
|
||||||
infinidat_volume = self._get_infinidat_volume(vol)
|
infinidat_volume = self._get_infinidat_volume(volume)
|
||||||
infinidat_cg.remove_member(infinidat_volume)
|
infinidat_cg.remove_member(infinidat_volume)
|
||||||
return None, None, None
|
return None, None, None
|
||||||
|
|
||||||
@ -844,62 +881,78 @@ class InfiniboxVolumeDriver(san.SanISCSIDriver):
|
|||||||
def create_group_from_src(self, context, group, volumes,
|
def create_group_from_src(self, context, group, volumes,
|
||||||
group_snapshot=None, snapshots=None,
|
group_snapshot=None, snapshots=None,
|
||||||
source_group=None, source_vols=None):
|
source_group=None, source_vols=None):
|
||||||
"""Creates a group from source."""
|
"""Creates a group from source.
|
||||||
# The source is either group_snapshot+snapshots or
|
|
||||||
# source_group+source_vols. The target is group+volumes
|
|
||||||
# we assume the source (source_vols / snapshots) are in the same
|
|
||||||
# order as the target (volumes)
|
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group: the Group object to be created.
|
||||||
|
:param volumes: a list of Volume objects in the group.
|
||||||
|
:param group_snapshot: the GroupSnapshot object as source.
|
||||||
|
:param snapshots: a list of Snapshot objects in group_snapshot.
|
||||||
|
:param source_group: the Group object as source.
|
||||||
|
:param source_vols: a list of Volume objects in the source_group.
|
||||||
|
:returns: model_update, volumes_model_update
|
||||||
|
|
||||||
|
The source can be group_snapshot or a source_group.
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
if not volume_utils.is_group_a_cg_snapshot_type(group):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
self.create_group(context, group)
|
self.create_group(context, group)
|
||||||
new_infinidat_group = self._get_infinidat_cg(group)
|
if group_snapshot and snapshots:
|
||||||
if group_snapshot is not None and snapshots is not None:
|
|
||||||
for volume, snapshot in zip(volumes, snapshots):
|
for volume, snapshot in zip(volumes, snapshots):
|
||||||
self.create_volume_from_snapshot(volume, snapshot)
|
self.create_volume_from_snapshot(volume, snapshot)
|
||||||
new_infinidat_volume = self._get_infinidat_volume(volume)
|
elif source_group and source_vols:
|
||||||
new_infinidat_group.add_member(new_infinidat_volume)
|
for volume, source_vol in zip(volumes, source_vols):
|
||||||
elif source_group is not None and source_vols is not None:
|
self.create_cloned_volume(volume, source_vol)
|
||||||
for volume, src_vol in zip(volumes, source_vols):
|
else:
|
||||||
self.create_cloned_volume(volume, src_vol)
|
message = _('creating a group from source is possible '
|
||||||
new_infinidat_volume = self._get_infinidat_volume(volume)
|
'from an existing group or a group snapshot.')
|
||||||
new_infinidat_group.add_member(new_infinidat_volume)
|
raise exception.InvalidInput(message=message)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
def create_group_snapshot(self, context, group_snapshot, snapshots):
|
def create_group_snapshot(self, context, group_snapshot, snapshots):
|
||||||
"""Creates a group_snapshot."""
|
"""Creates a group_snapshot.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group_snapshot: the GroupSnapshot object to be created.
|
||||||
|
:param snapshots: a list of Snapshot objects in the group_snapshot.
|
||||||
|
:returns: model_update, snapshots_model_update
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
|
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
infinidat_cg = self._get_infinidat_cg(group_snapshot.group)
|
infinidat_cg = self._get_infinidat_cg(group_snapshot.group)
|
||||||
group_snap_name = self._make_group_snapshot_name(group_snapshot)
|
group_snapshot_name = self._make_group_snapshot_name(group_snapshot)
|
||||||
new_group = infinidat_cg.create_snapshot(name=group_snap_name)
|
infinidat_sg = infinidat_cg.create_snapshot(name=group_snapshot_name)
|
||||||
# update the names of the individual snapshots in the new snapgroup
|
# update the names of the individual snapshots in the new snapgroup
|
||||||
# to match the names we use for cinder snapshots
|
# to match the names we use for cinder snapshots
|
||||||
for infinidat_snapshot in new_group.get_members():
|
for infinidat_snapshot in infinidat_sg.get_members():
|
||||||
parent_name = infinidat_snapshot.get_parent().get_name()
|
parent_name = infinidat_snapshot.get_parent().get_name()
|
||||||
for cinder_snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
if cinder_snapshot.volume_id in parent_name:
|
if snapshot.volume.name_id in parent_name:
|
||||||
snapshot_name = self._make_snapshot_name(cinder_snapshot)
|
snapshot_name = self._make_snapshot_name(snapshot)
|
||||||
infinidat_snapshot.update_name(snapshot_name)
|
infinidat_snapshot.update_name(snapshot_name)
|
||||||
return None, None
|
return None, None
|
||||||
|
|
||||||
@infinisdk_to_cinder_exceptions
|
@infinisdk_to_cinder_exceptions
|
||||||
def delete_group_snapshot(self, context, group_snapshot, snapshots):
|
def delete_group_snapshot(self, context, group_snapshot, snapshots):
|
||||||
"""Deletes a group_snapshot."""
|
"""Deletes a group_snapshot.
|
||||||
|
|
||||||
|
:param context: the context of the caller.
|
||||||
|
:param group_snapshot: the GroupSnapshot object to be deleted.
|
||||||
|
:param snapshots: a list of Snapshot objects in the group_snapshot.
|
||||||
|
:returns: model_update, snapshots_model_update
|
||||||
|
"""
|
||||||
# let generic volume group support handle non-cgsnapshots
|
# let generic volume group support handle non-cgsnapshots
|
||||||
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
|
if not volume_utils.is_group_a_cg_snapshot_type(group_snapshot):
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
cgsnap_name = self._make_group_snapshot_name(group_snapshot)
|
try:
|
||||||
infinidat_cgsnap = self._system.cons_groups.safe_get(name=cgsnap_name)
|
infinidat_sg = self._get_infinidat_sg(group_snapshot)
|
||||||
if infinidat_cgsnap is not None:
|
except exception.GroupSnapshotNotFound:
|
||||||
if not infinidat_cgsnap.is_snapgroup():
|
pass
|
||||||
msg = _('Group "%s" is not a snapshot group') % cgsnap_name
|
else:
|
||||||
LOG.error(msg)
|
infinidat_sg.safe_delete()
|
||||||
raise exception.InvalidGroupSnapshot(message=msg)
|
|
||||||
infinidat_cgsnap.safe_delete()
|
|
||||||
for snapshot in snapshots:
|
for snapshot in snapshots:
|
||||||
self.delete_snapshot(snapshot)
|
self.delete_snapshot(snapshot)
|
||||||
return None, None
|
return None, None
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
fixes:
|
||||||
|
- |
|
||||||
|
Infinidat Driver `bug #1984000
|
||||||
|
<https://bugs.launchpad.net/cinder/+bug/1984000>`_:
|
||||||
|
Fixed Infinidat driver to take into account the group
|
||||||
|
identifier property when creating a new volume and
|
||||||
|
add the volume to the consistency group.
|
Loading…
Reference in New Issue
Block a user