From: Shay Halsband Date: Tue, 3 Nov 2015 14:33:03 +0000 (+0200) Subject: XtremIO fix create CG from src flow X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=a049d759aff309695e8954203394570d5f0dccee;p=openstack-build%2Fcinder-build.git XtremIO fix create CG from src flow Fix a bug during volume creation with CG, that prevented the volume from being added to the CG on the array. Query array snapshots names for CG snapshot before copying them to a new volume. Add unittest for create_cg_from_src. liberty-backport-potential Change-Id: Ieb76cc3e039e4c5495d00a8703c79930bc8b4df1 Closes-Bug: #1512682 --- diff --git a/cinder/tests/unit/test_emc_xtremio.py b/cinder/tests/unit/test_emc_xtremio.py index b03deccb1..2486843c9 100644 --- a/cinder/tests/unit/test_emc_xtremio.py +++ b/cinder/tests/unit/test_emc_xtremio.py @@ -17,7 +17,9 @@ import mock from cinder import exception from cinder import test +from cinder.tests.unit import fake_consistencygroup as fake_cg from cinder.tests.unit import fake_snapshot +from cinder.tests.unit import fake_volume from cinder.volume.drivers.emc import xtremio @@ -465,15 +467,52 @@ class EMCXIODriverISCSITestCase(test.TestCase): (self.driver.db. volume_get_all_by_group.return_value) = [mock.MagicMock()] self.driver.create_cgsnapshot(d.context, d.cgsnapshot) - snaps_name = self.driver._get_cgsnap_name(d.cgsnapshot) - snaps = xms_data['volumes'][1] - snaps['index'] = 1 - xms_data['snapshot-sets'] = {snaps_name: snaps, 1: snaps} + snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot) + self.assertEqual(snapset_name, + '192eb39b6c2f420cbae33cfd117f0345192eb39b6c2f420cbae' + '33cfd117f9876') + snapset1 = {'ancestor-vol-id': ['', d.test_volume['id'], 2], + 'consistencygroup_id': d.group['id'], + 'name': snapset_name, + 'index': 1} + xms_data['snapshot-sets'] = {snapset_name: snapset1, 1: snapset1} + self.driver.delete_cgsnapshot(d.context, d.cgsnapshot) + self.driver.delete_consistencygroup(d.context, d.group) + xms_data['snapshot-sets'] = {} + + @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot') + def test_cg_from_src(self, get_all_for_cgsnapshot, req): + req.side_effect = xms_request + d = self.data + self.assertRaises(exception.InvalidInput, self.driver.create_consistencygroup_from_src, d.context, d.group, [], None, None, None, None) - self.driver.delete_cgsnapshot(d.context, d.cgsnapshot) - self.driver.delete_consistencygroup(d.context, d.group) + + snapshot_obj = fake_snapshot.fake_snapshot_obj(d.context) + snapshot_obj.consistencygroup_id = d.group['id'] + snapshot_obj.volume_id = d.test_volume['id'] + get_all_for_cgsnapshot.return_value = [snapshot_obj] + + self.driver.create_consistencygroup(d.context, d.group) + self.driver.create_volume(d.test_volume) + self.driver.create_cgsnapshot(d.context, d.cgsnapshot) + xms_data['volumes'][2]['ancestor-vol-id'] = (xms_data['volumes'][1] + ['vol-id']) + snapset_name = self.driver._get_cgsnap_name(d.cgsnapshot) + + snapset1 = {'vol-list': [xms_data['volumes'][2]['vol-id']], + 'name': snapset_name, + 'index': 1} + xms_data['snapshot-sets'] = {snapset_name: snapset1, 1: snapset1} + cg_obj = fake_cg.fake_consistencyobject_obj(d.context) + new_vol1 = fake_volume.fake_volume_obj(d.context) + snapshot1 = (fake_snapshot + .fake_snapshot_obj + (d.context, volume_id=d.test_volume['id'])) + self.driver.create_consistencygroup_from_src(d.context, cg_obj, + [new_vol1], + d.cgsnapshot, [snapshot1]) @mock.patch('requests.request') diff --git a/cinder/volume/drivers/emc/xtremio.py b/cinder/volume/drivers/emc/xtremio.py index 21fd2a151..a147d8c8b 100644 --- a/cinder/volume/drivers/emc/xtremio.py +++ b/cinder/volume/drivers/emc/xtremio.py @@ -70,6 +70,9 @@ VOL_OBJ_NOT_FOUND_ERR = 'vol_obj_not_found' ALREADY_MAPPED_ERR = 'already_mapped' SYSTEM_BUSY = 'system_is_busy' +XTREMIO_OID_NAME = 1 +XTREMIO_OID_INDEX = 2 + class XtremIOClient(object): def __init__(self, configuration, cluster_id): @@ -184,6 +187,9 @@ class XtremIOClient(object): def get_initiator(self, port_address): raise NotImplementedError() + def add_vol_to_cg(self, vol_id, cg_id): + pass + class XtremIOClient3(XtremIOClient): def __init__(self, configuration, cluster_id): @@ -367,15 +373,23 @@ class XtremIOVolumeDriver(san.SanDriver): } self.client.req('volumes', 'POST', data) - if volume.get('consistencygroup_id') and self.client is XtremIOClient4: + if volume.get('consistencygroup_id'): self.client.add_vol_to_cg(volume['id'], volume['consistencygroup_id']) def create_volume_from_snapshot(self, volume, snapshot): """Creates a volume from a snapshot.""" - self.client.create_snapshot(snapshot.id, volume['id']) + if snapshot.get('cgsnapshot_id'): + # get array snapshot id from CG snapshot + snap_by_anc = self.get_snapset_ancestors(snapshot.cgsnapshot) + snapshot_id = snap_by_anc[snapshot['volume_id']] + else: + snapshot_id = snapshot['id'] - if (snapshot.get('consistencygroup_id') and + self.client.create_snapshot(snapshot_id, volume['id']) + + # add new volume to consistency group + if (volume.get('consistencygroup_id') and self.client is XtremIOClient4): self.client.add_vol_to_cg(volume['id'], snapshot['consistencygroup_id']) @@ -566,6 +580,18 @@ class XtremIOVolumeDriver(san.SanDriver): return model_update, volumes + def get_snapset_ancestors(self, cgsnapshot): + snapset_name = self._get_cgsnap_name(cgsnapshot) + snapset = self.client.req('snapshot-sets', + name=snapset_name)['content'] + volume_ids = [s[XTREMIO_OID_INDEX] for s in snapset['vol-list']] + return {v['ancestor-vol-id'][XTREMIO_OID_NAME]: v['name'] for v + in self.client.req('volumes', + data={'full': 1, + 'props': + 'ancestor-vol-id'})['volumes'] + if v['index'] in volume_ids} + def create_consistencygroup_from_src(self, context, group, volumes, cgsnapshot=None, snapshots=None, source_cg=None, source_vols=None): @@ -579,8 +605,10 @@ class XtremIOVolumeDriver(san.SanDriver): :return model_update, volumes_model_update """ if cgsnapshot and snapshots: + snap_by_anc = self.get_snapset_ancestors(cgsnapshot) for volume, snapshot in zip(volumes, snapshots): - self.create_volume_from_snapshot(volume, snapshot) + real_snap = snap_by_anc[snapshot['volume_id']] + self.create_volume_from_snapshot(volume, {'id': real_snap}) create_data = {'consistency-group-name': group['id'], 'vol-list': [v['id'] for v in volumes]} self.client.req('consistency-groups', 'POST', data=create_data, @@ -726,7 +754,7 @@ class XtremIOISCSIDriver(XtremIOVolumeDriver, driver.ISCSIDriver): if initiator: login_passwd = initiator['chap-authentication-initiator-password'] discovery_passwd = initiator['chap-discovery-initiator-password'] - ig = self._get_ig(initiator['ig-id'][1]) + ig = self._get_ig(initiator['ig-id'][XTREMIO_OID_NAME]) else: ig = self._get_ig(self._get_ig_name(connector)) if not ig: @@ -748,7 +776,7 @@ class XtremIOISCSIDriver(XtremIOVolumeDriver, driver.ISCSIDriver): self.client.req('initiators', 'PUT', data, idx=initiator['index']) # lun mappping - lunmap = self.create_lun_map(volume, ig['ig-id'][1]) + lunmap = self.create_lun_map(volume, ig['ig-id'][XTREMIO_OID_NAME]) properties = self._get_iscsi_properties(lunmap) @@ -839,6 +867,18 @@ class XtremIOFibreChannelDriver(XtremIOVolumeDriver, (data=_("Failed to get targets"))) return self._targets + def _get_free_lun(self, igs): + luns = [] + for ig in igs: + luns.extend(lm['lun'] for lm in + self.client.req('lun-maps', + data={'full': 1, 'prop': 'lun', + 'filter': 'ig-name:eq:%s' % ig}) + ['lun-maps']) + uniq_luns = set(luns + [0]) + seq = range(len(uniq_luns) + 1) + return min(set(seq) - uniq_luns) + @fczm_utils.AddFCZone def initialize_connection(self, volume, connector): wwpns = self._get_initiator_name(connector) @@ -862,9 +902,13 @@ class XtremIOFibreChannelDriver(XtremIOVolumeDriver, data = {'initiator-name': wwpn, 'ig-id': ig_name, 'port-address': wwpn} self.client.req('initiators', 'POST', data) - igs = list(set([i['ig-id'][1] for i in found] + [ig_name])) + igs = list(set([i['ig-id'][XTREMIO_OID_NAME] + for i in found] + [ig_name])) - lun_num = None + if len(igs) > 1: + lun_num = self._get_free_lun(igs) + else: + lun_num = None for ig in igs: lunmap = self.create_lun_map(volume, ig, lun_num) lun_num = lunmap['lun']