]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
XtremIO fix create CG from src flow
authorShay Halsband <shay.halsband@emc.com>
Tue, 3 Nov 2015 14:33:03 +0000 (16:33 +0200)
committerShay Halsband <shay.halsband@emc.com>
Sun, 8 Nov 2015 10:00:40 +0000 (12:00 +0200)
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

cinder/tests/unit/test_emc_xtremio.py
cinder/volume/drivers/emc/xtremio.py

index b03deccb185d672f36208c9769f6e4f85efe05c9..2486843c97ca884e0e8ed29e5c62f2540a0e7bcb 100644 (file)
@@ -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')
index 21fd2a151702c35c0bf1cf14c67ebaf189f3253b..a147d8c8becd67b00f6675c615f0b2e43171fd26 100644 (file)
@@ -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']