]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add a FakeGateDriver
authorXing Yang <xing.yang@emc.com>
Thu, 12 Nov 2015 01:19:53 +0000 (20:19 -0500)
committerXing Yang <xing.yang@emc.com>
Wed, 18 Nov 2015 11:47:29 +0000 (06:47 -0500)
Currently there are a few features that do not have a reference
implementation. These features include Consistency Group (CG),
replication, etc. As a result, any changes to CG and replication
cannot be easily tested. For example, when CG was converted to
versioned objects, developers who were working on the conversion
could not test CG functionality because LVM does not support it.

This patch will add a FakeGateDriver to fake_driver.py under
tests/unit. This driver will inherit from the LVM driver and
implement functions for CG, replication, etc for testing
purpose only. This allows developers who do not have access to
a backend that supports these features to do some sanity testing
using the fake driver.

Related to this, tempest tests are submitted for CG APIs so that
third party CI can run them for drivers with CG support:
https://review.openstack.org/#/c/252213/

Implements: blueprint gate-driver
Change-Id: I1d5868a72741b80069656efc957cfb492889b36c

cinder/tests/unit/fake_driver.py

index e0221702bcb450dfd3f086ee1f432ca03a507abc..e13275acfe91d63477bc8525ff3c21114d2827eb 100644 (file)
@@ -12,6 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_utils import timeutils
+
+from cinder import exception
 from cinder.tests.unit.brick import fake_lvm
 from cinder.volume import driver
 from cinder.volume.drivers import lvm
@@ -191,3 +194,150 @@ class LoggingVolumeDriver(driver.VolumeDriver):
             if match:
                 matches.append(entry)
         return matches
+
+
+class FakeGateDriver(lvm.LVMVolumeDriver):
+    """Class designation for FakeGateDriver.
+
+    FakeGateDriver is for TESTING ONLY. There are a few
+    driver features such as CG and replication that are not
+    supported by the reference driver LVM currently. Adding
+    those functions in this fake driver will help detect
+    problems when changes are introduced in those functions.
+
+    Implementation of this driver is NOT meant for production.
+    They are implemented simply to make sure calls to the driver
+    functions are passing in the correct parameters, and the
+    results returned by the driver are handled properly by the manager.
+
+    """
+    def __init__(self, *args, **kwargs):
+        super(FakeGateDriver, self).__init__(*args, **kwargs)
+
+    def _update_volume_stats(self):
+        super(FakeGateDriver, self)._update_volume_stats()
+        self._stats["pools"][0]["consistencygroup_support"] = True
+        self._stats["pools"][0]["replication_enabled"] = True
+
+    # NOTE(xyang): Consistency Group functions implemented below
+    # are for testing purpose only. Data consistency cannot be
+    # achieved by running these functions.
+    def create_consistencygroup(self, context, group):
+        """Creates a consistencygroup."""
+        # A consistencygroup entry is already created in db
+        # This driver just returns a status
+        now = timeutils.utcnow()
+        model_update = {'status': 'available', 'updated_at': now}
+
+        return model_update
+
+    def create_consistencygroup_from_src(self, context, group, volumes,
+                                         cgsnapshot=None, snapshots=None,
+                                         soure_cg=None, source_vols=None):
+        """Creates a consistencygroup from cgsnapshot or source cg."""
+        for vol in volumes:
+            try:
+                if snapshots:
+                    for snapshot in snapshots:
+                        if vol['snapshot_id'] == snapshot['id']:
+                            self.create_volume_from_snapshot(vol, snapshot)
+                            break
+            except Exception:
+                raise
+            try:
+                if source_vols:
+                    for source_vol in source_vols:
+                        if vol['source_volid'] == source_vol['id']:
+                            self.create_cloned_volume(vol, source_vol)
+                            break
+            except Exception:
+                raise
+        return None, None
+
+    def delete_consistencygroup(self, context, group, volumes):
+        """Deletes a consistencygroup and volumes in the group."""
+        model_update = {'status': group.status}
+        volume_model_updates = []
+        for volume_ref in volumes:
+            volume_model_update = {'id': volume_ref.id}
+            try:
+                self.remove_export(context, volume_ref)
+                self.delete_volume(volume_ref)
+                volume_model_update['status'] = 'deleted'
+            except exception.VolumeIsBusy:
+                volume_model_update['status'] = 'available'
+            except Exception:
+                volume_model_update['status'] = 'error'
+                model_update['status'] = 'error'
+            volume_model_updates.append(volume_model_update)
+
+        return model_update, volume_model_updates
+
+    def update_consistencygroup(self, context, group,
+                                add_volumes=None, remove_volumes=None):
+        """Updates a consistency group."""
+        return None, None, None
+
+    def create_cgsnapshot(self, context, cgsnapshot, snapshots):
+        """Creates a cgsnapshot.
+
+        Snapshots created here are NOT consistent. This is for
+        testing purpose only.
+        """
+        model_update = {'status': 'available'}
+        snapshot_model_updates = []
+        for snapshot in snapshots:
+            snapshot_model_update = {'id': snapshot.id}
+            try:
+                self.create_snapshot(snapshot)
+                snapshot_model_update['status'] = 'available'
+            except Exception:
+                snapshot_model_update['status'] = 'error'
+                model_update['status'] = 'error'
+            snapshot_model_updates.append(snapshot_model_update)
+
+        return model_update, snapshot_model_updates
+
+    def delete_cgsnapshot(self, context, cgsnapshot, snapshots):
+        """Deletes a cgsnapshot."""
+        model_update = {'status': cgsnapshot.status}
+        snapshot_model_updates = []
+        for snapshot in snapshots:
+            snapshot_model_update = {'id': snapshot.id}
+            try:
+                self.delete_snapshot(snapshot)
+                snapshot_model_update['status'] = 'deleted'
+            except exception.SnapshotIsBusy:
+                snapshot_model_update['status'] = 'available'
+            except Exception:
+                snapshot_model_update['status'] = 'error'
+                model_update['status'] = 'error'
+            snapshot_model_updates.append(snapshot_model_update)
+
+        return model_update, snapshot_model_updates
+
+    # Replication functions here are not really doing replication.
+    # They are added so that we can do basic sanity check of replication
+    # APIs.
+    def replication_enable(self, context, volume):
+        return
+
+    def replication_disable(self, context, volume):
+        return
+
+    def replication_failover(self, context, volume, secondary):
+        return {'model_update': {'status': volume['status']},
+                'replication_driver_data': {'replication_driver_data': ''}}
+
+    def list_replication_targets(self, context, volume):
+        targets = []
+        remote_target = {'managed_backend_name': None,
+                         'type': 'unmanaged',
+                         'remote_device_id': 'fake_remote_device',
+                         'san_ip': '123.456.78.90'}
+        targets.append(remote_target)
+        return {'volume_id': volume['id'],
+                'targets': targets}
+
+    def get_replication_updates(self, context):
+        return []