From fabee91d85ffb1808aae655bb0f639af2a9e6e36 Mon Sep 17 00:00:00 2001 From: Xing Yang Date: Wed, 11 Nov 2015 20:19:53 -0500 Subject: [PATCH] Add a FakeGateDriver 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 | 150 +++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/cinder/tests/unit/fake_driver.py b/cinder/tests/unit/fake_driver.py index e0221702b..e13275acf 100644 --- a/cinder/tests/unit/fake_driver.py +++ b/cinder/tests/unit/fake_driver.py @@ -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 [] -- 2.45.2