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