From e918482674fc373e310c5616ddf7c0ddb283dcd0 Mon Sep 17 00:00:00 2001 From: Sean McGinnis Date: Fri, 15 Sep 2017 11:14:59 -0600 Subject: [PATCH] Use constants for microversion values We very often end up with merge conflicts for any patches that increment microversions due to conflicting numbers. We can't really solve that, but we can avoid the need to update version numbers throughout the code by defining a constant value in one place and using that variable instead. Change-Id: Ib3a80fee6caaabb49af097aa197f550c65d94985 --- cinder/api/common.py | 7 +- cinder/api/contrib/admin_actions.py | 4 +- cinder/api/contrib/backups.py | 5 +- cinder/api/contrib/resource_common_manage.py | 4 +- cinder/api/contrib/scheduler_stats.py | 8 +- cinder/api/contrib/services.py | 23 ++- cinder/api/contrib/used_limits.py | 4 +- cinder/api/contrib/volume_actions.py | 8 +- cinder/api/contrib/volume_manage.py | 4 +- cinder/api/microversions.py | 172 ++++++++++++++++++ cinder/api/openstack/api_version_request.py | 1 + cinder/api/v2/volumes.py | 2 +- cinder/api/v3/attachments.py | 17 +- cinder/api/v3/backups.py | 15 +- cinder/api/v3/clusters.py | 19 +- cinder/api/v3/consistencygroups.py | 4 +- cinder/api/v3/group_snapshots.py | 21 +-- cinder/api/v3/group_specs.py | 11 +- cinder/api/v3/group_types.py | 11 +- cinder/api/v3/groups.py | 33 ++-- cinder/api/v3/limits.py | 4 +- cinder/api/v3/messages.py | 16 +- cinder/api/v3/resource_common_manage.py | 6 +- cinder/api/v3/resource_filters.py | 6 +- cinder/api/v3/snapshot_manage.py | 3 +- cinder/api/v3/snapshots.py | 8 +- cinder/api/v3/views/groups.py | 14 +- cinder/api/v3/views/snapshots.py | 7 +- cinder/api/v3/views/volumes.py | 11 +- cinder/api/v3/volume_manage.py | 3 +- cinder/api/v3/volume_metadata.py | 10 +- cinder/api/v3/volumes.py | 22 +-- cinder/api/v3/workers.py | 3 +- cinder/api/versions.py | 2 +- cinder/api/views/backups.py | 3 +- .../tempest/api/volume/test_volume_revert.py | 1 - .../unit/api/contrib/test_admin_actions.py | 22 ++- .../contrib/test_backup_project_attribute.py | 12 +- cinder/tests/unit/api/contrib/test_backups.py | 10 +- .../unit/api/contrib/test_scheduler_stats.py | 9 +- .../tests/unit/api/contrib/test_services.py | 24 +-- .../unit/api/contrib/test_used_limits.py | 14 +- .../unit/api/contrib/test_volume_actions.py | 28 +-- .../unit/api/contrib/test_volume_manage.py | 14 +- cinder/tests/unit/api/v3/test_attachments.py | 30 +-- cinder/tests/unit/api/v3/test_backups.py | 19 +- cinder/tests/unit/api/v3/test_cluster.py | 24 +-- .../unit/api/v3/test_consistencygroups.py | 37 ++-- .../tests/unit/api/v3/test_group_snapshots.py | 75 ++++---- cinder/tests/unit/api/v3/test_group_specs.py | 23 ++- cinder/tests/unit/api/v3/test_group_types.py | 62 +++---- cinder/tests/unit/api/v3/test_groups.py | 157 ++++++++-------- cinder/tests/unit/api/v3/test_limits.py | 13 +- cinder/tests/unit/api/v3/test_messages.py | 25 ++- .../unit/api/v3/test_resource_filters.py | 5 +- .../tests/unit/api/v3/test_snapshot_manage.py | 30 +-- cinder/tests/unit/api/v3/test_snapshots.py | 64 ++++--- .../tests/unit/api/v3/test_volume_manage.py | 27 ++- .../tests/unit/api/v3/test_volume_metadata.py | 17 +- cinder/tests/unit/api/v3/test_volumes.py | 143 ++++++++------- cinder/tests/unit/api/v3/test_workers.py | 5 +- cinder/tests/unit/message/test_api.py | 37 ++-- cinder/volume/api.py | 18 +- .../contributor/api_microversion_dev.rst | 9 + 64 files changed, 868 insertions(+), 577 deletions(-) create mode 100644 cinder/api/microversions.py diff --git a/cinder/api/common.py b/cinder/api/common.py index 4bf09eb8705..5cbab7530f2 100644 --- a/cinder/api/common.py +++ b/cinder/api/common.py @@ -24,6 +24,7 @@ from oslo_log import log as logging from six.moves import urllib import webob +from cinder.api import microversions as mv from cinder.common import constants from cinder import exception from cinder.i18n import _ @@ -66,8 +67,6 @@ CONF.register_opts(api_common_opts) LOG = logging.getLogger(__name__) _FILTERS_COLLECTION = None -FILTERING_VERSION = '3.31' -LIKE_FILTER_VERSION = '3.34' ATTRIBUTE_CONVERTERS = {'name~': 'display_name~', 'description~': 'display_description~'} @@ -492,9 +491,9 @@ def process_general_filtering(resource): req_version = kwargs.get('req_version') filters = kwargs.get('filters') context = kwargs.get('context') - if req_version.matches(FILTERING_VERSION): + if req_version.matches(mv.RESOURCE_FILTER): support_like = False - if req_version.matches(LIKE_FILTER_VERSION): + if req_version.matches(mv.LIKE_FILTER): support_like = True reject_invalid_filters(context, filters, resource, support_like) diff --git a/cinder/api/contrib/admin_actions.py b/cinder/api/contrib/admin_actions.py index 4d9dfea0a68..8056a243928 100644 --- a/cinder/api/contrib/admin_actions.py +++ b/cinder/api/contrib/admin_actions.py @@ -20,6 +20,7 @@ from webob import exc from cinder.api import common from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder import backup from cinder import db @@ -245,7 +246,8 @@ class VolumeAdminController(AdminController): volume = self._get(context, id) params = body['os-migrate_volume'] - cluster_name, host = common.get_cluster_host(req, params, '3.16') + cluster_name, host = common.get_cluster_host(req, params, + mv.VOLUME_MIGRATE_CLUSTER) force_host_copy = utils.get_bool_param('force_host_copy', params) lock_volume = utils.get_bool_param('lock_volume', params) self.volume_api.migrate_volume(context, volume, host, cluster_name, diff --git a/cinder/api/contrib/backups.py b/cinder/api/contrib/backups.py index ca69b657320..80c03bc635b 100644 --- a/cinder/api/contrib/backups.py +++ b/cinder/api/contrib/backups.py @@ -23,6 +23,7 @@ from webob import exc from cinder.api import common from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.views import backups as backup_views from cinder import backup as backupAPI @@ -151,8 +152,8 @@ class BackupsController(wsgi.Controller): incremental = backup.get('incremental', False) force = backup.get('force', False) snapshot_id = backup.get('snapshot_id', None) - metadata = backup.get( - 'metadata', None) if req_version.matches("3.43") else None + metadata = backup.get('metadata', None) if req_version.matches( + mv.BACKUP_METADATA) else None LOG.info("Creating backup of volume %(volume_id)s in container" " %(container)s", {'volume_id': volume_id, 'container': container}, diff --git a/cinder/api/contrib/resource_common_manage.py b/cinder/api/contrib/resource_common_manage.py index 01396516814..5967d367267 100644 --- a/cinder/api/contrib/resource_common_manage.py +++ b/cinder/api/contrib/resource_common_manage.py @@ -15,6 +15,7 @@ import oslo_messaging as messaging from cinder.api import common +from cinder.api import microversions as mv from cinder import exception from cinder.i18n import _ @@ -23,7 +24,8 @@ def get_manageable_resources(req, is_detail, function_get_manageable, view_builder): context = req.environ['cinder.context'] params = req.params.copy() - cluster_name, host = common.get_cluster_host(req, params, '3.17') + cluster_name, host = common.get_cluster_host( + req, params, mv.MANAGE_EXISTING_CLUSTER) marker, limit, offset = common.get_pagination_params(params) sort_keys, sort_dirs = common.get_sort_params(params, default_key='reference') diff --git a/cinder/api/contrib/scheduler_stats.py b/cinder/api/contrib/scheduler_stats.py index 875d42ca54e..347f469eef6 100644 --- a/cinder/api/contrib/scheduler_stats.py +++ b/cinder/api/contrib/scheduler_stats.py @@ -16,14 +16,12 @@ from cinder.api import common from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.views import scheduler_stats as scheduler_stats_view from cinder.scheduler import rpcapi from cinder import utils -GET_POOL_NAME_FILTER_MICRO_VERSION = '3.28' -GET_POOL_VOLUME_TYPE_FILTER_MICRO_VERSION = '3.35' - def authorize(context, action_name): action = 'scheduler_stats:%s' % action_name @@ -42,7 +40,7 @@ class SchedulerStatsController(wsgi.Controller): @common.process_general_filtering('pool') def _process_pool_filtering(self, context=None, filters=None, req_version=None): - if not req_version.matches(GET_POOL_NAME_FILTER_MICRO_VERSION): + if not req_version.matches(mv.POOL_FILTER): filters.clear() def get_pools(self, req): @@ -60,7 +58,7 @@ class SchedulerStatsController(wsgi.Controller): filters=filters, req_version=req_version) - if not req_version.matches(GET_POOL_VOLUME_TYPE_FILTER_MICRO_VERSION): + if not req_version.matches(mv.POOL_TYPE_FILTER): filters.pop('volume_type', None) pools = self.scheduler_api.get_pools(context, filters=filters) diff --git a/cinder/api/contrib/services.py b/cinder/api/contrib/services.py index 4a78665377c..676a4a8f2a4 100644 --- a/cinder/api/contrib/services.py +++ b/cinder/api/contrib/services.py @@ -22,6 +22,7 @@ import webob.exc from cinder.api import common from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.backup import rpcapi as backup_rpcapi from cinder.common import constants @@ -94,8 +95,8 @@ class ServiceController(wsgi.Controller): 'status': active, 'state': art, 'updated_at': updated_at} - # On V3.7 we added cluster support - if req.api_version_request.matches('3.7'): + # On CLUSTER_SUPPORT we added cluster support + if req.api_version_request.matches(mv.CLUSTER_SUPPORT): ret_fields['cluster'] = svc.cluster_name if detailed: @@ -125,20 +126,23 @@ class ServiceController(wsgi.Controller): raise exception.InvalidInput(ex.msg) def _freeze(self, context, req, body): - cluster_name, host = common.get_cluster_host(req, body, '3.26') + cluster_name, host = common.get_cluster_host( + req, body, mv.REPLICATION_CLUSTER) return self._volume_api_proxy(self.volume_api.freeze_host, context, host, cluster_name) def _thaw(self, context, req, body): - cluster_name, host = common.get_cluster_host(req, body, '3.26') + cluster_name, host = common.get_cluster_host( + req, body, mv.REPLICATION_CLUSTER) return self._volume_api_proxy(self.volume_api.thaw_host, context, host, cluster_name) def _failover(self, context, req, body, clustered): # We set version to None to always get the cluster name from the body, - # to False when we don't want to get it, and '3.26' when we only want - # it if the requested version is 3.26 or higher. - version = '3.26' if clustered else False + # to False when we don't want to get it, and REPLICATION_CLUSTER when + # we only want it if the requested version is REPLICATION_CLUSTER or + # higher. + version = mv.REPLICATION_CLUSTER if clustered else False cluster_name, host = common.get_cluster_host(req, body, version) self._volume_api_proxy(self.volume_api.failover, context, host, cluster_name, body.get('backend_id')) @@ -221,7 +225,7 @@ class ServiceController(wsgi.Controller): context = req.environ['cinder.context'] authorize(context, action='update') - support_dynamic_log = req.api_version_request.matches('3.32') + support_dynamic_log = req.api_version_request.matches(mv.LOG_LEVEL) ext_loaded = self.ext_mgr.is_loaded('os-extended-services') ret_val = {} @@ -240,7 +244,8 @@ class ServiceController(wsgi.Controller): return self._thaw(context, req, body) elif id == "failover_host": return self._failover(context, req, body, False) - elif req.api_version_request.matches('3.26') and id == 'failover': + elif (req.api_version_request.matches(mv.REPLICATION_CLUSTER) and + id == 'failover'): return self._failover(context, req, body, True) elif support_dynamic_log and id == 'set-log': return self._set_log(context, body) diff --git a/cinder/api/contrib/used_limits.py b/cinder/api/contrib/used_limits.py index 1c638a2826b..445f8082f8b 100644 --- a/cinder/api/contrib/used_limits.py +++ b/cinder/api/contrib/used_limits.py @@ -13,6 +13,7 @@ # under the License. from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder import quota @@ -32,7 +33,8 @@ class UsedLimitsController(wsgi.Controller): # TODO(wangxiyuan): Support "tenant_id" here to keep the backwards # compatibility. Remove it once we drop all support for "tenant". - if req_version.matches(None, "3.38") or not context.is_admin: + if (req_version.matches(None, mv.GROUP_REPLICATION) or + not context.is_admin): params.pop('project_id', None) params.pop('tenant_id', None) project_id = params.get( diff --git a/cinder/api/contrib/volume_actions.py b/cinder/api/contrib/volume_actions.py index 6b1d0f57c48..c438a5deaed 100644 --- a/cinder/api/contrib/volume_actions.py +++ b/cinder/api/contrib/volume_actions.py @@ -22,7 +22,7 @@ from six.moves import http_client import webob from cinder.api import extensions -from cinder.api.openstack import api_version_request +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder import exception from cinder.i18n import _ @@ -271,7 +271,8 @@ class VolumeActionsController(wsgi.Controller): image_metadata['cinder_encryption_key_id'] = encryption_key_id - if req_version >= api_version_request.APIVersionRequest('3.1'): + if req_version >= mv.get_api_version( + mv.UPLOAD_IMAGE_PARAMS): image_metadata['visibility'] = params.get('visibility', 'private') image_metadata['protected'] = params.get('protected', 'False') @@ -321,7 +322,8 @@ class VolumeActionsController(wsgi.Controller): raise webob.exc.HTTPBadRequest(explanation=msg) try: - if req_version.matches("3.42") and volume.status in ['in-use']: + if (req_version.matches(mv.VOLUME_EXTEND_INUSE) and + volume.status in ['in-use']): self.volume_api.extend_attached_volume(context, volume, size) else: self.volume_api.extend(context, volume, size) diff --git a/cinder/api/contrib/volume_manage.py b/cinder/api/contrib/volume_manage.py index 99ff0377832..f1089a1c2bb 100644 --- a/cinder/api/contrib/volume_manage.py +++ b/cinder/api/contrib/volume_manage.py @@ -18,6 +18,7 @@ from six.moves import http_client from cinder.api import common from cinder.api.contrib import resource_common_manage from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v2.views import volumes as volume_views from cinder.api.views import manageable_volumes as list_manageable_view @@ -110,7 +111,8 @@ class VolumeManageController(wsgi.Controller): if 'ref' not in volume: raise exception.MissingRequired(element='ref') - cluster_name, host = common.get_cluster_host(req, volume, '3.16') + cluster_name, host = common.get_cluster_host( + req, volume, mv.VOLUME_MIGRATE_CLUSTER) LOG.debug('Manage volume request body: %s', body) diff --git a/cinder/api/microversions.py b/cinder/api/microversions.py new file mode 100644 index 00000000000..2f691bb0b48 --- /dev/null +++ b/cinder/api/microversions.py @@ -0,0 +1,172 @@ +# 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. + +"""API Microversion definitions. + +All new microversions should have a constant added here to be used throughout +the code instead of the specific version number. Until patches land, it's +common to end up with merge conflicts with other microversion changes. Merge +conflicts will be easier to handle via the microversion constants defined here +as the version number will only need to be changed in a single location. + +Actual version numbers should be used: + + * In this file + * In cinder/api/openstack/rest_api_version_history.rst + * In cinder/api/openstack/api_version_request.py + * In release notes describing the new functionality + * In updates to api-ref + +Nearly all microversion changes should include changes to all of those +locations. Make sure to add relevant documentation, and make sure that +documentation includes the final version number used. +""" + +from cinder.api.openstack import api_version_request as api_version +from cinder import exception + + +# Add new constants here for each new microversion. + +BASE_VERSION = '3.0' + +UPLOAD_IMAGE_PARAMS = '3.1' + +VOLUME_LIST_BOOTABLE = '3.2' + +MESSAGES = '3.3' + +VOLUME_LIST_GLANCE_METADATA = '3.4' + +MESSAGES_PAGINATION = '3.5' + +CG_UPDATE_BLANK_PROPERTIES = '3.6' + +CLUSTER_SUPPORT = '3.7' + +MANAGE_EXISTING_LIST = '3.8' + +BACKUP_UPDATE = '3.9' + +VOLUME_LIST_GROUP = '3.10' + +GROUP_TYPE = '3.11' + +VOLUME_SUMMARY = '3.12' + +GROUP_VOLUME = '3.13' + +GROUP_SNAPSHOTS = '3.14' + +ETAGS = '3.15' + +VOLUME_MIGRATE_CLUSTER = '3.16' + +MANAGE_EXISTING_CLUSTER = '3.17' + +BACKUP_PROJECT = '3.18' + +GROUP_SNAPSHOT_RESET_STATUS = '3.19' + +GROUP_VOLUME_RESET_STATUS = '3.20' + +VOLUME_DETAIL_PROVIDER_ID = '3.21' + +SNAPSHOT_LIST_METADATA_FILTER = '3.22' + +VOLUME_DELETE_FORCE = '3.23' + +WORKERS_CLEANUP = '3.24' + +GROUP_VOLUME_LIST = '3.25' + +REPLICATION_CLUSTER = '3.26' + +NEW_ATTACH = '3.27' + +POOL_FILTER = '3.28' + +GROUP_SNAPSHOT_PAGINATION = '3.29' + +SNAPSHOT_SORT = '3.30' + +RESOURCE_FILTER = '3.31' + +LOG_LEVEL = '3.32' + +RESOURCE_FILTER_CONFIG = '3.33' + +LIKE_FILTER = '3.34' + +POOL_TYPE_FILTER = '3.35' + +VOLUME_SUMMARY_METADATA = '3.36' + +BACKUP_SORT_NAME = '3.37' + +GROUP_REPLICATION = '3.38' + +LIMITS_ADMIN_FILTER = '3.39' + +VOLUME_REVERT = '3.40' + +SNAPSHOT_LIST_USER_ID = '3.41' + +VOLUME_EXTEND_INUSE = '3.42' + +BACKUP_METADATA = '3.43' + +NEW_ATTACH_COMPLETION = '3.44' + + +def get_mv_header(version): + """Gets a formatted HTTP microversion header. + + :param version: The microversion needed. + :return: A tuple containing the microversion header with the + requested version value. + """ + return {'OpenStack-API-Version': + 'volume %s' % version} + + +def get_api_version(version): + """Gets a ``APIVersionRequest`` instance. + + :param version: The microversion needed. + :return: The ``APIVersionRequest`` instance. + """ + return api_version.APIVersionRequest(version) + + +def get_prior_version(version): + """Gets the microversion before the given version. + + Mostly useful for testing boundaries. This gets the microversion defined + just prior to the given version. + + :param version: The version of interest. + :return: The version just prior to the given version. + """ + parts = version.split('.') + + if len(parts) != 2 or parts[0] != '3': + raise exception.InvalidInput(reason='Version %s is not a valid ' + 'microversion format.' % version) + + minor = int(parts[1]) - 1 + + if minor < 0: + # What's your problem? Are you trying to be difficult? + minor = 0 + + return '%s.%s' % (parts[0], minor) diff --git a/cinder/api/openstack/api_version_request.py b/cinder/api/openstack/api_version_request.py index bcdde392a93..ec0d4967f1e 100644 --- a/cinder/api/openstack/api_version_request.py +++ b/cinder/api/openstack/api_version_request.py @@ -116,6 +116,7 @@ REST_API_VERSION_HISTORY = """ _MIN_API_VERSION = "3.0" _MAX_API_VERSION = "3.44" _LEGACY_API_VERSION2 = "2.0" +UPDATED = "2017-09-19T20:18:14Z" # NOTE(cyeoh): min and max versions declared as functions so we can diff --git a/cinder/api/v2/volumes.py b/cinder/api/v2/volumes.py index 47fc2bfd876..f84a363866e 100644 --- a/cinder/api/v2/volumes.py +++ b/cinder/api/v2/volumes.py @@ -95,7 +95,7 @@ class VolumeController(wsgi.Controller): filters = params # NOTE(wanghao): Always removing glance_metadata since we support it - # only in API version >= 3.4. + # only in API version >= VOLUME_LIST_GLANCE_METADATA. filters.pop('glance_metadata', None) utils.remove_invalid_filter_options(context, filters, diff --git a/cinder/api/v3/attachments.py b/cinder/api/v3/attachments.py index 36d6678898d..c0aacb7b99f 100644 --- a/cinder/api/v3/attachments.py +++ b/cinder/api/v3/attachments.py @@ -16,6 +16,7 @@ from oslo_log import log as logging import webob from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import attachments as attachment_views from cinder import exception @@ -26,8 +27,6 @@ from cinder.volume import api as volume_api LOG = logging.getLogger(__name__) -API_VERSION = '3.27' -ATTACHMENT_COMPLETION_VERSION = '3.44' class AttachmentsController(wsgi.Controller): @@ -43,20 +42,20 @@ class AttachmentsController(wsgi.Controller): self.ext_mgr = ext_mgr super(AttachmentsController, self).__init__() - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) def show(self, req, id): """Return data about the given attachment.""" context = req.environ['cinder.context'] attachment = objects.VolumeAttachment.get_by_id(context, id) return attachment_views.ViewBuilder.detail(attachment) - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) def index(self, req): """Return a summary list of attachments.""" attachments = self._items(req) return attachment_views.ViewBuilder.list(attachments) - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) def detail(self, req): """Return a detailed list of attachments.""" attachments = self._items(req) @@ -94,7 +93,7 @@ class AttachmentsController(wsgi.Controller): marker=marker, limit=limit, offset=offset, sort_keys=sort_keys, sort_direction=sort_dirs) - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) @wsgi.response(202) def create(self, req, body): """Create an attachment. @@ -192,7 +191,7 @@ class AttachmentsController(wsgi.Controller): raise webob.exc.HTTPInternalServerError(explanation=err_msg) return attachment_views.ViewBuilder.detail(attachment_ref) - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) def update(self, req, id, body): """Update an attachment record. @@ -252,7 +251,7 @@ class AttachmentsController(wsgi.Controller): # or a dict? return attachment_views.ViewBuilder.detail(attachment_ref) - @wsgi.Controller.api_version(API_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH) def delete(self, req, id): """Delete an attachment. @@ -268,7 +267,7 @@ class AttachmentsController(wsgi.Controller): return attachment_views.ViewBuilder.list(attachments) @wsgi.response(202) - @wsgi.Controller.api_version(ATTACHMENT_COMPLETION_VERSION) + @wsgi.Controller.api_version(mv.NEW_ATTACH_COMPLETION) @wsgi.action('os-complete') def complete(self, req, id, body): """Mark a volume attachment process as completed (in-use).""" diff --git a/cinder/api/v3/backups.py b/cinder/api/v3/backups.py index d08e265eabf..a98a8a2e945 100644 --- a/cinder/api/v3/backups.py +++ b/cinder/api/v3/backups.py @@ -19,22 +19,20 @@ from oslo_log import log as logging from webob import exc from cinder.api.contrib import backups as backups_v2 +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.backup import api as backup_api from cinder import exception from cinder.i18n import _ -BACKUP_UPDATE_MICRO_VERSION = '3.9' -BACKUP_TENANT_MICRO_VERSION = '3.18' - LOG = logging.getLogger(__name__) class BackupsController(backups_v2.BackupsController): """The backups API controller for the OpenStack API V3.""" - @wsgi.Controller.api_version(BACKUP_UPDATE_MICRO_VERSION) + @wsgi.Controller.api_version(mv.BACKUP_UPDATE) def update(self, req, id, body): """Update a backup.""" context = req.environ['cinder.context'] @@ -50,7 +48,8 @@ class BackupsController(backups_v2.BackupsController): if 'description' in backup_update: update_dict['display_description'] = ( backup_update.pop('description')) - if req_version.matches('3.43') and 'metadata' in backup_update: + if (req_version.matches( + mv.BACKUP_METADATA) and 'metadata' in backup_update): update_dict['metadata'] = backup_update.pop('metadata') # Check no unsupported fields. if backup_update: @@ -77,7 +76,7 @@ class BackupsController(backups_v2.BackupsController): req.cache_db_backup(backup) resp_backup = self._view_builder.detail(req, backup) - if req_version.matches(BACKUP_TENANT_MICRO_VERSION): + if req_version.matches(mv.BACKUP_PROJECT): try: backup_api.check_policy(context, 'backup_project_attribute') self._add_backup_project_attribute(req, resp_backup['backup']) @@ -90,7 +89,7 @@ class BackupsController(backups_v2.BackupsController): context = req.environ['cinder.context'] req_version = req.api_version_request - if req_version.matches(BACKUP_TENANT_MICRO_VERSION): + if req_version.matches(mv.BACKUP_PROJECT): try: backup_api.check_policy(context, 'backup_project_attribute') for bak in resp_backup['backups']: @@ -100,7 +99,7 @@ class BackupsController(backups_v2.BackupsController): return resp_backup def _convert_sort_name(self, req_version, sort_keys): - if req_version.matches("3.37") and 'name' in sort_keys: + if req_version.matches(mv.BACKUP_SORT_NAME) and 'name' in sort_keys: sort_keys[sort_keys.index('name')] = 'display_name' diff --git a/cinder/api/v3/clusters.py b/cinder/api/v3/clusters.py index 120f1e6a106..53e43ac8104 100644 --- a/cinder/api/v3/clusters.py +++ b/cinder/api/v3/clusters.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import clusters as clusters_view from cinder import exception @@ -21,10 +22,6 @@ from cinder import objects from cinder import utils -CLUSTER_MICRO_VERSION = '3.7' -REPLICATION_DATA_MICRO_VERSION = '3.26' - - class ClusterController(wsgi.Controller): allowed_list_keys = {'name', 'binary', 'is_up', 'disabled', 'num_hosts', 'num_down_hosts', 'binary', 'replication_status', @@ -33,7 +30,7 @@ class ClusterController(wsgi.Controller): policy_checker = wsgi.Controller.get_policy_checker('clusters') - @wsgi.Controller.api_version(CLUSTER_MICRO_VERSION) + @wsgi.Controller.api_version(mv.CLUSTER_SUPPORT) def show(self, req, id, binary='cinder-volume'): """Return data for a given cluster name with optional binary.""" # Let the wsgi middleware convert NotAuthorized exceptions @@ -42,10 +39,10 @@ class ClusterController(wsgi.Controller): cluster = objects.Cluster.get_by_id(context, None, binary=binary, name=id, services_summary=True) replication_data = req.api_version_request.matches( - REPLICATION_DATA_MICRO_VERSION) + mv.REPLICATION_CLUSTER) return clusters_view.ViewBuilder.detail(cluster, replication_data) - @wsgi.Controller.api_version(CLUSTER_MICRO_VERSION) + @wsgi.Controller.api_version(mv.CLUSTER_SUPPORT) def index(self, req): """Return a non detailed list of all existing clusters. @@ -53,7 +50,7 @@ class ClusterController(wsgi.Controller): """ return self._get_clusters(req, detail=False) - @wsgi.Controller.api_version(CLUSTER_MICRO_VERSION) + @wsgi.Controller.api_version(mv.CLUSTER_SUPPORT) def detail(self, req): """Return a detailed list of all existing clusters. @@ -65,7 +62,7 @@ class ClusterController(wsgi.Controller): # Let the wsgi middleware convert NotAuthorized exceptions context = self.policy_checker(req, 'get_all') replication_data = req.api_version_request.matches( - REPLICATION_DATA_MICRO_VERSION) + mv.REPLICATION_CLUSTER) filters = dict(req.GET) allowed = self.allowed_list_keys if not replication_data: @@ -89,7 +86,7 @@ class ClusterController(wsgi.Controller): return clusters_view.ViewBuilder.list(clusters, detail, replication_data) - @wsgi.Controller.api_version(CLUSTER_MICRO_VERSION) + @wsgi.Controller.api_version(mv.CLUSTER_SUPPORT) def update(self, req, id, body): """Enable/Disable scheduling for a cluster.""" # NOTE(geguileo): This method tries to be consistent with services @@ -123,7 +120,7 @@ class ClusterController(wsgi.Controller): # We return summary data plus the disabled reason replication_data = req.api_version_request.matches( - REPLICATION_DATA_MICRO_VERSION) + mv.REPLICATION_CLUSTER) ret_val = clusters_view.ViewBuilder.summary(cluster, replication_data) ret_val['cluster']['disabled_reason'] = disabled_reason diff --git a/cinder/api/v3/consistencygroups.py b/cinder/api/v3/consistencygroups.py index a7e542293db..6ff3efba88c 100644 --- a/cinder/api/v3/consistencygroups.py +++ b/cinder/api/v3/consistencygroups.py @@ -19,6 +19,7 @@ import webob from webob import exc from cinder.api.contrib import consistencygroups as cg_v2 +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.i18n import _ @@ -30,7 +31,8 @@ class ConsistencyGroupsController(cg_v2.ConsistencyGroupsController): def _check_update_parameters_v3(self, req, name, description, add_volumes, remove_volumes): - allow_empty = req.api_version_request.matches('3.6', None) + allow_empty = req.api_version_request.matches( + mv.CG_UPDATE_BLANK_PROPERTIES, None) if allow_empty: if (name is None and description is None and not add_volumes and not remove_volumes): diff --git a/cinder/api/v3/group_snapshots.py b/cinder/api/v3/group_snapshots.py index f1b18763a06..300ea36e609 100644 --- a/cinder/api/v3/group_snapshots.py +++ b/cinder/api/v3/group_snapshots.py @@ -22,6 +22,7 @@ import webob from webob import exc from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import group_snapshots as group_snapshot_views from cinder import exception @@ -32,8 +33,6 @@ from cinder.volume import group_types LOG = logging.getLogger(__name__) -GROUP_SNAPSHOT_API_VERSION = '3.14' - class GroupSnapshotsController(wsgi.Controller): """The group_snapshots API controller for the OpenStack API.""" @@ -52,7 +51,7 @@ class GroupSnapshotsController(wsgi.Controller): % {'group_type': group_type_id}) raise exc.HTTPBadRequest(explanation=msg) - @wsgi.Controller.api_version(GROUP_SNAPSHOT_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def show(self, req, id): """Return data about the given group_snapshot.""" LOG.debug('show called for member %s', id) @@ -66,7 +65,7 @@ class GroupSnapshotsController(wsgi.Controller): return self._view_builder.detail(req, group_snapshot) - @wsgi.Controller.api_version(GROUP_SNAPSHOT_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def delete(self, req, id): """Delete a group_snapshot.""" LOG.debug('delete called for member %s', id) @@ -93,12 +92,12 @@ class GroupSnapshotsController(wsgi.Controller): return webob.Response(status_int=http_client.ACCEPTED) - @wsgi.Controller.api_version(GROUP_SNAPSHOT_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def index(self, req): """Returns a summary list of group_snapshots.""" return self._get_group_snapshots(req, is_detail=False) - @wsgi.Controller.api_version(GROUP_SNAPSHOT_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) def detail(self, req): """Returns a detailed list of group_snapshots.""" return self._get_group_snapshots(req, is_detail=True) @@ -109,14 +108,14 @@ class GroupSnapshotsController(wsgi.Controller): context = req.environ['cinder.context'] req_version = req.api_version_request filters = marker = limit = offset = sort_keys = sort_dirs = None - if req_version.matches("3.29"): + if req_version.matches(mv.GROUP_SNAPSHOT_PAGINATION): filters = req.params.copy() marker, limit, offset = common.get_pagination_params(filters) sort_keys, sort_dirs = common.get_sort_params(filters) - if req_version.matches(common.FILTERING_VERSION): + if req_version.matches(mv.RESOURCE_FILTER): support_like = (True if req_version.matches( - common.LIKE_FILTER_VERSION) else False) + mv.LIKE_FILTER) else False) common.reject_invalid_filters(context, filters, 'group_snapshot', support_like) @@ -145,7 +144,7 @@ class GroupSnapshotsController(wsgi.Controller): group_snapshots['group_snapshots'] = new_group_snapshots return group_snapshots - @wsgi.Controller.api_version(GROUP_SNAPSHOT_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) @wsgi.response(http_client.ACCEPTED) def create(self, req, body): """Create a new group_snapshot.""" @@ -183,7 +182,7 @@ class GroupSnapshotsController(wsgi.Controller): return retval - @wsgi.Controller.api_version('3.19') + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOT_RESET_STATUS) @wsgi.action("reset_status") def reset_status(self, req, id, body): return self._reset_status(req, id, body) diff --git a/cinder/api/v3/group_specs.py b/cinder/api/v3/group_specs.py index ee89cfe0815..e851839048b 100644 --- a/cinder/api/v3/group_specs.py +++ b/cinder/api/v3/group_specs.py @@ -18,6 +18,7 @@ from six.moves import http_client import webob from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder import db from cinder import exception @@ -51,7 +52,7 @@ class GroupTypeSpecsController(wsgi.Controller): except exception.GroupTypeNotFound as ex: raise webob.exc.HTTPNotFound(explanation=ex.msg) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def index(self, req, group_type_id): """Returns the list of group specs for a given group type.""" context = req.environ['cinder.context'] @@ -59,7 +60,7 @@ class GroupTypeSpecsController(wsgi.Controller): self._check_type(context, group_type_id) return self._get_group_specs(context, group_type_id) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) @wsgi.response(http_client.ACCEPTED) def create(self, req, group_type_id, body=None): context = req.environ['cinder.context'] @@ -80,7 +81,7 @@ class GroupTypeSpecsController(wsgi.Controller): notifier_info) return body - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def update(self, req, group_type_id, id, body=None): context = req.environ['cinder.context'] self._check_policy(context) @@ -108,7 +109,7 @@ class GroupTypeSpecsController(wsgi.Controller): notifier_info) return body - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def show(self, req, group_type_id, id): """Return a single extra spec item.""" context = req.environ['cinder.context'] @@ -123,7 +124,7 @@ class GroupTypeSpecsController(wsgi.Controller): "%(id)s.") % ({'type_id': group_type_id, 'id': id}) raise webob.exc.HTTPNotFound(explanation=msg) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def delete(self, req, group_type_id, id): """Deletes an existing group spec.""" context = req.environ['cinder.context'] diff --git a/cinder/api/v3/group_types.py b/cinder/api/v3/group_types.py index 1163f5197f9..c7fbad10216 100644 --- a/cinder/api/v3/group_types.py +++ b/cinder/api/v3/group_types.py @@ -21,6 +21,7 @@ import webob from webob import exc from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import group_types as views_types from cinder import exception @@ -55,7 +56,7 @@ class GroupTypesController(wsgi.Controller): payload = dict(group_types=group_type) rpc.get_notifier('groupType').info(context, method, payload) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) @wsgi.response(http_client.ACCEPTED) def create(self, req, body): """Creates a new group type.""" @@ -103,7 +104,7 @@ class GroupTypesController(wsgi.Controller): return self._view_builder.show(req, grp_type) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def update(self, req, id, body): # Update description for a given group type. context = req.environ['cinder.context'] @@ -163,7 +164,7 @@ class GroupTypesController(wsgi.Controller): return self._view_builder.show(req, grp_type) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def delete(self, req, id): """Deletes an existing group type.""" context = req.environ['cinder.context'] @@ -186,14 +187,14 @@ class GroupTypesController(wsgi.Controller): return webob.Response(status_int=http_client.ACCEPTED) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def index(self, req): """Returns the list of group types.""" limited_types = self._get_group_types(req) req.cache_resource(limited_types, name='group_types') return self._view_builder.index(req, limited_types) - @wsgi.Controller.api_version('3.11') + @wsgi.Controller.api_version(mv.GROUP_TYPE) def show(self, req, id): """Return a single group type item.""" context = req.environ['cinder.context'] diff --git a/cinder/api/v3/groups.py b/cinder/api/v3/groups.py index b0e029b0f51..90c9524f263 100644 --- a/cinder/api/v3/groups.py +++ b/cinder/api/v3/groups.py @@ -22,6 +22,7 @@ import webob from webob import exc from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import groups as views_groups from cinder import exception @@ -32,10 +33,6 @@ from cinder.volume import group_types LOG = logging.getLogger(__name__) -GROUP_API_VERSION = '3.13' -GROUP_CREATE_FROM_SRC_API_VERSION = '3.14' -GROUP_REPLICATION_API_VERSION = '3.38' - class GroupsController(wsgi.Controller): """The groups API controller for the OpenStack API.""" @@ -53,7 +50,7 @@ class GroupsController(wsgi.Controller): "CG APIs.") % {'group_type': group_type_id} raise exc.HTTPBadRequest(explanation=msg) - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) def show(self, req, id): """Return data about the given group.""" LOG.debug('show called for member %s', id) @@ -68,7 +65,7 @@ class GroupsController(wsgi.Controller): return self._view_builder.detail(req, group) - @wsgi.Controller.api_version('3.20') + @wsgi.Controller.api_version(mv.GROUP_VOLUME_RESET_STATUS) @wsgi.action("reset_status") def reset_status(self, req, id, body): return self._reset_status(req, id, body) @@ -109,7 +106,7 @@ class GroupsController(wsgi.Controller): raise exc.HTTPBadRequest(explanation=error.msg) return webob.Response(status_int=http_client.ACCEPTED) - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) @wsgi.action("delete") def delete_group(self, req, id, body): return self._delete(req, id, body) @@ -150,12 +147,12 @@ class GroupsController(wsgi.Controller): return webob.Response(status_int=http_client.ACCEPTED) - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) def index(self, req): """Returns a summary list of groups.""" return self._get_groups(req, is_detail=False) - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) def detail(self, req): """Returns a detailed list of groups.""" return self._get_groups(req, is_detail=True) @@ -169,9 +166,9 @@ class GroupsController(wsgi.Controller): sort_keys, sort_dirs = common.get_sort_params(filters) filters.pop('list_volume', None) - if api_version.matches(common.FILTERING_VERSION): + if api_version.matches(mv.RESOURCE_FILTER): support_like = (True if api_version.matches( - common.LIKE_FILTER_VERSION) else False) + mv.LIKE_FILTER) else False) common.reject_invalid_filters(context, filters, 'group', support_like) @@ -197,7 +194,7 @@ class GroupsController(wsgi.Controller): req, new_groups) return groups - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) @wsgi.response(http_client.ACCEPTED) def create(self, req, body): """Create a new group.""" @@ -243,7 +240,7 @@ class GroupsController(wsgi.Controller): retval = self._view_builder.summary(req, new_group) return retval - @wsgi.Controller.api_version(GROUP_CREATE_FROM_SRC_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_SNAPSHOTS) @wsgi.action("create-from-src") @wsgi.response(http_client.ACCEPTED) def create_from_src(self, req, body): @@ -308,7 +305,7 @@ class GroupsController(wsgi.Controller): retval = self._view_builder.summary(req, new_group) return retval - @wsgi.Controller.api_version(GROUP_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_VOLUME) def update(self, req, id, body): """Update the group. @@ -373,7 +370,7 @@ class GroupsController(wsgi.Controller): return webob.Response(status_int=http_client.ACCEPTED) - @wsgi.Controller.api_version(GROUP_REPLICATION_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_REPLICATION) @wsgi.action("enable_replication") def enable_replication(self, req, id, body): """Enables replications for a group.""" @@ -397,7 +394,7 @@ class GroupsController(wsgi.Controller): return webob.Response(status_int=202) - @wsgi.Controller.api_version(GROUP_REPLICATION_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_REPLICATION) @wsgi.action("disable_replication") def disable_replication(self, req, id, body): """Disables replications for a group.""" @@ -421,7 +418,7 @@ class GroupsController(wsgi.Controller): return webob.Response(status_int=202) - @wsgi.Controller.api_version(GROUP_REPLICATION_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_REPLICATION) @wsgi.action("failover_replication") def failover_replication(self, req, id, body): """Fails over replications for a group.""" @@ -457,7 +454,7 @@ class GroupsController(wsgi.Controller): return webob.Response(status_int=202) - @wsgi.Controller.api_version(GROUP_REPLICATION_API_VERSION) + @wsgi.Controller.api_version(mv.GROUP_REPLICATION) @wsgi.action("list_replication_targets") def list_replication_targets(self, req, id, body): """List replication targets for a group.""" diff --git a/cinder/api/v3/limits.py b/cinder/api/v3/limits.py index cc739a3df32..2e7b6988bd9 100644 --- a/cinder/api/v3/limits.py +++ b/cinder/api/v3/limits.py @@ -13,6 +13,7 @@ """The limits V3 api.""" +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v2 import limits as limits_v2 from cinder.api.views import limits as limits_views @@ -32,7 +33,8 @@ class LimitsController(limits_v2.LimitsController): # TODO(wangxiyuan): Support "tenant_id" here to keep the backwards # compatibility. Remove it once we drop all support for "tenant". - if req_version.matches(None, "3.38") or not context.is_admin: + if req_version.matches(None, + mv.GROUP_REPLICATION) or not context.is_admin: params.pop('project_id', None) params.pop('tenant_id', None) project_id = params.get( diff --git a/cinder/api/v3/messages.py b/cinder/api/v3/messages.py index ee1a789bbb4..c03e398b7f8 100644 --- a/cinder/api/v3/messages.py +++ b/cinder/api/v3/messages.py @@ -17,6 +17,7 @@ from six.moves import http_client import webob from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import messages as messages_view from cinder.message import api as message_api @@ -25,9 +26,6 @@ from cinder.message import message_field import cinder.policy -MESSAGES_BASE_MICRO_VERSION = '3.3' - - def check_policy(context, action, target_obj=None): target = { 'project_id': context.project_id, @@ -62,7 +60,7 @@ class MessagesController(wsgi.Controller): message_field.translate_action(message['action_id']), message_field.translate_detail(message['detail_id'])) - @wsgi.Controller.api_version(MESSAGES_BASE_MICRO_VERSION) + @wsgi.Controller.api_version(mv.MESSAGES) def show(self, req, id): """Return the given message.""" context = req.environ['cinder.context'] @@ -75,7 +73,7 @@ class MessagesController(wsgi.Controller): self._build_user_message(message) return self._view_builder.detail(req, message) - @wsgi.Controller.api_version(MESSAGES_BASE_MICRO_VERSION) + @wsgi.Controller.api_version(mv.MESSAGES) def delete(self, req, id): """Delete a message.""" context = req.environ['cinder.context'] @@ -87,7 +85,7 @@ class MessagesController(wsgi.Controller): return webob.Response(status_int=http_client.NO_CONTENT) - @wsgi.Controller.api_version(MESSAGES_BASE_MICRO_VERSION) + @wsgi.Controller.api_version(mv.MESSAGES) def index(self, req): """Returns a list of messages, transformed through view builder.""" context = req.environ['cinder.context'] @@ -100,14 +98,14 @@ class MessagesController(wsgi.Controller): sort_keys = None sort_dirs = None - if api_version.matches("3.5"): + if api_version.matches(mv.MESSAGES_PAGINATION): filters = req.params.copy() marker, limit, offset = common.get_pagination_params(filters) sort_keys, sort_dirs = common.get_sort_params(filters) - if api_version.matches(common.FILTERING_VERSION): + if api_version.matches(mv.RESOURCE_FILTER): support_like = (True if api_version.matches( - common.LIKE_FILTER_VERSION) else False) + mv.LIKE_FILTER) else False) common.reject_invalid_filters(context, filters, 'message', support_like) diff --git a/cinder/api/v3/resource_common_manage.py b/cinder/api/v3/resource_common_manage.py index 4265fca3df7..2d57b87a389 100644 --- a/cinder/api/v3/resource_common_manage.py +++ b/cinder/api/v3/resource_common_manage.py @@ -15,6 +15,7 @@ from cinder.api import common from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder import exception from cinder.i18n import _ @@ -41,13 +42,14 @@ class ManageResource(object): raise exception.VersionNotFoundForAPIMethod(version=version) def _get_resources(self, req, is_detail): - self._ensure_min_version(req, '3.8') + self._ensure_min_version(req, mv.MANAGE_EXISTING_LIST) context = req.environ['cinder.context'] self._authorizer(context) params = req.params.copy() - cluster_name, host = common.get_cluster_host(req, params, '3.17') + cluster_name, host = common.get_cluster_host( + req, params, mv.MANAGE_EXISTING_CLUSTER) marker, limit, offset = common.get_pagination_params(params) sort_keys, sort_dirs = common.get_sort_params(params, default_key='reference') diff --git a/cinder/api/v3/resource_filters.py b/cinder/api/v3/resource_filters.py index 955ae208980..e4cb32db672 100644 --- a/cinder/api/v3/resource_filters.py +++ b/cinder/api/v3/resource_filters.py @@ -13,13 +13,11 @@ """The resource filters api.""" from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import resource_filters as filter_views -FILTER_API_VERSION = '3.33' - - class ResourceFiltersController(wsgi.Controller): """The resource filter API controller for the OpenStack API.""" @@ -30,7 +28,7 @@ class ResourceFiltersController(wsgi.Controller): self.ext_mgr = ext_mgr super(ResourceFiltersController, self).__init__() - @wsgi.Controller.api_version(FILTER_API_VERSION) + @wsgi.Controller.api_version(mv.RESOURCE_FILTER_CONFIG) def index(self, req): """Return a list of resource filters.""" resource = req.params.get('resource', None) diff --git a/cinder/api/v3/snapshot_manage.py b/cinder/api/v3/snapshot_manage.py index ae9a54d60bf..baeef54bd2a 100644 --- a/cinder/api/v3/snapshot_manage.py +++ b/cinder/api/v3/snapshot_manage.py @@ -15,6 +15,7 @@ from six.moves import http_client from cinder.api.contrib import snapshot_manage as snapshot_manage_v2 +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3 import resource_common_manage as common @@ -27,7 +28,7 @@ class SnapshotManageController(common.ManageResource, @wsgi.response(http_client.ACCEPTED) def create(self, req, body): - self._ensure_min_version(req, "3.8") + self._ensure_min_version(req, mv.MANAGE_EXISTING_LIST) return super(SnapshotManageController, self).create(req, body) diff --git a/cinder/api/v3/snapshots.py b/cinder/api/v3/snapshots.py index 025e74fe09c..00c55a958df 100644 --- a/cinder/api/v3/snapshots.py +++ b/cinder/api/v3/snapshots.py @@ -20,6 +20,7 @@ import ast from oslo_log import log as logging from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v2 import snapshots as snapshots_v2 from cinder.api.v3.views import snapshots as snapshot_views @@ -56,9 +57,10 @@ class SnapshotsController(snapshots_v2.SnapshotsController): req_version=None): """Formats allowed filters""" - # if the max version is less than or same as 3.21 + # if the max version is less than SNAPSHOT_LIST_METADATA_FILTER # metadata based filtering is not supported - if req_version.matches(None, "3.21"): + if req_version.matches( + None, mv.get_prior_version(mv.SNAPSHOT_LIST_METADATA_FILTER)): filters.pop('metadata', None) # Filter out invalid options @@ -84,7 +86,7 @@ class SnapshotsController(snapshots_v2.SnapshotsController): self._format_snapshot_filter_options(search_opts) req_version = req.api_version_request - if req_version.matches("3.30", None) and 'name' in sort_keys: + if req_version.matches(mv.SNAPSHOT_SORT, None) and 'name' in sort_keys: sort_keys[sort_keys.index('name')] = 'display_name' # NOTE(thingee): v3 API allows name instead of display_name diff --git a/cinder/api/v3/views/groups.py b/cinder/api/v3/views/groups.py index 5b20c2928ed..90461f3d507 100644 --- a/cinder/api/v3/views/groups.py +++ b/cinder/api/v3/views/groups.py @@ -14,6 +14,7 @@ # under the License. from cinder.api import common +from cinder.api import microversions as mv from cinder import utils @@ -60,20 +61,21 @@ class ViewBuilder(common.ViewBuilder): req_version = request.api_version_request # Add group_snapshot_id and source_group_id if min version is greater - # than or equal to 3.14. - if req_version.matches("3.14", None): + # than or equal to GROUP_SNAPSHOTS. + if req_version.matches(mv.GROUP_SNAPSHOTS, None): group_ref['group']['group_snapshot_id'] = group.group_snapshot_id group_ref['group']['source_group_id'] = group.source_group_id - # Add volumes if min version is greater than or equal to 3.25. - if req_version.matches("3.25", None): + # Add volumes if min version is greater than or equal to + # GROUP_VOLUME_LIST. + if req_version.matches(mv.GROUP_VOLUME_LIST, None): if utils.get_bool_param('list_volume', request.params): group_ref['group']['volumes'] = [volume.id for volume in group.volumes] # Add replication_status if min version is greater than or equal - # to 3.38. - if req_version.matches("3.38", None): + # to GROUP_REPLICATION. + if req_version.matches(mv.GROUP_REPLICATION, None): group_ref['group']['replication_status'] = group.replication_status return group_ref diff --git a/cinder/api/v3/views/snapshots.py b/cinder/api/v3/views/snapshots.py index c5bd87005a5..857df059ca9 100644 --- a/cinder/api/v3/views/snapshots.py +++ b/cinder/api/v3/views/snapshots.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from cinder.api import microversions as mv from cinder.api.views import snapshots as views_v2 @@ -25,10 +26,10 @@ class ViewBuilder(views_v2.ViewBuilder): req_version = request.api_version_request # Add group_snapshot_id if min version is greater than or equal - # to 3.14. - if req_version.matches("3.14", None): + # to GROUP_SNAPSHOTS. + if req_version.matches(mv.GROUP_SNAPSHOTS, None): snapshot_ref['snapshot']['group_snapshot_id'] = ( snapshot.get('group_snapshot_id')) - if req_version.matches("3.41", None): + if req_version.matches(mv.SNAPSHOT_LIST_USER_ID, None): snapshot_ref['snapshot']['user_id'] = snapshot.get('user_id') return snapshot_ref diff --git a/cinder/api/v3/views/volumes.py b/cinder/api/v3/views/volumes.py index eb9b4058702..038d4e0f750 100644 --- a/cinder/api/v3/views/volumes.py +++ b/cinder/api/v3/views/volumes.py @@ -13,6 +13,7 @@ # License for the specific language governing permissions and limitations # under the License. +from cinder.api import microversions as mv from cinder.api.v2.views import volumes as views_v2 @@ -41,14 +42,14 @@ class ViewBuilder(views_v2.ViewBuilder): volume_ref = super(ViewBuilder, self).detail(request, volume) req_version = request.api_version_request - # Add group_id if min version is greater than or equal to 3.13. - if req_version.matches("3.13", None): + # Add group_id if min version is greater than or equal to GROUP_VOLUME. + if req_version.matches(mv.GROUP_VOLUME, None): volume_ref['volume']['group_id'] = volume.get('group_id') - # Add provider_id if min version is greater than or equal to 3.21 - # for admin. + # Add provider_id if min version is greater than or equal to + # VOLUME_DETAIL_PROVIDER_ID for admin. if (request.environ['cinder.context'].is_admin and - req_version.matches("3.21", None)): + req_version.matches(mv.VOLUME_DETAIL_PROVIDER_ID, None)): volume_ref['volume']['provider_id'] = volume.get('provider_id') return volume_ref diff --git a/cinder/api/v3/volume_manage.py b/cinder/api/v3/volume_manage.py index 4b2c5677e91..a09ddd5dd34 100644 --- a/cinder/api/v3/volume_manage.py +++ b/cinder/api/v3/volume_manage.py @@ -15,6 +15,7 @@ from six.moves import http_client from cinder.api.contrib import volume_manage as volume_manage_v2 +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3 import resource_common_manage as common @@ -27,7 +28,7 @@ class VolumeManageController(common.ManageResource, @wsgi.response(http_client.ACCEPTED) def create(self, req, body): - self._ensure_min_version(req, "3.8") + self._ensure_min_version(req, mv.MANAGE_EXISTING_LIST) return super(VolumeManageController, self).create(req, body) diff --git a/cinder/api/v3/volume_metadata.py b/cinder/api/v3/volume_metadata.py index 91f8d7d6f7a..27c2443d428 100644 --- a/cinder/api/v3/volume_metadata.py +++ b/cinder/api/v3/volume_metadata.py @@ -22,13 +22,11 @@ import six from six.moves import http_client import webob +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v2 import volume_metadata as volume_meta_v2 -METADATA_MICRO_VERSION = '3.15' - - class Controller(volume_meta_v2.Controller): """The volume metadata API controller for the OpenStack API.""" def _validate_etag(self, req, volume_id): @@ -46,7 +44,7 @@ class Controller(volume_meta_v2.Controller): def index(self, req, volume_id): req_version = req.api_version_request metadata = super(Controller, self).index(req, volume_id) - if req_version.matches(METADATA_MICRO_VERSION): + if req_version.matches(mv.ETAGS): data = jsonutils.dumps(metadata) if six.PY3: data = data.encode('utf-8') @@ -59,7 +57,7 @@ class Controller(volume_meta_v2.Controller): @wsgi.extends def update(self, req, volume_id, id, body): req_version = req.api_version_request - if req_version.matches(METADATA_MICRO_VERSION): + if req_version.matches(mv.ETAGS): if not self._validate_etag(req, volume_id): return webob.Response( status_int=http_client.PRECONDITION_FAILED) @@ -69,7 +67,7 @@ class Controller(volume_meta_v2.Controller): @wsgi.extends def update_all(self, req, volume_id, body): req_version = req.api_version_request - if req_version.matches(METADATA_MICRO_VERSION): + if req_version.matches(mv.ETAGS): if not self._validate_etag(req, volume_id): return webob.Response( status_int=http_client.PRECONDITION_FAILED) diff --git a/cinder/api/v3/volumes.py b/cinder/api/v3/volumes.py index 2674cf9f813..8f41694a5da 100644 --- a/cinder/api/v3/volumes.py +++ b/cinder/api/v3/volumes.py @@ -21,6 +21,7 @@ import webob from webob import exc from cinder.api import common +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v2 import volumes as volumes_v2 from cinder.api.v3.views import volumes as volume_views_v3 @@ -33,8 +34,6 @@ from cinder import utils LOG = logging.getLogger(__name__) -SUMMARY_BASE_MICRO_VERSION = '3.12' - def check_policy(context, action, target_obj=None): target = { @@ -65,7 +64,7 @@ class VolumeController(volumes_v2.VolumeController): force = False params = "" - if req_version.matches('3.23'): + if req_version.matches(mv.VOLUME_LIST_BOOTABLE): force = utils.get_bool_param('force', req.params) if cascade or force: params = "(cascade: %(c)s, force: %(f)s)" % {'c': cascade, @@ -88,10 +87,10 @@ class VolumeController(volumes_v2.VolumeController): @common.process_general_filtering('volume') def _process_volume_filtering(self, context=None, filters=None, req_version=None): - if req_version.matches(None, "3.3"): + if req_version.matches(None, mv.MESSAGES): filters.pop('glance_metadata', None) - if req_version.matches(None, "3.9"): + if req_version.matches(None, mv.BACKUP_UPDATE): filters.pop('group_id', None) utils.remove_invalid_filter_options( @@ -119,7 +118,8 @@ class VolumeController(volumes_v2.VolumeController): if 'name' in filters: filters['display_name'] = filters.pop('name') - strict = req.api_version_request.matches("3.2", None) + strict = req.api_version_request.matches( + mv.VOLUME_LIST_BOOTABLE, None) self.volume_api.check_volume_filters(filters, strict) volumes = self.volume_api.get_all(context, marker, limit, @@ -140,7 +140,7 @@ class VolumeController(volumes_v2.VolumeController): volumes = self._view_builder.summary_list(req, volumes) return volumes - @wsgi.Controller.api_version(SUMMARY_BASE_MICRO_VERSION) + @wsgi.Controller.api_version(mv.VOLUME_SUMMARY) def summary(self, req): """Return summary of volumes.""" view_builder_v3 = volume_views_v3.ViewBuilder() @@ -154,7 +154,7 @@ class VolumeController(volumes_v2.VolumeController): context, filters=filters) req_version = req.api_version_request - if req_version.matches("3.36"): + if req_version.matches(mv.VOLUME_SUMMARY_METADATA): all_distinct_metadata = metadata else: all_distinct_metadata = None @@ -163,7 +163,7 @@ class VolumeController(volumes_v2.VolumeController): all_distinct_metadata) @wsgi.response(http_client.ACCEPTED) - @wsgi.Controller.api_version('3.40') + @wsgi.Controller.api_version(mv.VOLUME_REVERT) @wsgi.action('revert') def revert(self, req, id, body): """revert a volume to a snapshot""" @@ -208,8 +208,8 @@ class VolumeController(volumes_v2.VolumeController): context = req.environ['cinder.context'] req_version = req.api_version_request - # Remove group_id from body if max version is less than 3.13. - if req_version.matches(None, "3.12"): + # Remove group_id from body if max version is less than GROUP_VOLUME. + if req_version.matches(None, mv.get_prior_version(mv.GROUP_VOLUME)): # NOTE(xyang): The group_id is from a group created with a # group_type. So with this group_id, we've got a group_type # for this volume. Also if group_id is passed in, that means diff --git a/cinder/api/v3/workers.py b/cinder/api/v3/workers.py index f38a5baa9cc..fa0a8540d46 100644 --- a/cinder/api/v3/workers.py +++ b/cinder/api/v3/workers.py @@ -16,6 +16,7 @@ from oslo_utils import timeutils from oslo_utils import uuidutils +from cinder.api import microversions as mv from cinder.api.openstack import wsgi from cinder.api.v3.views import workers as workers_view from cinder import db @@ -98,7 +99,7 @@ class WorkerController(wsgi.Controller): return params - @wsgi.Controller.api_version('3.24') + @wsgi.Controller.api_version(mv.WORKERS_CLEANUP) @wsgi.response(202) def cleanup(self, req, body=None): """Do the cleanup on resources from a specific service/host/node.""" diff --git a/cinder/api/versions.py b/cinder/api/versions.py index edaa5954883..4d51eccb8ea 100644 --- a/cinder/api/versions.py +++ b/cinder/api/versions.py @@ -51,7 +51,7 @@ _KNOWN_VERSIONS = { "status": "CURRENT", "version": api_version_request._MAX_API_VERSION, "min_version": api_version_request._MIN_API_VERSION, - "updated": "2016-02-08T12:20:21Z", + "updated": api_version_request.UPDATED, "links": _LINKS, "media-types": [{ "base": "application/json", diff --git a/cinder/api/views/backups.py b/cinder/api/views/backups.py index fee52bf225f..a4fec2abf55 100644 --- a/cinder/api/views/backups.py +++ b/cinder/api/views/backups.py @@ -14,6 +14,7 @@ # under the License. from cinder.api import common +from cinder.api import microversions as mv class ViewBuilder(common.ViewBuilder): @@ -78,7 +79,7 @@ class ViewBuilder(common.ViewBuilder): } } req_version = request.api_version_request - if req_version.matches("3.43"): + if req_version.matches(mv.BACKUP_METADATA): backup_dict['backup']['metadata'] = backup.metadata return backup_dict diff --git a/cinder/tests/tempest/api/volume/test_volume_revert.py b/cinder/tests/tempest/api/volume/test_volume_revert.py index b5151c59da8..bb7cde61644 100644 --- a/cinder/tests/tempest/api/volume/test_volume_revert.py +++ b/cinder/tests/tempest/api/volume/test_volume_revert.py @@ -24,7 +24,6 @@ CONF = config.CONF class VolumeRevertTests(volume_base.BaseVolumeTest): - min_microversion = '3.40' @classmethod def setup_clients(cls): diff --git a/cinder/tests/unit/api/contrib/test_admin_actions.py b/cinder/tests/unit/api/contrib/test_admin_actions.py index 4af9c794af8..9363a5cd420 100644 --- a/cinder/tests/unit/api/contrib/test_admin_actions.py +++ b/cinder/tests/unit/api/contrib/test_admin_actions.py @@ -23,7 +23,7 @@ import webob from webob import exc from cinder.api.contrib import admin_actions -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder.backup import api as backup_api from cinder.backup import rpcapi as backup_rpcapi from cinder.common import constants @@ -525,18 +525,16 @@ class AdminActionsTest(BaseAdminTest): force_host_copy=False, version=None, cluster=None): # build request to migrate to host - # req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action' % ( - # fake.PROJECT_ID, volume['id'])) req = webob.Request.blank('/v3/%s/volumes/%s/action' % ( fake.PROJECT_ID, volume['id'])) req.method = 'POST' req.headers['content-type'] = 'application/json' body = {'os-migrate_volume': {'host': host, 'force_host_copy': force_host_copy}} - version = version or '3.0' - req.headers = {'OpenStack-API-Version': 'volume %s' % version} - req.api_version_request = api_version.APIVersionRequest(version) - if version == '3.16': + version = version or mv.BASE_VERSION + req.headers = mv.get_mv_header(version) + req.api_version_request = mv.get_api_version(version) + if version == mv.VOLUME_MIGRATE_CLUSTER: body['os-migrate_volume']['cluster'] = cluster req.body = jsonutils.dump_as_bytes(body) req.environ['cinder.context'] = ctx @@ -547,7 +545,9 @@ class AdminActionsTest(BaseAdminTest): volume = db.volume_get(self.ctx, volume['id']) return volume - @ddt.data('3.0', '3.15', '3.16') + @ddt.data(mv.BASE_VERSION, + mv.get_prior_version(mv.VOLUME_MIGRATE_CLUSTER), + mv.VOLUME_MIGRATE_CLUSTER) def test_migrate_volume_success_3(self, version): expected_status = http_client.ACCEPTED host = 'test2' @@ -563,7 +563,8 @@ class AdminActionsTest(BaseAdminTest): cluster = 'cluster' volume = self._migrate_volume_prep() volume = self._migrate_volume_3_exec(self.ctx, volume, host, - expected_status, version='3.16', + expected_status, + version=mv.VOLUME_MIGRATE_CLUSTER, cluster=cluster) self.assertEqual('starting', volume['migration_status']) @@ -574,7 +575,8 @@ class AdminActionsTest(BaseAdminTest): volume = self._migrate_volume_prep() self.assertRaises(exception.InvalidInput, self._migrate_volume_3_exec, self.ctx, volume, host, - None, version='3.16', cluster=cluster) + None, version=mv.VOLUME_MIGRATE_CLUSTER, + cluster=cluster) def _migrate_volume_exec(self, ctx, volume, host, expected_status, force_host_copy=False): diff --git a/cinder/tests/unit/api/contrib/test_backup_project_attribute.py b/cinder/tests/unit/api/contrib/test_backup_project_attribute.py index d467ca0cbab..7e4c46830f6 100644 --- a/cinder/tests/unit/api/contrib/test_backup_project_attribute.py +++ b/cinder/tests/unit/api/contrib/test_backup_project_attribute.py @@ -17,7 +17,7 @@ import ddt from oslo_serialization import jsonutils import webob -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder.api.v3 import router as router_v3 from cinder.backup import api as backup_api from cinder import context @@ -57,7 +57,8 @@ class BackupProjectAttributeTest(test.TestCase): self.stubs.Set(backup_api.API, 'get', fake_backup_get) self.stubs.Set(backup_api.API, 'get_all', fake_backup_get_all) - def _send_backup_request(self, ctx, detail=False, version='3.18'): + def _send_backup_request(self, ctx, detail=False, + version=mv.BACKUP_PROJECT): req = None if detail: req = webob.Request.blank(('/v3/%s/backups/detail' @@ -67,8 +68,8 @@ class BackupProjectAttributeTest(test.TestCase): fake.BACKUP_ID)) req.method = 'GET' req.environ['cinder.context'] = ctx - req.headers['OpenStack-API-Version'] = 'volume ' + version - req.api_version_request = api_version.APIVersionRequest(version) + req.headers = mv.get_mv_header(version) + req.api_version_request = mv.get_api_version(version) res = req.get_response(app()) if detail: @@ -97,5 +98,6 @@ class BackupProjectAttributeTest(test.TestCase): def test_get_backup_under_allowed_api_version(self): ctx = context.RequestContext(fake.USER2_ID, fake.PROJECT_ID, True) - bak = self._send_backup_request(ctx, version='3.17') + bak = self._send_backup_request( + ctx, version=mv.get_prior_version(mv.BACKUP_PROJECT)) self.assertNotIn('os-backup-project-attr:project_id', bak) diff --git a/cinder/tests/unit/api/contrib/test_backups.py b/cinder/tests/unit/api/contrib/test_backups.py index 847c78df0fc..69bd7d3f638 100644 --- a/cinder/tests/unit/api/contrib/test_backups.py +++ b/cinder/tests/unit/api/contrib/test_backups.py @@ -25,6 +25,7 @@ from six.moves import http_client import webob from cinder.api.contrib import backups +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version # needed for stubs to work import cinder.backup @@ -117,8 +118,8 @@ class BackupsAPITestCase(test.TestCase): req = webob.Request.blank('/v3/%s/backups/%s' % ( fake.PROJECT_ID, backup.id)) req.method = 'GET' + req.headers = mv.get_mv_header(mv.BACKUP_METADATA) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.43' res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_context)) res_dict = jsonutils.loads(res.body) @@ -131,6 +132,7 @@ class BackupsAPITestCase(test.TestCase): req = webob.Request.blank('/v2/%s/backups/%s' % ( fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID)) req.method = 'GET' + req.headers = mv.get_mv_header(mv.BACKUP_METADATA) req.headers['Content-Type'] = 'application/json' res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_context)) @@ -330,9 +332,9 @@ class BackupsAPITestCase(test.TestCase): req = webob.Request.blank('/v3/%s/backups/detail' % fake.PROJECT_ID) req.method = 'GET' + req.headers = mv.get_mv_header(mv.BACKUP_METADATA) req.headers['Content-Type'] = 'application/json' req.headers['Accept'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.43' res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_context)) res_dict = jsonutils.loads(res.body) @@ -536,8 +538,8 @@ class BackupsAPITestCase(test.TestCase): } req = webob.Request.blank('/v3/%s/backups' % fake.PROJECT_ID) req.method = 'POST' + req.headers = mv.get_mv_header(mv.BACKUP_METADATA) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.43' req.body = jsonutils.dump_as_bytes(body) res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_context)) @@ -546,8 +548,8 @@ class BackupsAPITestCase(test.TestCase): req = webob.Request.blank('/v3/%s/backups/%s' % ( fake.PROJECT_ID, res_dict['backup']['id'])) req.method = 'GET' + req.headers = mv.get_mv_header(mv.BACKUP_METADATA) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.43' res = req.get_response(fakes.wsgi_app( fake_auth_context=self.user_context)) res_dict = jsonutils.loads(res.body) diff --git a/cinder/tests/unit/api/contrib/test_scheduler_stats.py b/cinder/tests/unit/api/contrib/test_scheduler_stats.py index 63ac4a673c3..d0262eb2668 100644 --- a/cinder/tests/unit/api/contrib/test_scheduler_stats.py +++ b/cinder/tests/unit/api/contrib/test_scheduler_stats.py @@ -19,6 +19,7 @@ import mock import webob from cinder.api.contrib import scheduler_stats +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder import context from cinder import exception @@ -84,7 +85,7 @@ class SchedulerStatsAPITest(test.TestCase): fake.PROJECT_ID) mock_rpcapi.return_value = [dict(name='pool1', capabilities=dict(foo='bar'))] - req.api_version_request = api_version.APIVersionRequest('3.28') + req.api_version_request = mv.get_api_version(mv.POOL_FILTER) req.environ['cinder.context'] = self.ctxt res = self.controller.get_pools(req) @@ -106,7 +107,7 @@ class SchedulerStatsAPITest(test.TestCase): '&foo=bar' % fake.PROJECT_ID) mock_rpcapi.return_value = [dict(name='pool1', capabilities=dict(foo='bar'))] - req.api_version_request = api_version.APIVersionRequest('3.28') + req.api_version_request = mv.get_api_version(mv.POOL_FILTER) req.environ['cinder.context'] = self.ctxt res = self.controller.get_pools(req) @@ -175,8 +176,8 @@ class SchedulerStatsAPITest(test.TestCase): self.controller.get_pools, req) - @ddt.data(('3.34', False), - ('3.35', True)) + @ddt.data((mv.get_prior_version(mv.POOL_TYPE_FILTER), False), + (mv.POOL_TYPE_FILTER, True)) @ddt.unpack @mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.get_pools') @mock.patch('cinder.api.common.reject_invalid_filters') diff --git a/cinder/tests/unit/api/contrib/test_services.py b/cinder/tests/unit/api/contrib/test_services.py index cf2fe948450..5bde460cd56 100644 --- a/cinder/tests/unit/api/contrib/test_services.py +++ b/cinder/tests/unit/api/contrib/test_services.py @@ -25,7 +25,7 @@ import webob.exc from cinder.api.contrib import services from cinder.api import extensions -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder import context from cinder import exception from cinder import objects @@ -114,10 +114,10 @@ fake_services_list = [ class FakeRequest(object): environ = {"cinder.context": context.get_admin_context()} - def __init__(self, version='3.0', **kwargs): + def __init__(self, version=mv.BASE_VERSION, **kwargs): self.GET = kwargs - self.headers = {'OpenStack-API-Version': 'volume ' + version} - self.api_version_request = api_version.APIVersionRequest(version) + self.headers = mv.get_mv_header(version) + self.api_version_request = mv.get_api_version(version) class FakeRequestWithBinary(FakeRequest): @@ -246,19 +246,19 @@ class ServicesTest(test.TestCase): self.assertEqual(response, res_dict) def test_failover_old_version(self): - req = FakeRequest(version='3.18') + req = FakeRequest(version=mv.BACKUP_PROJECT) self.assertRaises(exception.InvalidInput, self.controller.update, req, 'failover', {'cluster': 'cluster1'}) def test_failover_no_values(self): - req = FakeRequest(version='3.26') + req = FakeRequest(version=mv.REPLICATION_CLUSTER) self.assertRaises(exception.InvalidInput, self.controller.update, req, 'failover', {'backend_id': 'replica1'}) @ddt.data({'host': 'hostname'}, {'cluster': 'mycluster'}) @mock.patch('cinder.volume.api.API.failover') def test_failover(self, body, failover_mock): - req = FakeRequest(version='3.26') + req = FakeRequest(version=mv.REPLICATION_CLUSTER) body['backend_id'] = 'replica1' res = self.controller.update(req, 'failover', body) self.assertEqual(202, res.status_code) @@ -269,14 +269,14 @@ class ServicesTest(test.TestCase): @ddt.data({}, {'host': 'hostname', 'cluster': 'mycluster'}) @mock.patch('cinder.volume.api.API.failover') def test_failover_invalid_input(self, body, failover_mock): - req = FakeRequest(version='3.26') + req = FakeRequest(version=mv.REPLICATION_CLUSTER) body['backend_id'] = 'replica1' self.assertRaises(exception.InvalidInput, self.controller.update, req, 'failover', body) failover_mock.assert_not_called() def test_services_list_with_cluster_name(self): - req = FakeRequest(version='3.7') + req = FakeRequest(version=mv.CLUSTER_SUPPORT) res_dict = self.controller.index(req) response = {'services': [{'binary': 'cinder-scheduler', @@ -689,7 +689,7 @@ class ServicesTest(test.TestCase): def test_services_action_cluster_not_found(self, method, body, mock_get_all_services): url = '/v3/%s/os-services/%s' % (fake.PROJECT_ID, method) - req = fakes.HTTPRequest.blank(url, version='3.26') + req = fakes.HTTPRequest.blank(url, version=mv.REPLICATION_CLUSTER) mock_get_all_services.return_value = [] msg = 'No service found with cluster=%s' % mock.sentinel.cluster result = self.assertRaises(exception.InvalidInput, @@ -729,7 +729,7 @@ class ServicesTest(test.TestCase): @mock.patch('cinder.api.contrib.services.ServiceController._set_log') def test_set_log(self, set_log_mock): set_log_mock.return_value = None - req = FakeRequest(version='3.32') + req = FakeRequest(version=mv.LOG_LEVEL) body = mock.sentinel.body res = self.controller.update(req, 'set-log', body) self.assertEqual(set_log_mock.return_value, res) @@ -738,7 +738,7 @@ class ServicesTest(test.TestCase): @mock.patch('cinder.api.contrib.services.ServiceController._get_log') def test_get_log(self, get_log_mock): get_log_mock.return_value = None - req = FakeRequest(version='3.32') + req = FakeRequest(version=mv.LOG_LEVEL) body = mock.sentinel.body res = self.controller.update(req, 'get-log', body) self.assertEqual(get_log_mock.return_value, res) diff --git a/cinder/tests/unit/api/contrib/test_used_limits.py b/cinder/tests/unit/api/contrib/test_used_limits.py index cca43233d5a..7492e0ee5a0 100644 --- a/cinder/tests/unit/api/contrib/test_used_limits.py +++ b/cinder/tests/unit/api/contrib/test_used_limits.py @@ -17,6 +17,7 @@ import ddt import mock from cinder.api.contrib import used_limits +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request from cinder.api.openstack import wsgi from cinder import exception @@ -40,8 +41,11 @@ class UsedLimitsTestCase(test.TestCase): super(UsedLimitsTestCase, self).setUp() self.controller = used_limits.UsedLimitsController() - @ddt.data(('2.0', False), ('3.38', True), ('3.38', False), ('3.39', True), - ('3.39', False)) + @ddt.data(('2.0', False), + (mv.get_prior_version(mv.LIMITS_ADMIN_FILTER), True), + (mv.get_prior_version(mv.LIMITS_ADMIN_FILTER), False), + (mv.LIMITS_ADMIN_FILTER, True), + (mv.LIMITS_ADMIN_FILTER, False)) @mock.patch('cinder.quota.QUOTAS.get_project_quotas') @mock.patch('cinder.policy.enforce') def test_used_limits(self, ver_project, _mock_policy_enforce, @@ -78,9 +82,9 @@ class UsedLimitsTestCase(test.TestCase): self.controller.index(fake_req, res) abs_limits = res.obj['limits']['absolute'] - # if admin, only 3.39 and req contains project_id filter, cinder - # returns the specified project's quota. - if version == '3.39' and has_project: + # if admin, only LIMITS_ADMIN_FILTER and req contains project_id + # filter, cinder returns the specified project's quota. + if version == mv.LIMITS_ADMIN_FILTER and has_project: self.assertEqual(1, abs_limits['totalGigabytesUsed']) else: self.assertEqual(2, abs_limits['totalGigabytesUsed']) diff --git a/cinder/tests/unit/api/contrib/test_volume_actions.py b/cinder/tests/unit/api/contrib/test_volume_actions.py index 9b282106f0e..0ceedf6bcbd 100644 --- a/cinder/tests/unit/api/contrib/test_volume_actions.py +++ b/cinder/tests/unit/api/contrib/test_volume_actions.py @@ -24,7 +24,7 @@ from six.moves import http_client import webob from cinder.api.contrib import volume_actions -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder import context from cinder import db from cinder import exception @@ -818,7 +818,7 @@ class VolumeImageActionsTest(test.TestCase): 'size': 0} return ret - def fake_image_service_create_3_1(self, *args): + def fake_image_service_create_with_params(self, *args): ret = { 'status': u'queued', 'name': u'image_name', @@ -1017,13 +1017,13 @@ class VolumeImageActionsTest(test.TestCase): id, body) - @ddt.data({'version': '3.41', + @ddt.data({'version': mv.get_prior_version(mv.VOLUME_EXTEND_INUSE), 'status': 'available'}, - {'version': '3.41', + {'version': mv.get_prior_version(mv.VOLUME_EXTEND_INUSE), 'status': 'in-use'}, - {'version': '3.42', + {'version': mv.VOLUME_EXTEND_INUSE, 'status': 'available'}, - {'version': '3.42', + {'version': mv.VOLUME_EXTEND_INUSE, 'status': 'in-use'}) @ddt.unpack def test_extend_attached_volume(self, version, status): @@ -1035,9 +1035,9 @@ class VolumeImageActionsTest(test.TestCase): body = {"os-extend": {"new_size": 2}} req = fakes.HTTPRequest.blank('/v3/%s/volumes/%s/action' % (fake.PROJECT_ID, vol['id'])) - req.api_version_request = api_version.APIVersionRequest(version) + req.api_version_request = mv.get_api_version(version) self.controller._extend(req, vol['id'], body) - if version == '3.42' and status == 'in-use': + if version == mv.VOLUME_EXTEND_INUSE and status == 'in-use': mock_extend.assert_called_with(req.environ['cinder.context'], vol, 2, attached=True) else: @@ -1117,8 +1117,8 @@ class VolumeImageActionsTest(test.TestCase): id = 'aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee' req = fakes.HTTPRequest.blank('/v3/tenant1/volumes/%s/action' % id) req.environ['cinder.context'].is_admin = False - req.headers = {'OpenStack-API-Version': 'volume 3.1'} - req.api_version_request = api_version.APIVersionRequest('3.1') + req.headers = mv.get_mv_header(mv.UPLOAD_IMAGE_PARAMS) + req.api_version_request = mv.get_api_version(mv.UPLOAD_IMAGE_PARAMS) body = self._get_os_volume_upload_image() body['os-volume_upload_image']['visibility'] = 'public' self.assertRaises(exception.PolicyNotAuthorized, @@ -1311,7 +1311,7 @@ class VolumeImageActionsTest(test.TestCase): @mock.patch.object(volume_api.API, "get_volume_image_metadata") @mock.patch.object(glance.GlanceImageService, "create") @mock.patch.object(volume_rpcapi.VolumeAPI, "copy_volume_to_image") - def test_copy_volume_to_image_version_3_1( + def test_copy_volume_to_image_version_with_params( self, mock_copy_volume_to_image, mock_create, @@ -1323,7 +1323,7 @@ class VolumeImageActionsTest(test.TestCase): "volume_id": volume.id, "key": "x_billing_code_license", "value": "246254365"} - mock_create.side_effect = self.fake_image_service_create_3_1 + mock_create.side_effect = self.fake_image_service_create_with_params mock_copy_volume_to_image.side_effect = \ self.fake_rpc_copy_volume_to_image @@ -1333,8 +1333,8 @@ class VolumeImageActionsTest(test.TestCase): '/v3/%s/volumes/%s/action' % (fake.PROJECT_ID, volume.id), use_admin_context=self.context.is_admin) req.environ['cinder.context'].is_admin = True - req.headers = {'OpenStack-API-Version': 'volume 3.1'} - req.api_version_request = api_version.APIVersionRequest('3.1') + req.headers = mv.get_mv_header(mv.UPLOAD_IMAGE_PARAMS) + req.api_version_request = mv.get_api_version(mv.UPLOAD_IMAGE_PARAMS) body = self._get_os_volume_upload_image() body['os-volume_upload_image']['visibility'] = 'public' body['os-volume_upload_image']['protected'] = True diff --git a/cinder/tests/unit/api/contrib/test_volume_manage.py b/cinder/tests/unit/api/contrib/test_volume_manage.py index 5f6287f9497..34d07f591de 100644 --- a/cinder/tests/unit/api/contrib/test_volume_manage.py +++ b/cinder/tests/unit/api/contrib/test_volume_manage.py @@ -23,6 +23,7 @@ from six.moves.urllib.parse import urlencode import webob from cinder.api.contrib import volume_manage +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder import context from cinder import exception @@ -226,15 +227,15 @@ class VolumeManageTest(test.TestCase): self.assertEqual(body['volume']['ref'], args[3]) self.assertTrue(mock_validate.called) - def _get_resp_create(self, body, version='3.0'): + def _get_resp_create(self, body, version=mv.BASE_VERSION): url = '/v3/%s/os-volume-manage' % fake.PROJECT_ID req = webob.Request.blank(url, base_url='http://localhost.com' + url) req.method = 'POST' + req.headers = mv.get_mv_header(version) req.headers['Content-Type'] = 'application/json' req.environ['cinder.context'] = self._admin_ctxt req.body = jsonutils.dump_as_bytes(body) - req.headers = {'OpenStack-API-Version': 'volume %s' % version} - req.api_version_request = api_version.APIVersionRequest(version) + req.api_version_request = mv.get_api_version(version) res = self.controller.create(req, body) return res @@ -244,7 +245,7 @@ class VolumeManageTest(test.TestCase): def test_manage_volume_ok_cluster(self, mock_validate, mock_api_manage): body = {'volume': {'cluster': 'cluster', 'ref': 'fake_ref'}} - res = self._get_resp_create(body, '3.16') + res = self._get_resp_create(body, mv.VOLUME_MIGRATE_CLUSTER) self.assertEqual(['volume'], list(res.keys())) # Check that the manage API was called with the correct arguments. @@ -262,7 +263,8 @@ class VolumeManageTest(test.TestCase): 'cluster': 'cluster', 'ref': 'fake_ref'}} self.assertRaises(exception.InvalidInput, - self._get_resp_create, body, '3.16') + self._get_resp_create, body, + mv.VOLUME_MIGRATE_CLUSTER) def test_manage_volume_missing_host(self): """Test correct failure when host is not specified.""" @@ -485,7 +487,7 @@ class VolumeManageTest(test.TestCase): """Test managing volume to return 'creating' status in V3 API.""" body = {'volume': {'host': 'host_ok', 'ref': 'fake_ref'}} - res = self._get_resp_post_v3(body, '3.15') + res = self._get_resp_post_v3(body, mv.ETAGS) self.assertEqual(http_client.ACCEPTED, res.status_int) self.assertEqual(1, mock_api_manage.call_count) self.assertEqual('creating', diff --git a/cinder/tests/unit/api/v3/test_attachments.py b/cinder/tests/unit/api/v3/test_attachments.py index 950106672cd..f780f9d5b8f 100644 --- a/cinder/tests/unit/api/v3/test_attachments.py +++ b/cinder/tests/unit/api/v3/test_attachments.py @@ -21,6 +21,7 @@ import ddt import mock import webob +from cinder.api import microversions as mv from cinder.api.v3 import attachments as v3_attachments from cinder import context from cinder import exception @@ -31,8 +32,6 @@ from cinder.tests.unit import fake_constants as fake from cinder.volume import api as volume_api from cinder.volume import rpcapi as volume_rpcapi -ATTACHMENTS_MICRO_VERSION = '3.27' - @ddt.ddt class AttachmentsAPITestCase(test.TestCase): @@ -81,7 +80,7 @@ class AttachmentsAPITestCase(test.TestCase): def test_create_attachment(self): req = fakes.HTTPRequest.blank('/v3/%s/attachments' % fake.PROJECT_ID, - version=ATTACHMENTS_MICRO_VERSION) + version=mv.NEW_ATTACH) body = { "attachment": { @@ -104,7 +103,7 @@ class AttachmentsAPITestCase(test.TestCase): mock_update.return_value = fake_connector req = fakes.HTTPRequest.blank('/v3/%s/attachments/%s' % (fake.PROJECT_ID, self.attachment1.id), - version=ATTACHMENTS_MICRO_VERSION, + version=mv.NEW_ATTACH, use_admin_context=True) body = { "attachment": @@ -124,7 +123,7 @@ class AttachmentsAPITestCase(test.TestCase): mock_get.return_value = {'project_id': fake.PROJECT2_ID} req = fakes.HTTPRequest.blank('/v3/%s/attachments/%s' % (fake.PROJECT_ID, self.attachment1.id), - version=ATTACHMENTS_MICRO_VERSION, + version=mv.NEW_ATTACH, use_admin_context=False) body = { "attachment": @@ -139,7 +138,8 @@ class AttachmentsAPITestCase(test.TestCase): self.controller.delete, req, self.attachment1.id) - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_attachment_list_with_general_filter(self, version, mock_update): url = '/v3/%s/attachments' % fake.PROJECT_ID @@ -148,8 +148,8 @@ class AttachmentsAPITestCase(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'attachment', support_like) @@ -164,7 +164,7 @@ class AttachmentsAPITestCase(test.TestCase): attach_status=status) req = fakes.HTTPRequest.blank('/v3/%s/attachments/%s' % (fake.PROJECT_ID, attachment.id), - version=ATTACHMENTS_MICRO_VERSION, + version=mv.NEW_ATTACH, use_admin_context=True) self.controller.delete(req, attachment.id) @@ -201,7 +201,7 @@ class AttachmentsAPITestCase(test.TestCase): def test_create_attachment_without_resource_uuid(self, resource_uuid): req = fakes.HTTPRequest.blank('/v3/%s/attachments' % fake.PROJECT_ID, - version=ATTACHMENTS_MICRO_VERSION) + version=mv.NEW_ATTACH) body = { "attachment": { @@ -220,7 +220,7 @@ class AttachmentsAPITestCase(test.TestCase): if is_detail: url = '/v3/%s/groups/detail' % fake.PROJECT_ID list_func = self.controller.detail - req = fakes.HTTPRequest.blank(url, version=ATTACHMENTS_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.NEW_ATTACH, use_admin_context=True) res_dict = list_func(req) @@ -231,7 +231,7 @@ class AttachmentsAPITestCase(test.TestCase): def test_list_attachments_with_limit(self): url = '/v3/%s/attachments?limit=1' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=ATTACHMENTS_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.NEW_ATTACH, use_admin_context=True) res_dict = self.controller.index(req) @@ -241,7 +241,7 @@ class AttachmentsAPITestCase(test.TestCase): def test_list_attachments_with_marker(self): url = '/v3/%s/attachments?marker=%s' % (fake.PROJECT_ID, self.attachment3.id) - req = fakes.HTTPRequest.blank(url, version=ATTACHMENTS_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.NEW_ATTACH, use_admin_context=True) res_dict = self.controller.index(req) @@ -254,7 +254,7 @@ class AttachmentsAPITestCase(test.TestCase): def test_list_attachments_with_sort(self, sort_dir): url = '/v3/%s/attachments?sort_key=id&sort_dir=%s' % (fake.PROJECT_ID, sort_dir) - req = fakes.HTTPRequest.blank(url, version=ATTACHMENTS_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.NEW_ATTACH, use_admin_context=True) res_dict = self.controller.index(req) @@ -280,7 +280,7 @@ class AttachmentsAPITestCase(test.TestCase): @ddt.unpack def test_list_attachment_with_tenants(self, admin, request_url, count): url = '/v3/%s/attachments%s' % (fake.PROJECT_ID, request_url) - req = fakes.HTTPRequest.blank(url, version=ATTACHMENTS_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.NEW_ATTACH, use_admin_context=admin) res_dict = self.controller.index(req) diff --git a/cinder/tests/unit/api/v3/test_backups.py b/cinder/tests/unit/api/v3/test_backups.py index 33fdabae805..d055c6513d6 100644 --- a/cinder/tests/unit/api/v3/test_backups.py +++ b/cinder/tests/unit/api/v3/test_backups.py @@ -19,6 +19,7 @@ import ddt import mock import webob +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder.api.v3 import backups from cinder.api.views import backups as backup_view @@ -44,7 +45,7 @@ class BackupsControllerAPITestCase(test.TestCase): is_admin=True) self.controller = backups.BackupsController() - def _fake_update_request(self, backup_id, version='3.9'): + def _fake_update_request(self, backup_id, version=mv.BACKUP_UPDATE): req = fakes.HTTPRequest.blank('/v3/%s/backups/%s/update' % (fake.PROJECT_ID, backup_id)) req.environ['cinder.context'].is_admin = True @@ -54,7 +55,8 @@ class BackupsControllerAPITestCase(test.TestCase): return req def test_update_wrong_version(self): - req = self._fake_update_request(fake.BACKUP_ID, version='3.6') + req = self._fake_update_request( + fake.BACKUP_ID, version=mv.get_prior_version(mv.BACKUP_UPDATE)) body = {"backup": {"name": "Updated Test Name", }} self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.update, req, fake.BACKUP_ID, @@ -86,7 +88,9 @@ class BackupsControllerAPITestCase(test.TestCase): self.controller.update, req, fake.BACKUP_ID, body) - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, + mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_backup_list_with_general_filter(self, version, mock_update): url = '/v3/%s/backups' % fake.PROJECT_ID @@ -95,13 +99,14 @@ class BackupsControllerAPITestCase(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'backup', support_like) - @ddt.data('3.36', '3.37') + @ddt.data(mv.get_prior_version(mv.BACKUP_SORT_NAME), + mv.BACKUP_SORT_NAME) def test_backup_list_with_name(self, version): backup1 = test_utils.create_backup( self.ctxt, display_name='b_test_name', @@ -111,7 +116,7 @@ class BackupsControllerAPITestCase(test.TestCase): status=fields.BackupStatus.AVAILABLE) url = '/v3/%s/backups?sort_key=name' % fake.PROJECT_ID req = fakes.HTTPRequest.blank(url, version=version) - if version == '3.36': + if version == mv.get_prior_version(mv.BACKUP_SORT_NAME): self.assertRaises(exception.InvalidInput, self.controller.index, req) diff --git a/cinder/tests/unit/api/v3/test_cluster.py b/cinder/tests/unit/api/v3/test_cluster.py index a08fbede992..9e82af9578d 100644 --- a/cinder/tests/unit/api/v3/test_cluster.py +++ b/cinder/tests/unit/api/v3/test_cluster.py @@ -21,6 +21,7 @@ import mock from oslo_utils import versionutils from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder.api.v3 import clusters from cinder import context @@ -78,7 +79,7 @@ EXPECTED = [{'created_at': datetime.datetime(2016, 6, 1, 2, 46, 28), class FakeRequest(object): - def __init__(self, is_admin=True, version='3.7', **kwargs): + def __init__(self, is_admin=True, version=mv.CLUSTER_SUPPORT, **kwargs): self.GET = kwargs self.headers = {'OpenStack-API-Version': 'volume ' + version} self.api_version_request = api_version.APIVersionRequest(version) @@ -108,8 +109,10 @@ class ClustersTestCase(test.TestCase): REPLICATION_FILTERS = ({'replication_status': 'error'}, {'frozen': True}, {'active_backend_id': 'replication'}) - def _get_expected(self, version='3.8'): - if versionutils.convert_version_to_tuple(version) >= (3, 19): + def _get_expected(self, + version=mv.get_prior_version(mv.REPLICATION_CLUSTER)): + if (versionutils.convert_version_to_tuple(version) >= + versionutils.convert_version_to_tuple(mv.REPLICATION_CLUSTER)): return EXPECTED expect = [] @@ -130,7 +133,7 @@ class ClustersTestCase(test.TestCase): @mock.patch('cinder.db.cluster_get_all', return_value=CLUSTERS_ORM) def _test_list(self, get_all_mock, detailed, filters=None, expected=None, - version='3.8'): + version=mv.get_prior_version(mv.REPLICATION_CLUSTER)): filters = filters or {} req = FakeRequest(version=version, **filters) method = getattr(self.controller, 'detail' if detailed else 'index') @@ -187,14 +190,13 @@ class ClustersTestCase(test.TestCase): """Verify the wrong version so that user can't list clusters.""" self.assertRaises(exception.VersionNotFoundForAPIMethod, self._test_list, detailed=detailed, - version='3.6') + version=mv.get_prior_version(mv.CLUSTER_SUPPORT)) @ddt.data(*REPLICATION_FILTERS) def test_index_detail_replication_new_fields(self, filters): - version = '3.26' - expected = {'clusters': self._get_expected(version)} + expected = {'clusters': self._get_expected(mv.REPLICATION_CLUSTER)} self._test_list(detailed=True, filters=filters, expected=expected, - version=version) + version=mv.REPLICATION_CLUSTER) @ddt.data(*REPLICATION_FILTERS) def test_index_summary_replication_new_fields(self, filters): @@ -209,7 +211,7 @@ class ClustersTestCase(test.TestCase): 'replication_status': 'error', 'status': 'disabled'}]} self._test_list(detailed=False, filters=filters, expected=expected, - version='3.26') + version=mv.REPLICATION_CLUSTER) @mock.patch('cinder.db.sqlalchemy.api.cluster_get', return_value=CLUSTERS_ORM[0]) @@ -232,7 +234,7 @@ class ClustersTestCase(test.TestCase): self.controller.show, req, 'name') def test_show_wrong_version(self): - req = FakeRequest(version='3.5') + req = FakeRequest(version=mv.get_prior_version(mv.CLUSTER_SUPPORT)) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.show, req, 'name') @@ -307,6 +309,6 @@ class ClustersTestCase(test.TestCase): @ddt.data('enable', 'disable') def test_update_wrong_version(self, action): - req = FakeRequest(version='3.5') + req = FakeRequest(version=mv.get_prior_version(mv.CLUSTER_SUPPORT)) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.update, req, action, {}) diff --git a/cinder/tests/unit/api/v3/test_consistencygroups.py b/cinder/tests/unit/api/v3/test_consistencygroups.py index ece7524ab04..b6e7aefdcc3 100644 --- a/cinder/tests/unit/api/v3/test_consistencygroups.py +++ b/cinder/tests/unit/api/v3/test_consistencygroups.py @@ -15,6 +15,7 @@ import ddt from six.moves import http_client import webob +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder.api.v3 import consistencygroups from cinder import context @@ -72,9 +73,10 @@ class ConsistencyGroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/consistencygroups/%s/update' % (fake.PROJECT_ID, consistencygroup.id)) req.environ['cinder.context'].is_admin = True + req.headers = mv.get_mv_header(mv.CG_UPDATE_BLANK_PROPERTIES) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.6' - req.api_version_request = api_version.APIVersionRequest('3.6') + req.api_version_request = mv.get_api_version( + mv.CG_UPDATE_BLANK_PROPERTIES) body = {"consistencygroup": {"name": "", "description": "", "add_volumes": None, @@ -118,9 +120,10 @@ class ConsistencyGroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/consistencygroups/%s/update' % (fake.PROJECT_ID, consistencygroup.id)) req.environ['cinder.context'].is_admin = True + req.headers = mv.get_mv_header(mv.CG_UPDATE_BLANK_PROPERTIES) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.6' - req.api_version_request = api_version.APIVersionRequest('3.6') + req.api_version_request = mv.get_api_version( + mv.CG_UPDATE_BLANK_PROPERTIES) body = {"consistencygroup": {"name": None, "description": None, "add_volumes": None, @@ -132,16 +135,20 @@ class ConsistencyGroupsAPITestCase(test.TestCase): req, consistencygroup.id, body) consistencygroup.destroy() - def test_update_consistencygroup_all_empty_parameters_not_version_36(self): + def test_update_consistencygroup_all_empty_parameters_not_version_ok(self): consistencygroup = self._create_consistencygroup( ctxt=self.ctxt, status=fields.ConsistencyGroupStatus.AVAILABLE) req = fakes.HTTPRequest.blank('/v3/%s/consistencygroups/%s/update' % (fake.PROJECT_ID, consistencygroup.id)) req.environ['cinder.context'].is_admin = True + + non_supported_version = mv.get_prior_version( + mv.CG_UPDATE_BLANK_PROPERTIES) + req.headers = mv.get_mv_header(non_supported_version) + req.api_version_request = mv.get_api_version(non_supported_version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.5' - req.api_version_request = api_version.APIVersionRequest('3.5') + body = {"consistencygroup": {"name": None, "description": None, "add_volumes": None, @@ -160,9 +167,13 @@ class ConsistencyGroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/consistencygroups/%s/update' % (fake.PROJECT_ID, consistencygroup.id)) req.environ['cinder.context'].is_admin = True + + non_supported_version = mv.get_prior_version( + mv.CG_UPDATE_BLANK_PROPERTIES) + req.headers = mv.get_mv_header(non_supported_version) + req.api_version_request = mv.get_api_version(non_supported_version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.5' - req.api_version_request = api_version.APIVersionRequest('3.5') + body = None self.assertRaisesRegexp(webob.exc.HTTPBadRequest, "Missing request body", @@ -177,9 +188,13 @@ class ConsistencyGroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/consistencygroups/%s/update' % (fake.PROJECT_ID, consistencygroup.id)) req.environ['cinder.context'].is_admin = True + + non_supported_version = mv.get_prior_version( + mv.CG_UPDATE_BLANK_PROPERTIES) + req.headers = mv.get_mv_header(non_supported_version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume 3.5' - req.api_version_request = api_version.APIVersionRequest('3.5') + + req.api_version_request = mv.get_api_version(non_supported_version) body = {"consistencygroup": {"name": "my_fake_cg", "description": "fake consistency group", "add_volumes": "volume-uuid-1", diff --git a/cinder/tests/unit/api/v3/test_group_snapshots.py b/cinder/tests/unit/api/v3/test_group_snapshots.py index d464c4e5f90..3d230ecc0af 100644 --- a/cinder/tests/unit/api/v3/test_group_snapshots.py +++ b/cinder/tests/unit/api/v3/test_group_snapshots.py @@ -22,6 +22,7 @@ import mock from six.moves import http_client import webob +from cinder.api import microversions as mv from cinder.api.v3 import group_snapshots as v3_group_snapshots from cinder import context from cinder import db @@ -35,9 +36,6 @@ from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import utils import cinder.volume -GROUP_MICRO_VERSION = '3.14' -SUPPORT_FILTER_VERSION = '3.29' - @ddt.ddt class GroupSnapshotsAPITestCase(test.TestCase): @@ -76,7 +74,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): self.context, group_id=self.group.id) req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, group_snapshot.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) res_dict = self.controller.show(req, group_snapshot.id) self.assertEqual(1, len(res_dict)) @@ -95,7 +93,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): url = '/v3/%s/group_snapshots?limit=1' % fake.PROJECT_ID if is_detail: url = '/v3/%s/group_snapshots/detail?limit=1' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION) + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION) if is_detail: res_dict = self.controller.detail(req) else: @@ -122,7 +121,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): url = '/v3/%s/group_snapshots?offset=1' % fake.PROJECT_ID if is_detail: url = '/v3/%s/group_snapshots/detail?offset=1' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION) + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION) if is_detail: res_dict = self.controller.detail(req) else: @@ -146,7 +146,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/group_snapshots/detail?offset=234523423455454' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION) + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION) if is_detail: self.assertRaises(webob.exc.HTTPBadRequest, self.controller.detail, req) @@ -164,7 +165,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/group_snapshots/detail?limit=2&offset=1' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION) + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION) if is_detail: res_dict = self.controller.detail(req) else: @@ -184,7 +186,9 @@ class GroupSnapshotsAPITestCase(test.TestCase): res_dict['group_snapshots'][0].keys()) group_snapshot.destroy() - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, + mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_group_snapshot_list_with_general_filter(self, version, mock_update): @@ -194,8 +198,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'group_snapshot', support_like) @@ -209,7 +213,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): url = ('/v3/%s/group_snapshots/detail?' 'all_tenants=True&id=%s') % (fake.PROJECT_ID, self.g_snapshots_array[0].id) - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION, + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION, use_admin_context=True) if is_detail: res_dict = self.controller.detail(req) @@ -226,10 +231,10 @@ class GroupSnapshotsAPITestCase(test.TestCase): self.assertNotIn('description', res_dict['group_snapshots'][0].keys()) - @ddt.data({'is_detail': True, 'version': GROUP_MICRO_VERSION}, - {'is_detail': False, 'version': GROUP_MICRO_VERSION}, - {'is_detail': True, 'version': '3.28'}, - {'is_detail': False, 'version': '3.28'},) + @ddt.data({'is_detail': True, 'version': mv.GROUP_SNAPSHOTS}, + {'is_detail': False, 'version': mv.GROUP_SNAPSHOTS}, + {'is_detail': True, 'version': mv.POOL_FILTER}, + {'is_detail': False, 'version': mv.POOL_FILTER},) @ddt.unpack def test_list_group_snapshot_with_filter_previous_version(self, is_detail, version): @@ -257,7 +262,8 @@ class GroupSnapshotsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/group_snapshots/detail?sort=id:asc' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=SUPPORT_FILTER_VERSION) + req = fakes.HTTPRequest.blank(url, + version=mv.GROUP_SNAPSHOT_PAGINATION) expect_result = [snapshot.id for snapshot in self.g_snapshots_array] expect_result.sort() if is_detail: @@ -282,7 +288,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(exception.GroupSnapshotNotFound, self.controller.show, req, fake.WILL_NOT_BE_FOUND_ID) @@ -294,7 +300,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): else: request_url = '/v3/%s/group_snapshots' req = fakes.HTTPRequest.blank(request_url % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) if is_detail: res_dict = self.controller.detail(req) else: @@ -326,7 +332,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): "group_id": self.group.id}} req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) res_dict = self.controller.create(req, body) self.assertEqual(1, len(res_dict)) @@ -356,7 +362,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): "group_id": group.id}} req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) self.assertTrue(mock_validate.called) @@ -369,7 +375,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): # omit body from the request req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, None) @@ -383,7 +389,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): "group_id": self.group.id}} req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) @@ -397,7 +403,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): "group_id": self.group.id}} req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(exception.GroupSnapshotNotFound, self.controller.create, req, body) @@ -413,7 +419,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): "group_id": empty_group.id}} req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) @@ -426,7 +432,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): status=fields.GroupSnapshotStatus.AVAILABLE) req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, group_snapshot.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) res_dict = self.controller.delete(req, group_snapshot.id) group_snapshot = objects.GroupSnapshot.get_by_id(self.context, @@ -450,7 +456,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): volume_type_ids=[fake.VOLUME_TYPE_ID],) req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, group_snapshot.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete, req, group_snapshot.id) @@ -461,7 +467,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(exception.GroupSnapshotNotFound, self.controller.delete, req, fake.WILL_NOT_BE_FOUND_ID) @@ -473,19 +479,20 @@ class GroupSnapshotsAPITestCase(test.TestCase): status='invalid') req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s' % (fake.PROJECT_ID, group_snapshot.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete, req, group_snapshot.id) group_snapshot.destroy() - @ddt.data(('3.11', 'fake_snapshot_001', + @ddt.data((mv.GROUP_TYPE, 'fake_snapshot_001', fields.GroupSnapshotStatus.AVAILABLE, exception.VersionNotFoundForAPIMethod), - ('3.18', 'fake_snapshot_001', + (mv.get_prior_version(mv.GROUP_SNAPSHOT_RESET_STATUS), + 'fake_snapshot_001', fields.GroupSnapshotStatus.AVAILABLE, exception.VersionNotFoundForAPIMethod), - ('3.19', 'fake_snapshot_001', + (mv.GROUP_SNAPSHOT_RESET_STATUS, 'fake_snapshot_001', fields.GroupSnapshotStatus.AVAILABLE, exception.GroupSnapshotNotFound)) @ddt.unpack @@ -509,7 +516,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): status=fields.GroupSnapshotStatus.CREATING) req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s/action' % (fake.PROJECT_ID, group_snapshot.id), - version='3.19') + version=mv.GROUP_SNAPSHOT_RESET_STATUS) body = {"reset_status": { "status": "invalid_test_status" }} @@ -525,7 +532,7 @@ class GroupSnapshotsAPITestCase(test.TestCase): status=fields.GroupSnapshotStatus.CREATING) req = fakes.HTTPRequest.blank('/v3/%s/group_snapshots/%s/action' % (fake.PROJECT_ID, group_snapshot.id), - version='3.19') + version=mv.GROUP_SNAPSHOT_RESET_STATUS) body = {"reset_status": { "status": fields.GroupSnapshotStatus.AVAILABLE }} diff --git a/cinder/tests/unit/api/v3/test_group_specs.py b/cinder/tests/unit/api/v3/test_group_specs.py index 4c15d75b612..6ab66a09a59 100644 --- a/cinder/tests/unit/api/v3/test_group_specs.py +++ b/cinder/tests/unit/api/v3/test_group_specs.py @@ -21,12 +21,11 @@ from cinder import db from cinder import rpc from cinder import test +from cinder.api import microversions as mv from cinder.api.v3 import group_specs as v3_group_specs from cinder.tests.unit.api import fakes from cinder.tests.unit import fake_constants as fake -GROUP_TYPE_MICRO_VERSION = '3.11' - fake_group_specs = { 'key1': 'value1', 'key2': 'value2' @@ -71,7 +70,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req, fake.GROUP_ID) group_specs_dict = res_dict['group_specs'] @@ -90,7 +89,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.controller.create(req, fake.GROUP_ID, create_fake_group_specs) self.assertTrue(mock_rpc_notifier.called) @@ -108,7 +107,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.controller.update(req, fake.GROUP_TYPE_ID, 'id', @@ -124,7 +123,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) res_dict = self.controller.show(req, fake.GROUP_TYPE_ID, 'key1') self.assertEqual('value1', res_dict['key1']) @@ -138,7 +137,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.controller.delete(req, fake.GROUP_TYPE_ID, 'key1') self.assertTrue(rpc_notifier_mock.called) @@ -151,7 +150,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPNotFound, self.controller.create, req, @@ -166,7 +165,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, @@ -178,7 +177,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update, req, @@ -198,7 +197,7 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, @@ -216,6 +215,6 @@ class GroupSpecsTestCase(test.TestCase): req = fakes.HTTPRequest.blank('v3/%s/group_specs' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, fake.GROUP_ID, incorrect_fake_group_specs) diff --git a/cinder/tests/unit/api/v3/test_group_types.py b/cinder/tests/unit/api/v3/test_group_types.py index 48ea6a6f43e..b979e108ee1 100644 --- a/cinder/tests/unit/api/v3/test_group_types.py +++ b/cinder/tests/unit/api/v3/test_group_types.py @@ -23,6 +23,7 @@ import six import webob import cinder.api.common as common +from cinder.api import microversions as mv from cinder.api.v3 import group_specs as v3_group_specs from cinder.api.v3 import group_types as v3_group_types from cinder.api.v3.views import group_types as views_types @@ -33,7 +34,6 @@ from cinder.tests.unit.api import fakes from cinder.tests.unit import fake_constants as fake from cinder.volume import group_types -GROUP_TYPE_MICRO_VERSION = '3.11' IN_USE_GROUP_TYPE = fake.GROUP_TYPE3_ID @@ -132,7 +132,7 @@ class GroupTypesApiTest(test.TestCase): mock_create, mock_get): boolean_is_public = strutils.bool_from_string(is_public) req = fakes.HTTPRequest.blank('/v3/%s/types' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt body = {"group_type": {"is_public": is_public, "name": "group_type1", @@ -157,7 +157,7 @@ class GroupTypesApiTest(test.TestCase): '_notify_group_type_error') req = fakes.HTTPRequest.blank('/v3/%s/group_types/%s' % ( fake.PROJECT_ID, grp_type_id), - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt if grp_type_id == IN_USE_GROUP_TYPE: self.assertRaises(webob.exc.HTTPBadRequest, @@ -177,7 +177,7 @@ class GroupTypesApiTest(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/group_types' % fake.PROJECT_ID, use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) res_dict = self.controller.index(req) self.assertEqual(3, len(res_dict['group_types'])) @@ -193,7 +193,7 @@ class GroupTypesApiTest(test.TestCase): return_empty_group_types_get_all_types) req = fakes.HTTPRequest.blank('/v3/%s/group_types' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) res_dict = self.controller.index(req) self.assertEqual(0, len(res_dict['group_types'])) @@ -201,7 +201,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_limit(self): req = fakes.HTTPRequest.blank('/v3/%s/group_types?limit=1' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -216,7 +216,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_offset(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?offset=1' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -224,14 +224,14 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_offset_out_of_range(self): url = '/v3/%s/group_types?offset=424366766556787' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=GROUP_TYPE_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req) def test_group_types_index_with_limit_and_offset(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?limit=2&offset=1' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -244,7 +244,7 @@ class GroupTypesApiTest(test.TestCase): '&marker=%s' % (fake.PROJECT_ID, self.type_id2), - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -254,7 +254,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_valid_filter(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?is_public=True' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -267,7 +267,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_invalid_filter(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?id=%s' % (fake.PROJECT_ID, self.type_id1), - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) @@ -276,7 +276,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_sort_keys(self): req = fakes.HTTPRequest.blank('/v3/%s/group_types?sort=id' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) expect_result = [self.type_id0, self.type_id1, self.type_id2, @@ -292,7 +292,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_sort_and_limit(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?sort=id&limit=2' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) expect_result = [self.type_id0, self.type_id1, self.type_id2, @@ -306,7 +306,7 @@ class GroupTypesApiTest(test.TestCase): def test_group_types_index_with_sort_keys_and_sort_dirs(self): req = fakes.HTTPRequest.blank( '/v3/%s/group_types?sort=id:asc' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt res = self.controller.index(req) expect_result = [self.type_id0, self.type_id1, self.type_id2, @@ -332,7 +332,7 @@ class GroupTypesApiTest(test.TestCase): type_id = six.text_type(uuid.uuid4()) req = fakes.HTTPRequest.blank( '/v3/%s/types/%s' % (fake.PROJECT_ID, type_id), - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.environ['cinder.context'] = self.ctxt body = {"group_type": {"is_public": is_public, "name": "group_type1"}} self.controller.update(req, type_id, body) @@ -347,7 +347,7 @@ class GroupTypesApiTest(test.TestCase): type_id = six.text_type(uuid.uuid4()) req = fakes.HTTPRequest.blank('/v3/%s/group_types/' % fake.PROJECT_ID + type_id, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) res_dict = self.controller.show(req, type_id) self.assertEqual(1, len(res_dict)) @@ -359,10 +359,10 @@ class GroupTypesApiTest(test.TestCase): self.mock_object(group_types, 'get_group_type', return_group_types_get_group_type) - type_id = six.text_type(uuid.uuid4()) - req = fakes.HTTPRequest.blank('/v3/%s/group_types/' % fake.PROJECT_ID - + type_id, - version='3.5') + type_id = uuid.uuid4() + req = fakes.HTTPRequest.blank( + '/v3/%s/group_types/%s' % (fake.PROJECT_ID, type_id), + version=mv.get_prior_version(mv.GROUP_TYPE)) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.show, req, type_id) @@ -374,7 +374,7 @@ class GroupTypesApiTest(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/group_types/%s' % (fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID), - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, fake.WILL_NOT_BE_FOUND_ID) @@ -383,7 +383,7 @@ class GroupTypesApiTest(test.TestCase): return_group_types_get_default) req = fakes.HTTPRequest.blank('/v3/%s/group_types/default' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.method = 'GET' res_dict = self.controller.show(req, 'default') self.assertEqual(1, len(res_dict)) @@ -396,7 +396,7 @@ class GroupTypesApiTest(test.TestCase): return_group_types_get_default_not_found) req = fakes.HTTPRequest.blank('/v3/%s/group_types/default' % fake.PROJECT_ID, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) req.method = 'GET' self.assertRaises(webob.exc.HTTPNotFound, @@ -419,7 +419,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.show(request, raw_group_type) self.assertIn('group_type', output) @@ -448,7 +448,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.show(request, raw_group_type) self.assertIn('group_type', output) @@ -479,7 +479,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.show(request, raw_group_type) self.assertIn('group_type', output) @@ -510,7 +510,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.show(request, raw_group_type) self.assertIn('group_type', output) @@ -542,7 +542,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.show(request, raw_group_type) self.assertIn('group_type', output) @@ -576,7 +576,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.index(request, raw_group_types) self.assertIn('group_types', output) @@ -611,7 +611,7 @@ class GroupTypesApiTest(test.TestCase): ) request = fakes.HTTPRequest.blank("/v3", use_admin_context=True, - version=GROUP_TYPE_MICRO_VERSION) + version=mv.GROUP_TYPE) output = view_builder.index(request, raw_group_types) self.assertIn('group_types', output) diff --git a/cinder/tests/unit/api/v3/test_groups.py b/cinder/tests/unit/api/v3/test_groups.py index ad5c57c6403..45318128448 100644 --- a/cinder/tests/unit/api/v3/test_groups.py +++ b/cinder/tests/unit/api/v3/test_groups.py @@ -22,6 +22,7 @@ import mock from six.moves import http_client import webob +from cinder.api import microversions as mv from cinder.api.v3 import groups as v3_groups from cinder import context from cinder import db @@ -36,10 +37,7 @@ from cinder.tests.unit import fake_constants as fake from cinder.tests.unit import utils from cinder.volume import api as volume_api -GROUP_MICRO_VERSION = '3.13' -GROUP_FROM_SRC_MICRO_VERSION = '3.14' -GROUP_REPLICATION_MICRO_VERSION = '3.38' -INVALID_GROUP_REPLICATION_MICRO_VERSION = '3.37' +INVALID_GROUP_REPLICATION = mv.get_prior_version(mv.GROUP_REPLICATION) @ddt.ddt @@ -134,7 +132,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) @@ -149,7 +147,10 @@ class GroupsAPITestCase(test.TestCase): self.assertEqual([fake.VOLUME_TYPE_ID], res_dict['group']['volume_types']) - @ddt.data(('3.24', False), ('3.24', True), ('3.25', False), ('3.25', True)) + @ddt.data((mv.get_prior_version(mv.GROUP_VOLUME_LIST), False), + (mv.get_prior_version(mv.GROUP_VOLUME_LIST), True), + (mv.GROUP_VOLUME_LIST, False), + (mv.GROUP_VOLUME_LIST, True)) @ddt.unpack @mock.patch('cinder.objects.volume_type.VolumeTypeList.get_all_by_group') @mock.patch('cinder.objects.volume.VolumeList.get_all_by_generic_group') @@ -178,10 +179,10 @@ class GroupsAPITestCase(test.TestCase): res_dict = self.controller.detail(req) # If the microversion >= 3.25 and "list_volume=True", "volumes" should - # be contained in the response body. Else,"volumes" should not be + # be contained in the response body. Else, "volumes" should not be # contained in the response body. self.assertEqual(3, len(res_dict['groups'])) - if (version, has_list_volume) == ('3.25', True): + if (version, has_list_volume) == (mv.GROUP_VOLUME_LIST, True): self.assertEqual([fake.VOLUME_ID], res_dict['groups'][0]['volumes']) else: @@ -211,7 +212,7 @@ class GroupsAPITestCase(test.TestCase): # be contained in the response body. req = fakes.HTTPRequest.blank('/v3/%s/groups/%s?list_volume=True' % (fake.PROJECT_ID, self.group1.id), - version='3.25') + version=mv.GROUP_VOLUME_LIST) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) self.assertEqual([fake.VOLUME_ID], @@ -221,16 +222,17 @@ class GroupsAPITestCase(test.TestCase): # should not be contained in the response body. req = fakes.HTTPRequest.blank('/v3/%s/groups/%s' % (fake.PROJECT_ID, self.group1.id), - version='3.25') + version=mv.GROUP_VOLUME_LIST) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) self.assertIsNone(res_dict['group'].get('volumes', None)) # If the microversion < 3.25, "volumes" should not be contained in the # response body. - req = fakes.HTTPRequest.blank('/v3/%s/groups/%s?list_volume=True' % - (fake.PROJECT_ID, self.group1.id), - version='3.24') + req = fakes.HTTPRequest.blank( + '/v3/%s/groups/%s?list_volume=True' % + (fake.PROJECT_ID, self.group1.id), + version=mv.get_prior_version(mv.GROUP_VOLUME_LIST)) res_dict = self.controller.show(req, self.group1.id) self.assertEqual(1, len(res_dict)) self.assertIsNone(res_dict['group'].get('volumes', None)) @@ -239,11 +241,12 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s' % (fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) self.assertRaises(exception.GroupNotFound, self.controller.show, req, fake.WILL_NOT_BE_FOUND_ID) - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_group_list_with_general_filter(self, version, mock_update): url = '/v3/%s/groups' % fake.PROJECT_ID @@ -252,8 +255,8 @@ class GroupsAPITestCase(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'group', support_like) @@ -273,7 +276,7 @@ class GroupsAPITestCase(test.TestCase): self.group3.save() req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) res_dict = self.controller.index(req) self.assertEqual(1, len(res_dict)) @@ -295,7 +298,7 @@ class GroupsAPITestCase(test.TestCase): url = '/v3/%s/groups?limit=1' % fake.PROJECT_ID if is_detail: url = '/v3/%s/groups/detail?limit=1' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME) if is_detail: res_dict = self.controller.detail(req) @@ -320,7 +323,7 @@ class GroupsAPITestCase(test.TestCase): url = '/v3/%s/groups?offset=1' % fake.PROJECT_ID if is_detail: url = '/v3/%s/groups/detail?offset=1' % fake.PROJECT_ID - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME) res_dict = self.controller.index(req) self.assertEqual(1, len(res_dict)) @@ -337,7 +340,7 @@ class GroupsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/groups/detail?offset=234523423455454' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME) if is_detail: self.assertRaises(webob.exc.HTTPBadRequest, self.controller.detail, req) @@ -351,7 +354,7 @@ class GroupsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/groups/detail?limit=2&offset=1' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME) if is_detail: res_dict = self.controller.detail(req) @@ -377,7 +380,7 @@ class GroupsAPITestCase(test.TestCase): url = ('/v3/%s/groups/detail?' 'all_tenants=True&id=%s') % (fake.PROJECT_ID, self.group3.id) - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION, + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME, use_admin_context=True) if is_detail: @@ -398,7 +401,7 @@ class GroupsAPITestCase(test.TestCase): if is_detail: url = ('/v3/%s/groups/detail?sort=id:asc' % fake.PROJECT_ID) - req = fakes.HTTPRequest.blank(url, version=GROUP_MICRO_VERSION) + req = fakes.HTTPRequest.blank(url, version=mv.GROUP_VOLUME) expect_result = [self.group1.id, self.group2.id, self.group3.id] expect_result.sort() @@ -438,7 +441,7 @@ class GroupsAPITestCase(test.TestCase): # self.group3.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/detail' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) res_dict = self.controller.detail(req) self.assertEqual(1, len(res_dict)) @@ -476,7 +479,7 @@ class GroupsAPITestCase(test.TestCase): "description": "Group 1", }} req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) res_dict = self.controller.create(req, body) self.assertEqual(1, len(res_dict)) @@ -489,7 +492,7 @@ class GroupsAPITestCase(test.TestCase): def test_create_group_with_no_body(self): # omit body from the request req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, None) @@ -498,7 +501,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": False}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -513,7 +516,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": False}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -528,7 +531,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, fake.WILL_NOT_BE_FOUND_ID), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": False}} self.assertRaises(exception.GroupNotFound, self.controller.delete_group, @@ -538,7 +541,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": False}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -548,7 +551,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -565,7 +568,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -620,7 +623,7 @@ class GroupsAPITestCase(test.TestCase): "description": "Group 1", }} req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) ex = self.assertRaises(exception.GroupLimitExceeded, self.controller.create, req, body) @@ -631,7 +634,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"invalid_request_element": {"delete-volumes": False}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -642,7 +645,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": "abcd"}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -653,7 +656,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": ""}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -666,7 +669,7 @@ class GroupsAPITestCase(test.TestCase): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -688,7 +691,7 @@ class GroupsAPITestCase(test.TestCase): vol = utils.create_volume(self.ctxt, group_id=self.group1.id) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -707,7 +710,7 @@ class GroupsAPITestCase(test.TestCase): attach_status='attached') req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -722,7 +725,7 @@ class GroupsAPITestCase(test.TestCase): utils.create_snapshot(self.ctxt, vol.id) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete_group, @@ -739,7 +742,7 @@ class GroupsAPITestCase(test.TestCase): deleted=True) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"delete": {"delete-volumes": True}} res_dict = self.controller.delete_group( req, self.group1.id, body) @@ -758,7 +761,7 @@ class GroupsAPITestCase(test.TestCase): "description": "Group 1", }} req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) @@ -770,7 +773,7 @@ class GroupsAPITestCase(test.TestCase): "description": "Group 1", }} req = fakes.HTTPRequest.blank('/v3/%s/groups' % fake.PROJECT_ID, - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) @@ -820,7 +823,7 @@ class GroupsAPITestCase(test.TestCase): volume_type_id=volume_type_id) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) name = 'newgroup' description = 'New Group Description' add_volumes = add_volume.id + "," + add_volume2.id @@ -851,7 +854,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.status = status req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"group": {"name": "new name", "description": "new description", "add_volumes": None, @@ -870,7 +873,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"group": {"name": None, "description": None, "add_volumes": "fake-volume-uuid", @@ -885,7 +888,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"group": {"name": None, "description": "new description", "add_volumes": None, @@ -900,7 +903,7 @@ class GroupsAPITestCase(test.TestCase): self.group1.save() req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"group": {"name": None, "description": None, "add_volumes": None, @@ -919,7 +922,7 @@ class GroupsAPITestCase(test.TestCase): status='wrong_status') req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) add_volumes = add_volume.id body = {"group": {"name": "group1", "description": "", @@ -941,7 +944,7 @@ class GroupsAPITestCase(test.TestCase): volume_type_id=wrong_type) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) add_volumes = add_volume.id body = {"group": {"name": "group1", "description": "", @@ -962,7 +965,7 @@ class GroupsAPITestCase(test.TestCase): group_id=fake.GROUP2_ID) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) add_volumes = add_volume.id body = {"group": {"name": "group1", "description": "", @@ -984,7 +987,7 @@ class GroupsAPITestCase(test.TestCase): host=self.group1.host) req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/update' % (fake.PROJECT_ID, self.group1.id), - version=GROUP_MICRO_VERSION) + version=mv.GROUP_VOLUME) body = {"group": {"name": "new name", "description": None, @@ -999,16 +1002,16 @@ class GroupsAPITestCase(test.TestCase): self.assertEqual(add_volume.status, vol.status) add_volume.destroy() - @ddt.data(('3.11', 'fake_group_001', + @ddt.data((mv.GROUP_TYPE, 'fake_group_001', fields.GroupStatus.AVAILABLE, exception.VersionNotFoundForAPIMethod), - ('3.19', 'fake_group_001', + (mv.GROUP_SNAPSHOT_RESET_STATUS, 'fake_group_001', fields.GroupStatus.AVAILABLE, exception.VersionNotFoundForAPIMethod), - ('3.20', 'fake_group_001', + (mv.GROUP_VOLUME_RESET_STATUS, 'fake_group_001', fields.GroupStatus.AVAILABLE, exception.GroupNotFound), - ('3.20', None, + (mv.GROUP_VOLUME_RESET_STATUS, None, 'invalid_test_status', webob.exc.HTTPBadRequest), ) @@ -1029,7 +1032,7 @@ class GroupsAPITestCase(test.TestCase): def test_reset_group_status(self): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group2.id), - version='3.20') + version=mv.GROUP_VOLUME_RESET_STATUS) body = {"reset_status": { "status": fields.GroupStatus.AVAILABLE }} @@ -1068,7 +1071,7 @@ class GroupsAPITestCase(test.TestCase): "group_snapshot_id": group_snapshot.id}} req = fakes.HTTPRequest.blank('/v3/%s/groups/action' % fake.PROJECT_ID, - version=GROUP_FROM_SRC_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) res_dict = self.controller.create_from_src(req, body) self.assertIn('id', res_dict['group']) @@ -1101,7 +1104,7 @@ class GroupsAPITestCase(test.TestCase): "source_group_id": source_grp.id}} req = fakes.HTTPRequest.blank('/v3/%s/groups/action' % fake.PROJECT_ID, - version=GROUP_FROM_SRC_MICRO_VERSION) + version=mv.GROUP_SNAPSHOTS) res_dict = self.controller.create_from_src(req, body) self.assertIn('id', res_dict['group']) @@ -1120,7 +1123,7 @@ class GroupsAPITestCase(test.TestCase): def test_enable_replication(self, mock_rep_grp_type, mock_rep_vol_type): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) self.group3.status = fields.GroupStatus.AVAILABLE self.group3.save() body = {"enable_replication": {}} @@ -1145,7 +1148,7 @@ class GroupsAPITestCase(test.TestCase): mock_rep_vol_type.return_value = is_vol_rep_type req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) self.group3.status = fields.GroupStatus.AVAILABLE self.group3.save() body = {"enable_replication": {}} @@ -1161,7 +1164,7 @@ class GroupsAPITestCase(test.TestCase): mock_rep_vol_type): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) self.group3.status = fields.GroupStatus.AVAILABLE self.group3.save() body = {"enable_replication": {}} @@ -1173,13 +1176,13 @@ class GroupsAPITestCase(test.TestCase): return_value=True) @mock.patch('cinder.volume.utils.is_group_a_type', return_value=True) - @ddt.data((GROUP_REPLICATION_MICRO_VERSION, True, + @ddt.data((mv.GROUP_REPLICATION, True, fields.GroupStatus.CREATING, webob.exc.HTTPBadRequest), - (GROUP_REPLICATION_MICRO_VERSION, False, + (mv.GROUP_REPLICATION, False, fields.GroupStatus.AVAILABLE, exception.GroupNotFound), - (INVALID_GROUP_REPLICATION_MICRO_VERSION, True, + (INVALID_GROUP_REPLICATION, True, fields.GroupStatus.AVAILABLE, exception.VersionNotFoundForAPIMethod), ) @@ -1209,7 +1212,7 @@ class GroupsAPITestCase(test.TestCase): def test_disable_replication(self, mock_rep_grp_type, mock_rep_vol_type): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) self.group3.status = fields.GroupStatus.AVAILABLE self.group3.replication_status = fields.ReplicationStatus.ENABLED self.group3.save() @@ -1227,19 +1230,19 @@ class GroupsAPITestCase(test.TestCase): return_value=True) @mock.patch('cinder.volume.utils.is_group_a_type', return_value=True) - @ddt.data((GROUP_REPLICATION_MICRO_VERSION, True, + @ddt.data((mv.GROUP_REPLICATION, True, fields.GroupStatus.CREATING, fields.ReplicationStatus.ENABLED, webob.exc.HTTPBadRequest), - (GROUP_REPLICATION_MICRO_VERSION, True, + (mv.GROUP_REPLICATION, True, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.DISABLED, webob.exc.HTTPBadRequest), - (GROUP_REPLICATION_MICRO_VERSION, False, + (mv.GROUP_REPLICATION, False, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.DISABLED, exception.GroupNotFound), - (INVALID_GROUP_REPLICATION_MICRO_VERSION, True, + (INVALID_GROUP_REPLICATION, True, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.ENABLED, exception.VersionNotFoundForAPIMethod), @@ -1272,7 +1275,7 @@ class GroupsAPITestCase(test.TestCase): def test_failover_replication(self, mock_rep_grp_type, mock_rep_vol_type): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) self.group3.status = fields.GroupStatus.AVAILABLE self.group3.replication_status = fields.ReplicationStatus.ENABLED self.group3.save() @@ -1290,19 +1293,19 @@ class GroupsAPITestCase(test.TestCase): return_value=True) @mock.patch('cinder.volume.utils.is_group_a_type', return_value=True) - @ddt.data((GROUP_REPLICATION_MICRO_VERSION, True, + @ddt.data((mv.GROUP_REPLICATION, True, fields.GroupStatus.CREATING, fields.ReplicationStatus.ENABLED, webob.exc.HTTPBadRequest), - (GROUP_REPLICATION_MICRO_VERSION, True, + (mv.GROUP_REPLICATION, True, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.DISABLED, webob.exc.HTTPBadRequest), - (GROUP_REPLICATION_MICRO_VERSION, False, + (mv.GROUP_REPLICATION, False, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.DISABLED, exception.GroupNotFound), - (INVALID_GROUP_REPLICATION_MICRO_VERSION, True, + (INVALID_GROUP_REPLICATION, True, fields.GroupStatus.AVAILABLE, fields.ReplicationStatus.ENABLED, exception.VersionNotFoundForAPIMethod), @@ -1337,7 +1340,7 @@ class GroupsAPITestCase(test.TestCase): mock_rep_grp_type, mock_rep_vol_type): req = fakes.HTTPRequest.blank('/v3/%s/groups/%s/action' % (fake.PROJECT_ID, self.group3.id), - version=GROUP_REPLICATION_MICRO_VERSION) + version=mv.GROUP_REPLICATION) targets = { 'replication_targets': [ {'backend_id': 'lvm_backend_1'} diff --git a/cinder/tests/unit/api/v3/test_limits.py b/cinder/tests/unit/api/v3/test_limits.py index 14aa726b57c..7e9694fe7f0 100644 --- a/cinder/tests/unit/api/v3/test_limits.py +++ b/cinder/tests/unit/api/v3/test_limits.py @@ -16,12 +16,16 @@ import ddt import mock +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder.api.v3 import limits from cinder import test from cinder.tests.unit.api import fakes from cinder.tests.unit import fake_constants as fake +LIMITS_FILTER = mv.LIMITS_ADMIN_FILTER +PRE_LIMITS_FILTER = mv.get_prior_version(LIMITS_FILTER) + @ddt.ddt class LimitsControllerTest(test.TestCase): @@ -29,7 +33,8 @@ class LimitsControllerTest(test.TestCase): super(LimitsControllerTest, self).setUp() self.controller = limits.LimitsController() - @ddt.data(('3.38', True), ('3.38', False), ('3.39', True), ('3.39', False)) + @ddt.data((PRE_LIMITS_FILTER, True), (PRE_LIMITS_FILTER, False), + (LIMITS_FILTER, True), (LIMITS_FILTER, False)) @mock.patch('cinder.quota.VolumeTypeQuotaEngine.get_project_quotas') def test_get_limit_with_project_id(self, ver_project, mock_get_quotas): max_ver, has_project = ver_project @@ -48,9 +53,9 @@ class LimitsControllerTest(test.TestCase): mock_get_quotas.side_effect = get_project_quotas resp_dict = self.controller.index(req) - # if admin, only 3.39 and req contains project_id filter, cinder - # returns the specified project's quota. - if max_ver == '3.39' and has_project: + # if admin, only LIMITS_FILTER and req contains project_id filter, + # cinder returns the specified project's quota. + if max_ver == LIMITS_FILTER and has_project: self.assertEqual( 5, resp_dict['limits']['absolute']['maxTotalVolumeGigabytes']) else: diff --git a/cinder/tests/unit/api/v3/test_messages.py b/cinder/tests/unit/api/v3/test_messages.py index 06ad44b9b66..bb6bce435c0 100644 --- a/cinder/tests/unit/api/v3/test_messages.py +++ b/cinder/tests/unit/api/v3/test_messages.py @@ -15,6 +15,7 @@ import mock from six.moves import http_client from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.v3 import messages from cinder import context from cinder import exception @@ -66,8 +67,7 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get', v3_fakes.fake_message_get) req = fakes.HTTPRequest.blank( - '/v3/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION) + '/v3/messages/%s' % fakes.FAKE_UUID, version=mv.MESSAGES) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.show(req, fakes.FAKE_UUID) @@ -81,8 +81,7 @@ class MessageApiTest(test.TestCase): message_id=fakes.FAKE_UUID)) req = fakes.HTTPRequest.blank( - '/v3/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION) + '/v3/messages/%s' % fakes.FAKE_UUID, version=mv.MESSAGES) req.environ['cinder.context'] = self.ctxt self.assertRaises(exception.MessageNotFound, self.controller.show, @@ -92,7 +91,7 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get', v3_fakes.fake_message_get) req = fakes.HTTPRequest.blank('/v3/messages/%s' % fakes.FAKE_UUID, - version='3.0') + version=mv.BASE_VERSION) req.environ['cinder.context'] = self.ctxt self.assertRaises(exception.VersionNotFoundForAPIMethod, @@ -103,8 +102,7 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'delete') req = fakes.HTTPRequest.blank( - '/v3/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION) + '/v3/messages/%s' % fakes.FAKE_UUID, version=mv.MESSAGES) req.environ['cinder.context'] = self.ctxt resp = self.controller.delete(req, fakes.FAKE_UUID) @@ -118,13 +116,13 @@ class MessageApiTest(test.TestCase): message_id=fakes.FAKE_UUID)) req = fakes.HTTPRequest.blank( - '/v3/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION) + '/v3/messages/%s' % fakes.FAKE_UUID, version=mv.MESSAGES) self.assertRaises(exception.MessageNotFound, self.controller.delete, req, fakes.FAKE_UUID) - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_message_list_with_general_filter(self, version, mock_update): url = '/v3/%s/messages' % fakes.FAKE_UUID @@ -133,8 +131,8 @@ class MessageApiTest(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'message', support_like) @@ -143,8 +141,7 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get_all', return_value=[v3_fakes.fake_message(fakes.FAKE_UUID)]) req = fakes.HTTPRequest.blank( - '/v3/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION) + '/v3/messages/%s' % fakes.FAKE_UUID, version=mv.MESSAGES) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req) diff --git a/cinder/tests/unit/api/v3/test_resource_filters.py b/cinder/tests/unit/api/v3/test_resource_filters.py index 917f1f996c5..f348cbbcbc4 100644 --- a/cinder/tests/unit/api/v3/test_resource_filters.py +++ b/cinder/tests/unit/api/v3/test_resource_filters.py @@ -18,13 +18,12 @@ import ddt import mock import six +from cinder.api import microversions as mv from cinder.api.v3 import resource_filters as v3_filters from cinder import test from cinder.tests.unit.api import fakes from cinder.tests.unit import fake_constants as fake -FILTERS_MICRO_VERSION = '3.33' - @ddt.ddt class ResourceFiltersAPITestCase(test.TestCase): @@ -53,7 +52,7 @@ class ResourceFiltersAPITestCase(test.TestCase): if resource is not None: request_url += '?resource=%s' % resource req = fakes.HTTPRequest.blank(request_url, - version=FILTERS_MICRO_VERSION) + version=mv.RESOURCE_FILTER_CONFIG) with mock.patch('cinder.api.common._FILTERS_COLLECTION', filters): result = self.controller.index(req) diff --git a/cinder/tests/unit/api/v3/test_snapshot_manage.py b/cinder/tests/unit/api/v3/test_snapshot_manage.py index 21f3fc15622..b333cd54052 100644 --- a/cinder/tests/unit/api/v3/test_snapshot_manage.py +++ b/cinder/tests/unit/api/v3/test_snapshot_manage.py @@ -20,6 +20,7 @@ from six.moves import http_client from six.moves.urllib.parse import urlencode import webob +from cinder.api import microversions as mv from cinder.api.v3 import router as router_v3 from cinder import context from cinder import objects @@ -51,13 +52,13 @@ class SnapshotManageTest(test.TestCase): fake.PROJECT_ID, True) - def _get_resp_post(self, body, version="3.8"): + def _get_resp_post(self, body, version=mv.MANAGE_EXISTING_LIST): """Helper to execute a POST manageable_snapshots API call.""" req = webob.Request.blank('/v3/%s/manageable_snapshots' % fake.PROJECT_ID) req.method = 'POST' + req.headers = mv.get_mv_header(version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume ' + version req.environ['cinder.context'] = self._admin_ctxt req.body = jsonutils.dump_as_bytes(body) res = req.get_response(app()) @@ -84,10 +85,12 @@ class SnapshotManageTest(test.TestCase): def test_manage_snapshot_previous_version(self): body = {'snapshot': {'volume_id': fake.VOLUME_ID, 'ref': 'fake_ref'}} - res = self._get_resp_post(body, version="3.7") + res = self._get_resp_post( + body, version=mv.get_prior_version(mv.MANAGE_EXISTING_LIST)) self.assertEqual(http_client.NOT_FOUND, res.status_int, res) - def _get_resp_get(self, host, detailed, paging, version="3.8", **kwargs): + def _get_resp_get(self, host, detailed, paging, + version=mv.MANAGE_EXISTING_LIST, **kwargs): """Helper to execute a GET os-snapshot-manage API call.""" params = {'host': host} if host else {} params.update(kwargs) @@ -101,8 +104,8 @@ class SnapshotManageTest(test.TestCase): req = webob.Request.blank('/v3/%s/manageable_snapshots%s%s' % (fake.PROJECT_ID, detail, query_string)) req.method = 'GET' + req.headers = mv.get_mv_header(version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume ' + version req.environ['cinder.context'] = self._admin_ctxt res = req.get_response(app()) return res @@ -120,7 +123,9 @@ class SnapshotManageTest(test.TestCase): self.assertEqual(http_client.OK, res.status_int) def test_get_manageable_snapshots_previous_version(self): - res = self._get_resp_get('fakehost', False, False, version="3.7") + res = self._get_resp_get( + 'fakehost', False, False, + version=mv.get_prior_version(mv.MANAGE_EXISTING_LIST)) self.assertEqual(http_client.NOT_FOUND, res.status_int) @mock.patch('cinder.volume.api.API.get_manageable_snapshots', @@ -136,7 +141,9 @@ class SnapshotManageTest(test.TestCase): self.assertEqual(http_client.OK, res.status_int) def test_get_manageable_snapshots_detail_previous_version(self): - res = self._get_resp_get('fakehost', True, True, version="3.7") + res = self._get_resp_get( + 'fakehost', True, True, + version=mv.get_prior_version(mv.MANAGE_EXISTING_LIST)) self.assertEqual(http_client.NOT_FOUND, res.status_int) @ddt.data((True, True, 'detail_list'), (True, False, 'summary_list'), @@ -150,12 +157,12 @@ class SnapshotManageTest(test.TestCase): if clustered: host = None cluster_name = 'mycluster' - version = '3.17' + version = mv.MANAGE_EXISTING_CLUSTER kwargs = {'cluster': cluster_name} else: host = 'fakehost' cluster_name = None - version = '3.8' + version = mv.MANAGE_EXISTING_LIST kwargs = {} service = objects.Service(disabled=False, host='fakehost', cluster_name=cluster_name) @@ -183,12 +190,13 @@ class SnapshotManageTest(test.TestCase): mock.ANY, None, host=host, binary='cinder-volume', cluster_name=cluster_name) - @ddt.data('3.8', '3.17') + @ddt.data(mv.MANAGE_EXISTING_LIST, mv.MANAGE_EXISTING_CLUSTER) def test_get_manageable_missing_host(self, version): res = self._get_resp_get(None, True, False, version=version) self.assertEqual(http_client.BAD_REQUEST, res.status_int) def test_get_manageable_both_host_cluster(self): - res = self._get_resp_get('host', True, False, version='3.17', + res = self._get_resp_get('host', True, False, + version=mv.MANAGE_EXISTING_CLUSTER, cluster='cluster') self.assertEqual(http_client.BAD_REQUEST, res.status_int) diff --git a/cinder/tests/unit/api/v3/test_snapshots.py b/cinder/tests/unit/api/v3/test_snapshots.py index b15bc70c1b0..3a831897858 100644 --- a/cinder/tests/unit/api/v3/test_snapshots.py +++ b/cinder/tests/unit/api/v3/test_snapshots.py @@ -17,7 +17,7 @@ import ddt import mock -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder.api.v3 import snapshots from cinder import context from cinder import exception @@ -54,9 +54,8 @@ def create_snapshot_query_with_metadata(metadata_query_string, """Helper to create metadata querystring with microversion""" req = fakes.HTTPRequest.blank('/v3/snapshots?metadata=' + metadata_query_string) - req.headers["OpenStack-API-Version"] = "volume " + api_microversion - req.api_version_request = api_version.APIVersionRequest( - api_microversion) + req.headers = mv.get_mv_header(api_microversion) + req.api_version_request = mv.get_api_version(api_microversion) return req @@ -69,7 +68,9 @@ class SnapshotApiTest(test.TestCase): self.controller = snapshots.SnapshotsController() self.ctx = context.RequestContext(fake.USER_ID, fake.PROJECT_ID, True) - @ddt.data('3.14', '3.13', '3.41') + @ddt.data(mv.GROUP_SNAPSHOTS, + mv.get_prior_version(mv.GROUP_SNAPSHOTS), + mv.SNAPSHOT_LIST_USER_ID) @mock.patch('cinder.db.snapshot_metadata_get', return_value=dict()) @mock.patch('cinder.objects.Volume.get_by_id') @mock.patch('cinder.objects.Snapshot.get_by_id') @@ -91,20 +92,20 @@ class SnapshotApiTest(test.TestCase): snapshot_get_by_id.return_value = snapshot_obj volume_get_by_id.return_value = fake_volume_obj req = fakes.HTTPRequest.blank('/v3/snapshots/%s' % UUID) - req.api_version_request = api_version.APIVersionRequest(max_ver) + req.api_version_request = mv.get_api_version(max_ver) resp_dict = self.controller.show(req, UUID) self.assertIn('snapshot', resp_dict) self.assertEqual(UUID, resp_dict['snapshot']['id']) self.assertIn('updated_at', resp_dict['snapshot']) - if max_ver == '3.14': + if max_ver == mv.SNAPSHOT_LIST_USER_ID: + self.assertIn('user_id', resp_dict['snapshot']) + elif max_ver == mv.GROUP_SNAPSHOTS: self.assertIn('group_snapshot_id', resp_dict['snapshot']) self.assertNotIn('user_id', resp_dict['snapshot']) - elif max_ver == '3.13': + else: self.assertNotIn('group_snapshot_id', resp_dict['snapshot']) self.assertNotIn('user_id', resp_dict['snapshot']) - elif max_ver == '3.41': - self.assertIn('user_id', resp_dict['snapshot']) def test_snapshot_show_invalid_id(self): snapshot_id = INVALID_UUID @@ -144,7 +145,7 @@ class SnapshotApiTest(test.TestCase): # Generic filtering is introduced since '3,31' and we add # 'availability_zone' support by using generic filtering. req = fakes.HTTPRequest.blank(url, use_admin_context=is_admin_user, - version='3.31') + version=mv.RESOURCE_FILTER) res_dict = self.controller.detail(req) self.assertEqual(1, len(res_dict['snapshots'])) @@ -154,12 +155,13 @@ class SnapshotApiTest(test.TestCase): self._create_snapshot(name='test1') self._create_snapshot(name='test2') - req = fakes.HTTPRequest.blank('/v3/snapshots?sort_key=name', - version='3.29') + req = fakes.HTTPRequest.blank( + '/v3/snapshots?sort_key=name', + version=mv.get_prior_version(mv.SNAPSHOT_SORT)) self.assertRaises(exception.InvalidInput, self.controller.detail, req) req = fakes.HTTPRequest.blank('/v3/snapshots?sort_key=name', - version='3.30') + version=mv.SNAPSHOT_SORT) res_dict = self.controller.detail(req) self.assertEqual(2, len(res_dict['snapshots'])) self.assertEqual('test2', res_dict['snapshots'][0]['name']) @@ -171,7 +173,8 @@ class SnapshotApiTest(test.TestCase): self._create_snapshot(metadata=metadata) # Create request with metadata filter key1: value1 - req = create_snapshot_query_with_metadata('{"key1":"val1"}', '3.22') + req = create_snapshot_query_with_metadata( + '{"key1":"val1"}', mv.SNAPSHOT_LIST_METADATA_FILTER) # query controller with above request res_dict = self.controller.detail(req) @@ -184,7 +187,8 @@ class SnapshotApiTest(test.TestCase): 'metadata']) # Create request with metadata filter key2: value2 - req = create_snapshot_query_with_metadata('{"key2":"val2"}', '3.22') + req = create_snapshot_query_with_metadata( + '{"key2":"val2"}', mv.SNAPSHOT_LIST_METADATA_FILTER) # query controller with above request res_dict = self.controller.detail(req) @@ -199,7 +203,8 @@ class SnapshotApiTest(test.TestCase): # Create request with metadata filter key1: value1, key11: value11 req = create_snapshot_query_with_metadata( - '{"key1":"val1", "key11":"val11"}', '3.22') + '{"key1":"val1", "key11":"val11"}', + mv.SNAPSHOT_LIST_METADATA_FILTER) # query controller with above request res_dict = self.controller.detail(req) @@ -212,7 +217,8 @@ class SnapshotApiTest(test.TestCase): 'snapshots'][0]['metadata']) # Create request with metadata filter key1: value1 - req = create_snapshot_query_with_metadata('{"key1":"val1"}', '3.22') + req = create_snapshot_query_with_metadata( + '{"key1":"val1"}', mv.SNAPSHOT_LIST_METADATA_FILTER) # query controller with above request res_dict = self.controller.detail(req) @@ -224,7 +230,19 @@ class SnapshotApiTest(test.TestCase): self.assertDictEqual({"key1": "val1", "key11": "val11"}, res_dict[ 'snapshots'][0]['metadata']) - @ddt.data('3.30', '3.31', '3.34') + # Create request with metadata filter key2: value2 + req = create_snapshot_query_with_metadata( + '{"key2":"val2"}', mv.SNAPSHOT_LIST_METADATA_FILTER) + + # query controller with above request + res_dict = self.controller.detail(req) + + # verify no snapshot is returned + self.assertEqual(0, len(res_dict['snapshots'])) + + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), + mv.RESOURCE_FILTER, + mv.LIKE_FILTER) @mock.patch('cinder.api.common.reject_invalid_filters') def test_snapshot_list_with_general_filter(self, version, mock_update): url = '/v3/%s/snapshots' % fake.PROJECT_ID @@ -233,8 +251,8 @@ class SnapshotApiTest(test.TestCase): use_admin_context=False) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version != mv.get_prior_version(mv.RESOURCE_FILTER): + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'snapshot', support_like) @@ -245,7 +263,9 @@ class SnapshotApiTest(test.TestCase): self._create_snapshot(metadata=metadata) # Create request with metadata filter key2: value2 - req = create_snapshot_query_with_metadata('{"key2":"val2"}', '3.21') + req = create_snapshot_query_with_metadata( + '{"key2":"val2"}', + mv.get_prior_version(mv.SNAPSHOT_LIST_METADATA_FILTER)) # query controller with above request res_dict = self.controller.detail(req) diff --git a/cinder/tests/unit/api/v3/test_volume_manage.py b/cinder/tests/unit/api/v3/test_volume_manage.py index 22c82342bd9..96406183767 100644 --- a/cinder/tests/unit/api/v3/test_volume_manage.py +++ b/cinder/tests/unit/api/v3/test_volume_manage.py @@ -20,6 +20,7 @@ from six.moves import http_client from six.moves.urllib.parse import urlencode import webob +from cinder.api import microversions as mv from cinder.api.v3 import router as router_v3 from cinder import context from cinder import objects @@ -56,13 +57,13 @@ class VolumeManageTest(test.TestCase): fake.PROJECT_ID, True) - def _get_resp_post(self, body, version="3.8"): + def _get_resp_post(self, body, version=mv.MANAGE_EXISTING_LIST): """Helper to execute a POST manageable_volumes API call.""" req = webob.Request.blank('/v3/%s/manageable_volumes' % fake.PROJECT_ID) req.method = 'POST' + req.headers = mv.get_mv_header(version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume ' + version req.environ['cinder.context'] = self._admin_ctxt req.body = jsonutils.dump_as_bytes(body) res = req.get_response(app()) @@ -88,7 +89,8 @@ class VolumeManageTest(test.TestCase): res = self._get_resp_post(body) self.assertEqual(http_client.BAD_REQUEST, res.status_int, res) - def _get_resp_get(self, host, detailed, paging, version="3.8", **kwargs): + def _get_resp_get(self, host, detailed, paging, + version=mv.MANAGE_EXISTING_LIST, **kwargs): """Helper to execute a GET os-volume-manage API call.""" params = {'host': host} if host else {} params.update(kwargs) @@ -103,8 +105,8 @@ class VolumeManageTest(test.TestCase): req = webob.Request.blank('/v3/%s/manageable_volumes%s%s' % (fake.PROJECT_ID, detail, query_string)) req.method = 'GET' + req.headers = mv.get_mv_header(version) req.headers['Content-Type'] = 'application/json' - req.headers['OpenStack-API-Version'] = 'volume ' + version req.environ['cinder.context'] = self._admin_ctxt res = req.get_response(app()) return res @@ -122,7 +124,9 @@ class VolumeManageTest(test.TestCase): self.assertEqual(http_client.OK, res.status_int) def test_get_manageable_volumes_previous_version(self): - res = self._get_resp_get('fakehost', False, True, version="3.7") + res = self._get_resp_get( + 'fakehost', False, True, + version=mv.get_prior_version(mv.MANAGE_EXISTING_LIST)) self.assertEqual(http_client.NOT_FOUND, res.status_int) @mock.patch('cinder.volume.api.API.get_manageable_volumes', @@ -138,7 +142,9 @@ class VolumeManageTest(test.TestCase): self.assertEqual(http_client.OK, res.status_int) def test_get_manageable_volumes_detail_previous_version(self): - res = self._get_resp_get('fakehost', True, False, version="3.7") + res = self._get_resp_get( + 'fakehost', True, False, + version=mv.get_prior_version(mv.MANAGE_EXISTING_LIST)) self.assertEqual(http_client.NOT_FOUND, res.status_int) @ddt.data((True, True, 'detail_list'), (True, False, 'summary_list'), @@ -152,12 +158,12 @@ class VolumeManageTest(test.TestCase): if clustered: host = None cluster_name = 'mycluster' - version = '3.17' + version = mv.MANAGE_EXISTING_CLUSTER kwargs = {'cluster': cluster_name} else: host = 'fakehost' cluster_name = None - version = '3.8' + version = mv.MANAGE_EXISTING_LIST kwargs = {} service = objects.Service(disabled=False, host='fakehost', cluster_name=cluster_name) @@ -185,12 +191,13 @@ class VolumeManageTest(test.TestCase): mock.ANY, None, host=host, binary='cinder-volume', cluster_name=cluster_name) - @ddt.data('3.8', '3.17') + @ddt.data(mv.MANAGE_EXISTING_LIST, mv.MANAGE_EXISTING_CLUSTER) def test_get_manageable_missing_host(self, version): res = self._get_resp_get(None, True, False, version=version) self.assertEqual(http_client.BAD_REQUEST, res.status_int) def test_get_manageable_both_host_cluster(self): - res = self._get_resp_get('host', True, False, version='3.17', + res = self._get_resp_get('host', True, False, + version=mv.MANAGE_EXISTING_CLUSTER, cluster='cluster') self.assertEqual(http_client.BAD_REQUEST, res.status_int) diff --git a/cinder/tests/unit/api/v3/test_volume_metadata.py b/cinder/tests/unit/api/v3/test_volume_metadata.py index a1ac313f962..1ba61557f3b 100644 --- a/cinder/tests/unit/api/v3/test_volume_metadata.py +++ b/cinder/tests/unit/api/v3/test_volume_metadata.py @@ -18,6 +18,7 @@ from oslo_serialization import jsonutils import webob from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.v3 import volume_metadata from cinder.api.v3 import volumes from cinder import db @@ -150,7 +151,7 @@ class VolumeMetaDataTest(test.TestCase): self.volume_controller.create(req, body) def test_index(self): - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) data = self.controller.index(req, self.req_id) expected = { @@ -166,14 +167,14 @@ class VolumeMetaDataTest(test.TestCase): def test_index_nonexistent_volume(self): self.mock_object(db, 'volume_metadata_get', return_volume_nonexistent) - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) self.assertRaises(exception.VolumeNotFound, self.controller.index, req, self.url) def test_index_no_data(self): self.mock_object(db, 'volume_metadata_get', return_empty_volume_metadata) - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) data = self.controller.index(req, self.req_id) expected = {'metadata': {}} result = jsonutils.loads(data.body) @@ -182,7 +183,7 @@ class VolumeMetaDataTest(test.TestCase): def test_validate_etag_true(self): self.mock_object(db, 'volume_metadata_get', return_value={'key1': 'vanue1', 'key2': 'value2'}) - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) req.environ['cinder.context'] = mock.Mock() req.if_match.etags = ['d5103bf7b26ff0310200d110da3ed186'] self.assertTrue(self.controller._validate_etag(req, self.req_id)) @@ -192,7 +193,7 @@ class VolumeMetaDataTest(test.TestCase): fake_volume = {'id': self.req_id, 'status': 'available'} fake_context = mock.Mock() metadata_update.side_effect = return_new_volume_metadata - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) req.method = 'PUT' req.content_type = "application/json" expected = { @@ -217,7 +218,7 @@ class VolumeMetaDataTest(test.TestCase): fake_volume = {'id': self.req_id, 'status': 'available'} fake_context = mock.Mock() metadata_update.side_effect = return_create_volume_metadata - req = fakes.HTTPRequest.blank(self.url + '/key1', version="3.15") + req = fakes.HTTPRequest.blank(self.url + '/key1', version=mv.ETAGS) req.method = 'PUT' body = {"meta": {"key1": "value1"}} req.body = jsonutils.dump_as_bytes(body) @@ -235,7 +236,7 @@ class VolumeMetaDataTest(test.TestCase): def test_create_metadata_keys_value_none(self): self.mock_object(db, 'volume_metadata_update', return_create_volume_metadata) - req = fakes.HTTPRequest.blank(self.url, version="3.15") + req = fakes.HTTPRequest.blank(self.url, version=mv.ETAGS) req.method = 'POST' req.headers["content-type"] = "application/json" body = {"meta": {"key": None}} @@ -245,7 +246,7 @@ class VolumeMetaDataTest(test.TestCase): def test_update_items_value_none(self): self.mock_object(db, 'volume_metadata_update', return_create_volume_metadata) - req = fakes.HTTPRequest.blank(self.url + '/key1', version="3.15") + req = fakes.HTTPRequest.blank(self.url + '/key1', version=mv.ETAGS) req.method = 'PUT' body = {"metadata": {"key": None}} req.body = jsonutils.dump_as_bytes(body) diff --git a/cinder/tests/unit/api/v3/test_volumes.py b/cinder/tests/unit/api/v3/test_volumes.py index 7eff927b021..d644c6ce9db 100644 --- a/cinder/tests/unit/api/v3/test_volumes.py +++ b/cinder/tests/unit/api/v3/test_volumes.py @@ -19,7 +19,7 @@ import mock import webob from cinder.api import extensions -from cinder.api.openstack import api_version_request as api_version +from cinder.api import microversions as mv from cinder.api.v2.views.volumes import ViewBuilder from cinder.api.v3 import volumes from cinder import context @@ -38,10 +38,7 @@ from cinder import utils from cinder.volume import api as volume_api from cinder.volume import api as vol_get -version_header_name = 'OpenStack-API-Version' - DEFAULT_AZ = "zone1:host1" -REVERT_TO_SNAPSHOT_VERSION = '3.40' @ddt.ddt @@ -61,7 +58,7 @@ class VolumeApiTest(test.TestCase): req = fakes.HTTPRequest.blank('/v3/volumes?bootable=True') req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.0'} + req.headers = mv.get_mv_header(mv.BASE_VERSION) req.environ['cinder.context'].is_admin = True self.override_config('query_volume_filters', 'bootable') @@ -77,9 +74,10 @@ class VolumeApiTest(test.TestCase): req = fakes.HTTPRequest.blank('/v3/volumes?bootable=True') req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.2'} + req.headers = mv.get_mv_header(mv.VOLUME_LIST_BOOTABLE) req.environ['cinder.context'].is_admin = True - req.api_version_request = api_version.APIVersionRequest('3.29') + req.api_version_request = mv.get_api_version( + mv.VOLUME_LIST_BOOTABLE) self.override_config('query_volume_filters', 'bootable') self.controller.index(req) @@ -119,8 +117,9 @@ class VolumeApiTest(test.TestCase): vols = self._create_volume_with_glance_metadata() req = fakes.HTTPRequest.blank("/v3/volumes?glance_metadata=" "{'image_name': 'imageTestOne'}") - req.headers["OpenStack-API-Version"] = "volume 3.4" - req.api_version_request = api_version.APIVersionRequest('3.4') + req.headers = mv.get_mv_header(mv.VOLUME_LIST_GLANCE_METADATA) + req.api_version_request = mv.get_api_version( + mv.VOLUME_LIST_GLANCE_METADATA) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req) volumes = res_dict['volumes'] @@ -131,8 +130,8 @@ class VolumeApiTest(test.TestCase): self._create_volume_with_glance_metadata() req = fakes.HTTPRequest.blank("/v3/volumes?glance_metadata=" "{'image_name': 'imageTestOne'}") - req.headers["OpenStack-API-Version"] = "volume 3.0" - req.api_version_request = api_version.APIVersionRequest('3.0') + req.headers = mv.get_mv_header(mv.BASE_VERSION) + req.api_version_request = mv.get_api_version(mv.BASE_VERSION) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req) volumes = res_dict['volumes'] @@ -142,8 +141,8 @@ class VolumeApiTest(test.TestCase): vols = self._create_volume_with_group() req = fakes.HTTPRequest.blank(("/v3/volumes?group_id=%s") % fake.GROUP_ID) - req.headers["OpenStack-API-Version"] = "volume 3.10" - req.api_version_request = api_version.APIVersionRequest('3.10') + req.headers = mv.get_mv_header(mv.VOLUME_LIST_GROUP) + req.api_version_request = mv.get_api_version(mv.VOLUME_LIST_GROUP) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req) volumes = res_dict['volumes'] @@ -154,26 +153,29 @@ class VolumeApiTest(test.TestCase): self._create_volume_with_group() req = fakes.HTTPRequest.blank(("/v3/volumes?group_id=%s") % fake.GROUP_ID) - req.headers["OpenStack-API-Version"] = "volume 3.9" - req.api_version_request = api_version.APIVersionRequest('3.9') + req.headers = mv.get_mv_header(mv.BACKUP_UPDATE) + req.api_version_request = mv.get_api_version(mv.BACKUP_UPDATE) req.environ['cinder.context'] = self.ctxt res_dict = self.controller.index(req) volumes = res_dict['volumes'] self.assertEqual(2, len(volumes)) - def _fake_volumes_summary_request(self, version='3.12', all_tenant=False, + def _fake_volumes_summary_request(self, + version=mv.VOLUME_SUMMARY, + all_tenant=False, is_admin=False): req_url = '/v3/volumes/summary' if all_tenant: req_url += '?all_tenants=True' req = fakes.HTTPRequest.blank(req_url, use_admin_context=is_admin) - req.headers = {'OpenStack-API-Version': 'volume ' + version} - req.api_version_request = api_version.APIVersionRequest(version) + req.headers = mv.get_mv_header(version) + req.api_version_request = mv.get_api_version(version) return req def test_volumes_summary_in_unsupport_version(self): """Function call to test summary volumes API in unsupported version""" - req = self._fake_volumes_summary_request(version='3.7') + req = self._fake_volumes_summary_request( + version=mv.get_prior_version(mv.VOLUME_SUMMARY)) self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.summary, req) @@ -196,11 +198,12 @@ class VolumeApiTest(test.TestCase): self.assertEqual(expected, res_dict) @ddt.data( - ('3.35', {'volume-summary': {'total_size': 0.0, - 'total_count': 0}}), - ('3.36', {'volume-summary': {'total_size': 0.0, - 'total_count': 0, - 'metadata': {}}})) + (mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA), + {'volume-summary': {'total_size': 0.0, + 'total_count': 0}}), + (mv.VOLUME_SUMMARY_METADATA, {'volume-summary': {'total_size': 0.0, + 'total_count': 0, + 'metadata': {}}})) @ddt.unpack def test_volume_summary_empty(self, summary_api_version, expect_result): req = self._fake_volumes_summary_request(version=summary_api_version) @@ -208,13 +211,15 @@ class VolumeApiTest(test.TestCase): self.assertEqual(expect_result, res_dict) @ddt.data( - ('3.35', {'volume-summary': {'total_size': 2, - 'total_count': 2}}), - ('3.36', {'volume-summary': {'total_size': 2, - 'total_count': 2, - 'metadata': { - 'name': ['test_name1', 'test_name2'], - 'age': ['test_age']}}})) + (mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA), + {'volume-summary': {'total_size': 2, + 'total_count': 2}}), + (mv.VOLUME_SUMMARY_METADATA, + {'volume-summary': {'total_size': 2, + 'total_count': 2, + 'metadata': { + 'name': ['test_name1', 'test_name2'], + 'age': ['test_age']}}})) @ddt.unpack def test_volume_summary_return_metadata(self, summary_api_version, expect_result): @@ -230,13 +235,15 @@ class VolumeApiTest(test.TestCase): self.assertEqual(expect_result, res_dict) @ddt.data( - ('3.35', {'volume-summary': {'total_size': 2, - 'total_count': 2}}), - ('3.36', {'volume-summary': {'total_size': 2, - 'total_count': 2, - 'metadata': { - 'name': ['test_name1', 'test_name2'], - 'age': ['test_age']}}})) + (mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA), + {'volume-summary': {'total_size': 2, + 'total_count': 2}}), + (mv.VOLUME_SUMMARY_METADATA, + {'volume-summary': {'total_size': 2, + 'total_count': 2, + 'metadata': { + 'name': ['test_name1', 'test_name2'], + 'age': ['test_age']}}})) @ddt.unpack def test_volume_summary_return_metadata_all_tenant( self, summary_api_version, expect_result): @@ -334,8 +341,9 @@ class VolumeApiTest(test.TestCase): if with_migration_status: volume['volume']['migration_status'] = None - # Remove group_id if max version is less than 3.13. - if req_version and req_version.matches(None, "3.12"): + # Remove group_id if max version is less than GROUP_VOLUME. + if req_version and req_version.matches( + None, mv.get_prior_version(mv.GROUP_VOLUME)): volume['volume'].pop('group_id') return volume @@ -356,13 +364,14 @@ class VolumeApiTest(test.TestCase): 'group': test_group, } - # Remove group_id if max version is less than 3.13. - if req_version and req_version.matches(None, "3.12"): + # Remove group_id if max version is less than GROUP_VOLUME. + if req_version and req_version.matches( + None, mv.get_prior_version(mv.GROUP_VOLUME)): volume.pop('group') return volume - @ddt.data('3.13', '3.12') + @ddt.data(mv.GROUP_VOLUME, mv.get_prior_version(mv.GROUP_VOLUME)) @mock.patch( 'cinder.api.openstack.wsgi.Controller.validate_name_and_description') def test_volume_create(self, max_ver, mock_validate): @@ -375,14 +384,14 @@ class VolumeApiTest(test.TestCase): vol = self._vol_in_request_body() body = {"volume": vol} req = fakes.HTTPRequest.blank('/v3/volumes') - req.api_version_request = api_version.APIVersionRequest(max_ver) + req.api_version_request = mv.get_api_version(max_ver) res_dict = self.controller.create(req, body) ex = self._expected_vol_from_controller( req_version=req.api_version_request) self.assertEqual(ex, res_dict) self.assertTrue(mock_validate.called) - @ddt.data('3.14', '3.13') + @ddt.data(mv.GROUP_SNAPSHOTS, mv.get_prior_version(mv.GROUP_SNAPSHOTS)) @mock.patch.object(group_api.API, 'get') @mock.patch.object(db.sqlalchemy.api, '_volume_type_get_full', autospec=True) @@ -405,7 +414,7 @@ class VolumeApiTest(test.TestCase): group_id=fake.GROUP_ID) body = {"volume": vol} req = fakes.HTTPRequest.blank('/v3/volumes') - req.api_version_request = api_version.APIVersionRequest(max_ver) + req.api_version_request = mv.get_api_version(max_ver) res_dict = self.controller.create(req, body) ex = self._expected_vol_from_controller( snapshot_id=snapshot_id, @@ -450,23 +459,26 @@ class VolumeApiTest(test.TestCase): self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) - @ddt.data('3.30', '3.31', '3.34') + @ddt.data(mv.get_prior_version(mv.RESOURCE_FILTER), mv.RESOURCE_FILTER, + mv.LIKE_FILTER) @mock.patch.object(volume_api.API, 'check_volume_filters', mock.Mock()) @mock.patch.object(utils, 'add_visible_admin_metadata', mock.Mock()) @mock.patch('cinder.api.common.reject_invalid_filters') def test_list_volume_with_general_filter(self, version, mock_update): req = fakes.HTTPRequest.blank('/v3/volumes', version=version) self.controller.index(req) - if version != '3.30': - support_like = True if version == '3.34' else False + if version >= mv.RESOURCE_FILTER: + support_like = True if version == mv.LIKE_FILTER else False mock_update.assert_called_once_with(req.environ['cinder.context'], mock.ANY, 'volume', support_like) - @ddt.data({'admin': True, 'version': '3.21'}, - {'admin': False, 'version': '3.21'}, - {'admin': True, 'version': '3.20'}, - {'admin': False, 'version': '3.20'}) + @ddt.data({'admin': True, 'version': mv.VOLUME_DETAIL_PROVIDER_ID}, + {'admin': False, 'version': mv.VOLUME_DETAIL_PROVIDER_ID}, + {'admin': True, + 'version': mv.get_prior_version(mv.VOLUME_DETAIL_PROVIDER_ID)}, + {'admin': False, + 'version': mv.get_prior_version(mv.VOLUME_DETAIL_PROVIDER_ID)}) @ddt.unpack def test_volume_show_provider_id(self, admin, version): self.mock_object(volume_api.API, 'get', v2_fakes.fake_volume_api_get) @@ -482,8 +494,8 @@ class VolumeApiTest(test.TestCase): res_dict = self.controller.show(req, fake.VOLUME_ID) req_version = req.api_version_request # provider_id is in view if min version is greater than or equal to - # 3.21 for admin. - if req_version.matches("3.21", None) and admin: + # VOLUME_DETAIL_PROVIDER_ID for admin. + if req_version.matches(mv.VOLUME_DETAIL_PROVIDER_ID, None) and admin: self.assertIn('provider_id', res_dict['volume']) else: self.assertNotIn('provider_id', res_dict['volume']) @@ -516,10 +528,9 @@ class VolumeApiTest(test.TestCase): mock_latest.side_effect = exception.VolumeSnapshotNotFound(volume_id= 'fake_id') req = fakes.HTTPRequest.blank('/v3/volumes/fake_id/revert') - req.headers = {'OpenStack-API-Version': - 'volume %s' % REVERT_TO_SNAPSHOT_VERSION} - req.api_version_request = api_version.APIVersionRequest( - REVERT_TO_SNAPSHOT_VERSION) + req.headers = mv.get_mv_header(mv.VOLUME_REVERT) + req.api_version_request = mv.get_api_version( + mv.VOLUME_REVERT) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.revert, req, 'fake_id', {'revert': {'snapshot_id': @@ -534,10 +545,9 @@ class VolumeApiTest(test.TestCase): fake_snapshot = self._fake_create_snapshot(fake.UUID1) mock_latest.return_value = fake_snapshot req = fakes.HTTPRequest.blank('/v3/volumes/fake_id/revert') - req.headers = {'OpenStack-API-Version': - 'volume %s' % REVERT_TO_SNAPSHOT_VERSION} - req.api_version_request = api_version.APIVersionRequest( - REVERT_TO_SNAPSHOT_VERSION) + req.headers = mv.get_mv_header(mv.VOLUME_REVERT) + req.api_version_request = mv.get_api_version( + mv.VOLUME_REVERT) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.revert, req, 'fake_id', {'revert': {'snapshot_id': @@ -557,10 +567,9 @@ class VolumeApiTest(test.TestCase): mock_latest.return_value = fake_snapshot req = fakes.HTTPRequest.blank('/v3/volumes/%s/revert' % fake_volume['id']) - req.headers = {'OpenStack-API-Version': - 'volume %s' % REVERT_TO_SNAPSHOT_VERSION} - req.api_version_request = api_version.APIVersionRequest( - REVERT_TO_SNAPSHOT_VERSION) + req.headers = mv.get_mv_header(mv.VOLUME_REVERT) + req.api_version_request = mv.get_api_version( + mv.VOLUME_REVERT) # update volume's status failed mock_update.side_effect = [False, True] diff --git a/cinder/tests/unit/api/v3/test_workers.py b/cinder/tests/unit/api/v3/test_workers.py index 9fe9e34aa9c..ea154f24bd6 100644 --- a/cinder/tests/unit/api/v3/test_workers.py +++ b/cinder/tests/unit/api/v3/test_workers.py @@ -19,6 +19,7 @@ from oslo_serialization import jsonutils from six.moves import http_client import webob +from cinder.api import microversions as mv from cinder.api.v3 import router as router_v3 from cinder.api.v3 import workers from cinder import context @@ -61,7 +62,7 @@ class WorkersTestCase(test.TestCase): overwrite=False) self.controller = workers.create_resource() - def _get_resp_post(self, body, version='3.24', ctxt=None): + def _get_resp_post(self, body, version=mv.WORKERS_CLEANUP, ctxt=None): """Helper to execute a POST workers API call.""" req = webob.Request.blank('/v3/%s/workers/cleanup' % fake.PROJECT_ID) req.method = 'POST' @@ -74,7 +75,7 @@ class WorkersTestCase(test.TestCase): @mock.patch('cinder.scheduler.rpcapi.SchedulerAPI.work_cleanup') def test_cleanup_old_api_version(self, rpc_mock): - res = self._get_resp_post({}, '3.19') + res = self._get_resp_post({}, mv.get_prior_version(mv.WORKERS_CLEANUP)) self.assertEqual(http_client.NOT_FOUND, res.status_code) rpc_mock.assert_not_called() diff --git a/cinder/tests/unit/message/test_api.py b/cinder/tests/unit/message/test_api.py index 1233a3328c7..e9cee6533fd 100644 --- a/cinder/tests/unit/message/test_api.py +++ b/cinder/tests/unit/message/test_api.py @@ -16,6 +16,7 @@ from oslo_config import cfg from oslo_utils import timeutils from cinder.api import extensions +from cinder.api import microversions as mv from cinder.api.openstack import api_version_request as api_version from cinder.api.v3 import messages from cinder import context @@ -128,8 +129,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.5'} - req.api_version_request = api_version.APIVersionRequest('3.30') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.RESOURCE_FILTER) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -139,8 +140,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.5'} - req.api_version_request = api_version.APIVersionRequest('3.30') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.RESOURCE_FILTER) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -149,12 +150,14 @@ class MessageApiTest(test.TestCase): def test_get_all_messages_with_limit_wrong_version(self): self.create_message_for_tests() + PRE_MESSAGES_PAGINATION = mv.get_prior_version(mv.MESSAGES_PAGINATION) + url = '/v3/messages?limit=1' req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers["OpenStack-API-Version"] = "volume 3.3" - req.api_version_request = api_version.APIVersionRequest('3.3') + req.headers = mv.get_mv_header(PRE_MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(PRE_MESSAGES_PAGINATION) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -167,8 +170,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers["OpenStack-API-Version"] = "volume 3.5" - req.api_version_request = api_version.APIVersionRequest('3.5') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.MESSAGES_PAGINATION) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -181,8 +184,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers["OpenStack-API-Version"] = "volume 3.5" - req.api_version_request = api_version.APIVersionRequest('3.5') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.MESSAGES_PAGINATION) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -196,8 +199,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers["OpenStack-API-Version"] = "volume 3.5" - req.api_version_request = api_version.APIVersionRequest('3.5') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.MESSAGES_PAGINATION) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -210,8 +213,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers["OpenStack-API-Version"] = "volume 3.5" - req.api_version_request = api_version.APIVersionRequest('3.5') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.MESSAGES_PAGINATION) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -242,8 +245,8 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.5'} - req.api_version_request = api_version.APIVersionRequest('3.30') + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) + req.api_version_request = mv.get_api_version(mv.RESOURCE_FILTER) req.environ['cinder.context'].is_admin = True res = self.controller.index(req) @@ -263,7 +266,7 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank(url) req.method = 'GET' req.content_type = 'application/json' - req.headers = {version_header_name: 'volume 3.5'} + req.headers = mv.get_mv_header(mv.MESSAGES_PAGINATION) req.api_version_request = api_version.max_api_version() req.environ['cinder.context'].is_admin = True diff --git a/cinder/volume/api.py b/cinder/volume/api.py index 257c4f1c60f..3f04ba50af3 100644 --- a/cinder/volume/api.py +++ b/cinder/volume/api.py @@ -1909,20 +1909,20 @@ class API(base.Base): def _check_boolean_filter_value(self, key, val, strict=False): """Boolean filter values in Volume GET. - Before V3.2, all values other than 'False', 'false', 'FALSE' were - trated as True for specific boolean filter parameters in Volume - GET request. + Before VOLUME_LIST_BOOTABLE, all values other than 'False', 'false', + 'FALSE' were trated as True for specific boolean filter parameters in + Volume GET request. - But V3.2 onwards, only true/True/0/1/False/false parameters are - supported. + But VOLUME_LIST_BOOTABLE onwards, only true/True/0/1/False/false + parameters are supported. All other input values to specific boolean filter parameter will lead to raising exception. - This changes API behavior. So, micro version introduced for V3.2 - onwards. + This changes API behavior. So, micro version introduced for + VOLUME_LIST_BOOTABLE onwards. """ if strict: - # for updated behavior, from V3.2 onwards. + # for updated behavior, from VOLUME_LIST_BOOTABLE onwards. # To translate any true/false/t/f/0/1 to True/False # which is only acceptable format in database queries. try: @@ -1932,7 +1932,7 @@ class API(base.Base): 'value': val} raise exception.InvalidInput(reason=msg) else: - # For existing behavior(before version 3.2) + # For existing behavior(before version VOLUME_LIST_BOOTABLE) accepted_true = ['True', 'true', 'TRUE'] accepted_false = ['False', 'false', 'FALSE'] diff --git a/doc/source/contributor/api_microversion_dev.rst b/doc/source/contributor/api_microversion_dev.rst index e8970559c2c..c5315a320a1 100644 --- a/doc/source/contributor/api_microversion_dev.rst +++ b/doc/source/contributor/api_microversion_dev.rst @@ -278,8 +278,17 @@ necessary to add changes to other places which describe your change: be enough information that it could be used by the docs team for release notes. +* Constants should be used in the code to minimize errors on microversion + merge conflicts. Define a constant for the new microversion in the + ``cinder/api/microversions.py`` file and use that in the rest of the code. + * Update the expected versions in affected tests. +* API changes should almost always include a release note announcing the + availability of the new API functionality. The description of the API change + should indicate which microversion is required for the change, and it should + refer to the numerical value of the microversion and not its constant name. + Allocating a microversion -------------------------