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
This commit is contained in:
Sean McGinnis 2017-09-15 11:14:59 -06:00
parent b3833594da
commit 1c8fe0ade4
62 changed files with 845 additions and 561 deletions

View File

@ -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)

View File

@ -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},

View File

@ -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')

View File

@ -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)

View File

@ -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)

View File

@ -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(

View File

@ -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
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 >= microversions.get_api_version(
microversions.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(microversions.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)

View File

@ -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)

172
cinder/api/microversions.py Normal file
View File

@ -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)

View File

@ -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

View File

@ -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,

View File

@ -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,7 @@ from cinder.volume import api as volume_api
LOG = logging.getLogger(__name__)
API_VERSION = '3.27'
ATTACHMENT_COMPLETION_VERSION = '3.44'
mv.NEW_ATTACH_COMPLETION = '3.44'
class AttachmentsController(wsgi.Controller):
@ -43,20 +43,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 +94,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 +192,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 +252,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 +268,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)."""

View File

@ -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'

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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']

View File

@ -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']

View File

@ -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."""

View File

@ -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(

View File

@ -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.MESSAGES):
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)

View File

@ -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')

View File

@ -13,11 +13,12 @@
"""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'
mv.RESOURCE_FILTER_CONFIG = '3.33'
class ResourceFiltersController(wsgi.Controller):
@ -30,7 +31,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)

View File

@ -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)

View File

@ -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

View File

@ -14,6 +14,7 @@
# under the License.
from cinder.api import common
from cinder.api import microversions as mv
from cinder import utils
@ -60,13 +61,14 @@ 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]

View File

@ -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,8 +26,8 @@ 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):

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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."""

View File

@ -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",

View File

@ -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

View File

@ -24,7 +24,6 @@ CONF = config.CONF
class VolumeRevertTests(volume_base.BaseVolumeTest):
min_microversion = '3.40'
@classmethod
def setup_clients(cls):

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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')

View File

@ -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)

View File

@ -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'])

View File

@ -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

View File

@ -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',

View File

@ -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)

View File

@ -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)

View File

@ -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, {})

View File

@ -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",

View File

@ -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
}}

View File

@ -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)

View File

@ -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)

View File

@ -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')
@ -181,7 +182,7 @@ class GroupsAPITestCase(test.TestCase):
# 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' %
req = fakes.HTTPRequest.blank(
'/v3/%s/groups/%s?list_volume=True' %
(fake.PROJECT_ID, self.group1.id),
version='3.24')
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'}

View File

@ -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:

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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,9 +198,10 @@ class VolumeApiTest(test.TestCase):
self.assertEqual(expected, res_dict)
@ddt.data(
('3.35', {'volume-summary': {'total_size': 0.0,
(mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA),
{'volume-summary': {'total_size': 0.0,
'total_count': 0}}),
('3.36', {'volume-summary': {'total_size': 0.0,
(mv.VOLUME_SUMMARY_METADATA, {'volume-summary': {'total_size': 0.0,
'total_count': 0,
'metadata': {}}}))
@ddt.unpack
@ -208,9 +211,11 @@ class VolumeApiTest(test.TestCase):
self.assertEqual(expect_result, res_dict)
@ddt.data(
('3.35', {'volume-summary': {'total_size': 2,
(mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA),
{'volume-summary': {'total_size': 2,
'total_count': 2}}),
('3.36', {'volume-summary': {'total_size': 2,
(mv.VOLUME_SUMMARY_METADATA,
{'volume-summary': {'total_size': 2,
'total_count': 2,
'metadata': {
'name': ['test_name1', 'test_name2'],
@ -230,9 +235,11 @@ class VolumeApiTest(test.TestCase):
self.assertEqual(expect_result, res_dict)
@ddt.data(
('3.35', {'volume-summary': {'total_size': 2,
(mv.get_prior_version(mv.VOLUME_SUMMARY_METADATA),
{'volume-summary': {'total_size': 2,
'total_count': 2}}),
('3.36', {'volume-summary': {'total_size': 2,
(mv.VOLUME_SUMMARY_METADATA,
{'volume-summary': {'total_size': 2,
'total_count': 2,
'metadata': {
'name': ['test_name1', 'test_name2'],
@ -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]

View File

@ -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()

View File

@ -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

View File

@ -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']

View File

@ -278,8 +278,15 @@ 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 using the numerical
value of the microversion.
Allocating a microversion
-------------------------