From c43e1cc1b0d9d6633e8be2a0c57bbf9459b24140 Mon Sep 17 00:00:00 2001 From: xing-yang Date: Fri, 25 Nov 2016 22:22:35 -0500 Subject: [PATCH] Add driver interface for groups This patch adds the Generic Volume Groups interface for drivers. Also fixed a few docstrings for groups driver functions. Change-Id: Ia3274fa2dc8ac6f52ccc903296d42e1dae6c6945 --- cinder/interface/volume_group_driver.py | 227 ++++++++++++++++++++++++ cinder/volume/driver.py | 24 ++- doc/source/devref/drivers.rst | 16 ++ 3 files changed, 254 insertions(+), 13 deletions(-) create mode 100644 cinder/interface/volume_group_driver.py diff --git a/cinder/interface/volume_group_driver.py b/cinder/interface/volume_group_driver.py new file mode 100644 index 00000000000..9e0a4b309e6 --- /dev/null +++ b/cinder/interface/volume_group_driver.py @@ -0,0 +1,227 @@ +# Copyright (c) 2017 Dell Inc. or its subsidiaries. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +""" +Generic volume group volume driver interface. +""" + +from cinder.interface import base + + +class VolumeGroupDriver(base.CinderInterface): + """Interface for drivers that support groups.""" + + def create_group(self, context, group): + """Creates a group. + + :param context: the context of the caller. + :param group: the Group object to be created. + :returns: model_update + + model_update will be in this format: {'status': xxx, ......}. + + If the status in model_update is 'error', the manager will throw + an exception and it will be caught in the try-except block in the + manager. If the driver throws an exception, the manager will also + catch it in the try-except block. The group status in the db will + be changed to 'error'. + + For a successful operation, the driver can either build the + model_update and return it or return None. The group status will + be set to 'available'. + """ + + def create_group_from_src(self, context, group, volumes, + group_snapshot=None, snapshots=None, + source_group=None, source_vols=None): + """Creates a group from source. + + :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 the group_snapshot. + :param source_group: a 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. + + param volumes is a list of objects retrieved from the db. It cannot + be assigned to volumes_model_update. volumes_model_update is a list + of dictionaries. It has to be built by the driver. An entry will be + in this format: {'id': xxx, 'status': xxx, ......}. model_update + will be in this format: {'status': xxx, ......}. + + To be consistent with other volume operations, the manager will + assume the operation is successful if no exception is thrown by + the driver. For a successful operation, the driver can either build + the model_update and volumes_model_update and return them or + return None, None. + """ + + def delete_group(self, context, group, volumes): + """Deletes a group. + + :param context: the context of the caller. + :param group: the Group object to be deleted. + :param volumes: a list of Volume objects in the group. + :returns: model_update, volumes_model_update + + param volumes is a list of objects retrieved from the db. It cannot + be assigned to volumes_model_update. volumes_model_update is a list + of dictionaries. It has to be built by the driver. An entry will be + in this format: {'id': xxx, 'status': xxx, ......}. model_update + will be in this format: {'status': xxx, ......}. + + The driver should populate volumes_model_update and model_update + and return them. + + The manager will check volumes_model_update and update db accordingly + for each volume. If the driver successfully deleted some volumes + but failed to delete others, it should set statuses of the volumes + accordingly so that the manager can update db correctly. + + If the status in any entry of volumes_model_update is 'error_deleting' + or 'error', the status in model_update will be set to the same if it + is not already 'error_deleting' or 'error'. + + If the status in model_update is 'error_deleting' or 'error', the + manager will raise an exception and the status of the group will be + set to 'error' in the db. If volumes_model_update is not returned by + the driver, the manager will set the status of every volume in the + group to 'error' in the except block. + + If the driver raises an exception during the operation, it will be + caught by the try-except block in the manager. The statuses of the + group and all volumes in it will be set to 'error'. + + For a successful operation, the driver can either build the + model_update and volumes_model_update and return them or + return None, None. The statuses of the group and all volumes + will be set to 'deleted' after the manager deletes them from db. + """ + + def update_group(self, context, group, + add_volumes=None, remove_volumes=None): + """Updates a group. + + :param context: the context of the caller. + :param group: the Group object 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 + + model_update is a dictionary that the driver wants the manager + to update upon a successful return. If None is returned, the manager + will set the status to 'available'. + + add_volumes_update and remove_volumes_update are lists of dictionaries + that the driver wants the manager to update upon a successful return. + Note that each entry requires a {'id': xxx} so that the correct + volume entry can be updated. If None is returned, the volume will + remain its original status. Also note that you cannot directly + assign add_volumes to add_volumes_update as add_volumes is a list of + volume objects and cannot be used for db update directly. Same with + remove_volumes. + + If the driver throws an exception, the status of the group as well as + those of the volumes to be added/removed will be set to 'error'. + """ + + def create_group_snapshot(self, context, group_snapshot, snapshots): + """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 + + param snapshots is a list of Snapshot objects. It cannot be assigned + to snapshots_model_update. snapshots_model_update is a list of + dictionaries. It has to be built by the driver. An entry will be + in this format: {'id': xxx, 'status': xxx, ......}. model_update + will be in this format: {'status': xxx, ......}. + + The driver should populate snapshots_model_update and model_update + and return them. + + The manager will check snapshots_model_update and update db accordingly + for each snapshot. If the driver successfully deleted some snapshots + but failed to delete others, it should set statuses of the snapshots + accordingly so that the manager can update db correctly. + + If the status in any entry of snapshots_model_update is 'error', the + status in model_update will be set to the same if it is not already + 'error'. + + If the status in model_update is 'error', the manager will raise an + exception and the status of group_snapshot will be set to 'error' in + the db. If snapshots_model_update is not returned by the driver, the + manager will set the status of every snapshot to 'error' in the except + block. + + If the driver raises an exception during the operation, it will be + caught by the try-except block in the manager and the statuses of + group_snapshot and all snapshots will be set to 'error'. + + For a successful operation, the driver can either build the + model_update and snapshots_model_update and return them or + return None, None. The statuses of group_snapshot and all snapshots + will be set to 'available' at the end of the manager function. + """ + + def delete_group_snapshot(self, context, group_snapshot, snapshots): + """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 + + param snapshots is a list of objects. It cannot be assigned to + snapshots_model_update. snapshots_model_update is a list of of + dictionaries. It has to be built by the driver. An entry will be + in this format: {'id': xxx, 'status': xxx, ......}. model_update + will be in this format: {'status': xxx, ......}. + + The driver should populate snapshots_model_update and model_update + and return them. + + The manager will check snapshots_model_update and update db accordingly + for each snapshot. If the driver successfully deleted some snapshots + but failed to delete others, it should set statuses of the snapshots + accordingly so that the manager can update db correctly. + + If the status in any entry of snapshots_model_update is + 'error_deleting' or 'error', the status in model_update will be set to + the same if it is not already 'error_deleting' or 'error'. + + If the status in model_update is 'error_deleting' or 'error', the + manager will raise an exception and the status of group_snapshot will + be set to 'error' in the db. If snapshots_model_update is not returned + by the driver, the manager will set the status of every snapshot to + 'error' in the except block. + + If the driver raises an exception during the operation, it will be + caught by the try-except block in the manager and the statuses of + group_snapshot and all snapshots will be set to 'error'. + + For a successful operation, the driver can either build the + model_update and snapshots_model_update and return them or + return None, None. The statuses of group_snapshot and all snapshots + will be set to 'deleted' after the manager deletes them from db. + """ diff --git a/cinder/volume/driver.py b/cinder/volume/driver.py index db8e05339f4..b429a50eb61 100644 --- a/cinder/volume/driver.py +++ b/cinder/volume/driver.py @@ -1780,10 +1780,9 @@ class BaseVD(object): :param volumes: a list of Volume objects in the group. :returns: model_update, volumes_model_update - param volumes is retrieved directly from the db. It is a list of - cinder.db.sqlalchemy.models.Volume to be precise. It cannot be - assigned to volumes_model_update. volumes_model_update is a list of - dictionaries. It has to be built by the driver. An entry will be + param volumes is a list of objects retrieved from the db. It cannot + be assigned to volumes_model_update. volumes_model_update is a list + of dictionaries. It has to be built by the driver. An entry will be in this format: {'id': xxx, 'status': xxx, ......}. model_update will be in this format: {'status': xxx, ......}. @@ -1836,8 +1835,8 @@ class BaseVD(object): volume entry can be updated. If None is returned, the volume will remain its original status. Also note that you cannot directly assign add_volumes to add_volumes_update as add_volumes is a list of - cinder.db.sqlalchemy.models.Volume objects and cannot be used for - db update directly. Same with remove_volumes. + volume objects and cannot be used for db update directly. Same with + remove_volumes. If the driver throws an exception, the status of the group as well as those of the volumes to be added/removed will be set to 'error'. @@ -1853,17 +1852,16 @@ class BaseVD(object): :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 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. + :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. - param volumes is retrieved directly from the db. It is a list of - cinder.db.sqlalchemy.models.Volume to be precise. It cannot be - assigned to volumes_model_update. volumes_model_update is a list of - dictionaries. It has to be built by the driver. An entry will be + param volumes is a list of objects retrieved from the db. It cannot + be assigned to volumes_model_update. volumes_model_update is a list + of dictionaries. It has to be built by the driver. An entry will be in this format: {'id': xxx, 'status': xxx, ......}. model_update will be in this format: {'status': xxx, ......}. @@ -1923,7 +1921,7 @@ class BaseVD(object): :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. + :param snapshots: a list of Snapshot objects in the group_snapshot. :returns: model_update, snapshots_model_update param snapshots is a list of objects. It cannot be assigned to diff --git a/doc/source/devref/drivers.rst b/doc/source/devref/drivers.rst index d4698cbced1..6cd2953b059 100644 --- a/doc/source/devref/drivers.rst +++ b/doc/source/devref/drivers.rst @@ -147,6 +147,7 @@ additional methods must be implemented to support these operations. .. automodule:: cinder.interface.volume_snapshotmanagement_driver :members: + Volume Consistency Groups ````````````````````````` Some storage backends support the ability to group volumes and create write @@ -156,3 +157,18 @@ the following interface must be implemented by the driver. .. automodule:: cinder.interface.volume_consistencygroup_driver :members: + +Generic Volume Groups +````````````````````` +The generic volume groups feature provides the ability to manage a group of +volumes together. Because this feature is implemented at the manager level, +every driver gets this feature by default. If a driver wants to override +the default behavior to support additional functionalities such as consistent +group snapshot, the following interface must be implemented by the driver. +Once every driver supporting volume consistency groups has added the +consistent group snapshot capability to generic volume groups, we no longer +need the volume consistency groups interface listed above. + +.. automodule:: cinder.interface.volume_group_driver + :members: +