api: Remove v1 API

Remove the api-paste definitions, the router, and the remaining
controllers.

Change-Id: I27cc12db7c3824ef3abc007ce97154508891d74b
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
Depends-on: https://review.opendev.org/c/openstack/manila-tempest-plugin/+/976938
This commit is contained in:
Stephen Finucane
2025-09-04 11:52:57 +01:00
parent e1fb16f880
commit 8b94409fb0
32 changed files with 46 additions and 761 deletions
-4
View File
@@ -496,10 +496,6 @@ function create_manila_accounts {
create_service_user "manila"
get_or_create_service "manila" "share" "Manila Shared Filesystem Service"
get_or_create_endpoint "share" "$REGION_NAME" \
"$MANILA_ENDPOINT_BASE/v1/\$(project_id)s"
# Set up Manila v2 service and endpoint - as of microversion 2.60,
# project_id is no longer necessary in the v2 endpoint
get_or_create_service "manilav2" "sharev2" "Manila Shared Filesystem Service V2"
+5 -1
View File
@@ -56,12 +56,16 @@ set -o xtrace
# Install the target manila
install_manila
# calls upgrade-manila for specific release
# Calls upgrade-manila for specific release
upgrade_project manila $RUN_DIR $BASE_DEVSTACK_BRANCH $TARGET_DEVSTACK_BRANCH
# Migrate the database
$MANILA_BIN_DIR/manila-manage db sync || die $LINENO "DB migration error"
# Overwrite the api-paste.ini
# TODO(stephenfin): We can remove this in 2026.2 (Hibiscus)
cp $MANILA_DIR/etc/manila/api-paste.ini $MANILA_API_PASTE_INI
start_manila
# Don't succeed unless the services come up
-10
View File
@@ -6,15 +6,8 @@
use = call:manila.api:root_app_factory
/: apiversions
/healthcheck: healthcheck
/v1: openstack_share_api
/v2: openstack_share_api_v2
[composite:openstack_share_api]
use = call:manila.api.middleware.auth:pipeline_factory
noauth = cors request_id faultwrap http_proxy_to_wsgi sizelimit osprofiler noauth api
keystone = cors request_id faultwrap http_proxy_to_wsgi sizelimit osprofiler authtoken keystonecontext api
keystone_nolimit = cors request_id faultwrap http_proxy_to_wsgi sizelimit osprofiler authtoken keystonecontext api
[composite:openstack_share_api_v2]
use = call:manila.api.middleware.auth:pipeline_factory
noauth = cors request_id faultwrap http_proxy_to_wsgi sizelimit osprofiler noauth apiv2
@@ -40,9 +33,6 @@ paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
[filter:http_proxy_to_wsgi]
paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory
[app:api]
paste.app_factory = manila.api.v1.router:APIRouter.factory
[app:apiv2]
paste.app_factory = manila.api.v2.router:APIRouter.factory
+2 -2
View File
@@ -44,8 +44,8 @@ REST_API_VERSION_HISTORY = """
REST API Version History:
* 1.0 - Initial version. Includes all V1 APIs and extensions in Kilo.
* 2.0 - Versions API updated to reflect beginning of microversions epoch.
* 2.0 - Initial version. Includes all V1 APIs and extensions in Kilo and
the addition of microversions.
* 2.1 - Share create() doesn't ignore availability_zone field of share.
* 2.2 - Snapshots become optional feature.
* 2.3 - Share instances admin API
+3 -6
View File
@@ -217,15 +217,12 @@ class Request(webob.Request):
def set_api_version_request(self):
"""Set API version request based on the request header information.
Microversions starts with /v2, so if a client sends a /v1 URL, then
ignore the headers and request 1.0 APIs.
Microversions starts with /v2, so if a client sends a different URL
then ignore the headers and request unversioned APIs.
"""
if not self.script_name or not (V1_SCRIPT_NAME in self.script_name or
V2_SCRIPT_NAME in self.script_name):
if not self.script_name or V2_SCRIPT_NAME not in self.script_name:
# The request is on the base URL without a major version specified
self.api_version_request = api_version.APIVersionRequest()
elif V1_SCRIPT_NAME in self.script_name:
self.api_version_request = api_version.APIVersionRequest('1.0')
else:
if API_VERSION_REQUEST_HEADER in self.headers:
hdr_string = self.headers[API_VERSION_REQUEST_HEADER]
View File
-168
View File
@@ -1,168 +0,0 @@
# Copyright 2011 OpenStack LLC.
# Copyright 2011 United States Government as represented by the
# Administrator of the National Aeronautics and Space Administration.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""
WSGI middleware for OpenStack Share API v1.
"""
from manila.api import extensions
import manila.api.openstack
from manila.api.v1 import share_metadata
from manila.api.v1 import share_servers
from manila.api.v1 import share_snapshots
from manila.api.v1 import shares
from manila.api.v2 import availability_zones
from manila.api.v2 import limits
from manila.api.v2 import quota_class_sets
from manila.api.v2 import quota_sets
from manila.api.v2 import scheduler_stats
from manila.api.v2 import security_service
from manila.api.v2 import services
from manila.api.v2 import share_manage
from manila.api.v2 import share_networks
from manila.api.v2 import share_types
from manila.api.v2 import share_types_extra_specs
from manila.api.v2 import share_unmanage
from manila.api import versions
class APIRouter(manila.api.openstack.APIRouter):
"""Route API requests.
Routes requests on the OpenStack API to the appropriate controller
and method.
"""
ExtensionManager = extensions.ExtensionManager
def _setup_routes(self, mapper):
self.resources['versions'] = versions.create_resource()
mapper.connect("versions", "/",
controller=self.resources['versions'],
action='index')
mapper.redirect("", "/")
self.resources["availability_zones"] = (
availability_zones.create_resource_legacy())
mapper.resource("availability-zone",
"os-availability-zone",
controller=self.resources["availability_zones"])
self.resources["services"] = services.create_resource_legacy()
mapper.resource("service",
"os-services",
controller=self.resources["services"])
self.resources["quota_sets"] = quota_sets.create_resource_legacy()
mapper.resource("quota-set",
"os-quota-sets",
controller=self.resources["quota_sets"],
member={'defaults': 'GET'})
self.resources["quota_class_sets"] = (
quota_class_sets.create_resource_legacy())
mapper.resource("quota-class-set",
"os-quota-class-sets",
controller=self.resources["quota_class_sets"])
self.resources["share_manage"] = share_manage.create_resource()
mapper.resource("share_manage",
"os-share-manage",
controller=self.resources["share_manage"])
self.resources["share_unmanage"] = share_unmanage.create_resource()
mapper.resource("share_unmanage",
"os-share-unmanage",
controller=self.resources["share_unmanage"],
member={'unmanage': 'POST'})
self.resources['shares'] = shares.create_resource()
mapper.resource("share", "shares",
controller=self.resources['shares'],
collection={'detail': 'GET'},
member={'action': 'POST'})
self.resources['snapshots'] = share_snapshots.create_resource()
mapper.resource("snapshot", "snapshots",
controller=self.resources['snapshots'],
collection={'detail': 'GET'},
member={'action': 'POST'})
self.resources['share_metadata'] = share_metadata.create_resource()
share_metadata_controller = self.resources['share_metadata']
mapper.resource("share_metadata", "metadata",
controller=share_metadata_controller,
parent_resource=dict(member_name='share',
collection_name='shares'))
mapper.connect("metadata",
"/{project_id}/shares/{share_id}/metadata",
controller=share_metadata_controller,
action='update_all',
conditions={"method": ['PUT']})
self.resources['limits'] = limits.create_resource()
mapper.resource("limit", "limits",
controller=self.resources['limits'])
self.resources["security_services"] = (
security_service.create_resource())
mapper.resource("security-service", "security-services",
controller=self.resources['security_services'],
collection={'detail': 'GET'})
self.resources['share_networks'] = share_networks.create_resource()
mapper.resource(share_networks.RESOURCE_NAME,
'share-networks',
controller=self.resources['share_networks'],
collection={'detail': 'GET'},
member={'action': 'POST'})
self.resources['share_servers'] = share_servers.create_resource()
mapper.resource('share_server',
'share-servers',
controller=self.resources['share_servers'])
mapper.connect('details',
'/{project_id}/share-servers/{id}/details',
controller=self.resources['share_servers'],
action='details',
conditions={"method": ['GET']})
self.resources['types'] = share_types.create_resource()
mapper.resource("type", "types",
controller=self.resources['types'],
collection={'detail': 'GET', 'default': 'GET'},
member={'action': 'POST',
'os-share-type-access': 'GET'})
self.resources['extra_specs'] = (
share_types_extra_specs.create_resource())
mapper.resource('extra_spec', 'extra_specs',
controller=self.resources['extra_specs'],
parent_resource=dict(member_name='type',
collection_name='types'))
self.resources['scheduler_stats'] = scheduler_stats.create_resource()
mapper.connect('pools', '/{project_id}/scheduler-stats/pools',
controller=self.resources['scheduler_stats'],
action='pools_index',
conditions={'method': ['GET']})
mapper.connect('pools', '/{project_id}/scheduler-stats/pools/detail',
controller=self.resources['scheduler_stats'],
action='pools_detail',
conditions={'method': ['GET']})
-199
View File
@@ -1,199 +0,0 @@
# Copyright 2011 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from http import client as http_client
from oslo_log import log
import webob
from webob import exc
from oslo_config import cfg
from manila.api import common as api_common
from manila.api.openstack import wsgi
from manila import db
from manila import exception
from manila.i18n import _
from manila import policy
from manila import share
LOG = log.getLogger(__name__)
CONF = cfg.CONF
class ShareMetadataController(object):
"""The share metadata API controller for the OpenStack API."""
def __init__(self):
self.share_api = share.API()
super(ShareMetadataController, self).__init__()
def _get_metadata(self, context, share_id):
try:
share = self.share_api.get(context, share_id)
rv = db.share_metadata_get(context, share['id'])
meta = dict(rv.items())
except exception.NotFound:
msg = _('share does not exist')
raise exc.HTTPNotFound(explanation=msg)
return meta
def index(self, req, share_id):
"""Returns the list of metadata for a given share."""
context = req.environ['manila.context']
return {'metadata': self._get_metadata(context, share_id)}
def create(self, req, share_id, body):
try:
metadata = body['metadata']
except (KeyError, TypeError):
msg = _("Malformed request body")
raise exc.HTTPBadRequest(explanation=msg)
context = req.environ['manila.context']
new_metadata = self._update_share_metadata(context,
share_id,
metadata,
delete=False)
return {'metadata': new_metadata}
def update(self, req, share_id, id, body):
try:
meta_item = body['meta']
except (TypeError, KeyError):
expl = _('Malformed request body')
raise exc.HTTPBadRequest(explanation=expl)
if id not in meta_item:
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
if len(meta_item) > 1:
expl = _('Request body contains too many items')
raise exc.HTTPBadRequest(explanation=expl)
context = req.environ['manila.context']
self._update_share_metadata(context,
share_id,
meta_item,
delete=False)
return {'meta': meta_item}
def update_all(self, req, share_id, body):
try:
metadata = body['metadata']
except (TypeError, KeyError):
expl = _('Malformed request body')
raise exc.HTTPBadRequest(explanation=expl)
context = req.environ['manila.context']
new_metadata = self._update_share_metadata(
context, share_id, metadata, delete=True)
return {'metadata': new_metadata}
def _update_share_metadata(self, context,
share_id, metadata,
delete=False):
ignore_keys = getattr(CONF, 'admin_only_metadata', [])
try:
share = self.share_api.get(context, share_id)
if set(metadata).intersection(set(ignore_keys)):
try:
policy.check_policy(
context, 'share', 'update_admin_only_metadata')
except exception.PolicyNotAuthorized:
msg = _("Cannot set or update admin only metadata.")
LOG.exception(msg)
raise exc.HTTPForbidden(explanation=msg)
ignore_keys = []
rv = db.share_metadata_get(context, share['id'])
orig_meta = dict(rv.items())
if delete:
_metadata = metadata
for key in ignore_keys:
if key in orig_meta:
_metadata[key] = orig_meta[key]
else:
metadata_copy = metadata.copy()
for key in ignore_keys:
metadata_copy.pop(key, None)
_metadata = orig_meta.copy()
_metadata.update(metadata_copy)
api_common.check_metadata_properties(_metadata)
db.share_metadata_update(context, share['id'],
_metadata, delete)
return _metadata
except exception.NotFound:
msg = _('share does not exist')
raise exc.HTTPNotFound(explanation=msg)
except (ValueError, AttributeError):
msg = _("Malformed request body")
raise exc.HTTPBadRequest(explanation=msg)
except exception.InvalidMetadata as error:
raise exc.HTTPBadRequest(explanation=error.msg)
except exception.InvalidMetadataSize as error:
raise exc.HTTPBadRequest(explanation=error.msg)
def show(self, req, share_id, id):
"""Return a single metadata item."""
context = req.environ['manila.context']
data = self._get_metadata(context, share_id)
try:
return {'meta': {id: data[id]}}
except KeyError:
msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
def delete(self, req, share_id, id):
"""Deletes an existing metadata."""
context = req.environ['manila.context']
metadata = self._get_metadata(context, share_id)
if id not in metadata:
msg = _("Metadata item was not found")
raise exc.HTTPNotFound(explanation=msg)
try:
share = self.share_api.get(context, share_id)
admin_only_metadata_keys = (
getattr(CONF, 'admin_only_metadata', set())
)
if id in admin_only_metadata_keys:
policy.check_policy(context, 'share',
'update_admin_only_metadata')
db.share_metadata_delete(context, share['id'], id)
except exception.NotFound:
msg = _('share does not exist')
raise exc.HTTPNotFound(explanation=msg)
except exception.PolicyNotAuthorized:
msg = _("Cannot delete admin only metadata.")
LOG.exception(msg)
raise exc.HTTPForbidden(explanation=msg)
return webob.Response(status_int=http_client.OK)
def create_resource():
return wsgi.Resource(ShareMetadataController())
-154
View File
@@ -1,154 +0,0 @@
# Copyright 2014 OpenStack Foundation
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from http import client as http_client
from oslo_log import log
import webob
from webob import exc
from manila.api.openstack import wsgi
from manila.api.views import share_servers as share_servers_views
from manila.common import constants
from manila.db import api as db_api
from manila import exception
from manila.i18n import _
from manila import share
LOG = log.getLogger(__name__)
class ShareServerController(wsgi.Controller):
"""The Share Server API controller for the OpenStack API."""
_view_builder_class = share_servers_views.ViewBuilder
resource_name = 'share_server'
def __init__(self):
self.share_api = share.API()
super(ShareServerController, self).__init__()
@wsgi.Controller.authorize
def index(self, req):
"""Returns a list of share servers."""
context = req.environ['manila.context']
search_opts = {}
search_opts.update(req.GET)
ss_filters = {}
if 'host' in search_opts:
ss_filters['host'] = search_opts.pop('host')
if 'status' in search_opts:
ss_filters['status'] = search_opts.pop('status')
if 'source_share_server_id' in search_opts:
ss_filters['source_share_server_id'] = search_opts.pop(
'source_share_server_id')
if 'identifier' in search_opts:
ss_filters['identifier'] = search_opts.pop('identifier')
share_servers = db_api.share_server_get_all_with_filters(
context, ss_filters)
for s in share_servers:
try:
share_network = db_api.share_network_get(
context, s.share_network_id)
s.project_id = share_network['project_id']
if share_network['name']:
s.share_network_name = share_network['name']
else:
s.share_network_name = share_network['id']
except exception.ShareNetworkNotFound:
# NOTE(dviroel): The share-network may already be deleted while
# the share-server is in 'deleting' state. In this scenario,
# we will return some empty values.
LOG.debug("Unable to retrieve share network details for share "
"server %(server)s, the network %(network)s was "
"not found.",
{'server': s.id, 'network': s.share_network_id})
s.project_id = ''
s.share_network_name = ''
if search_opts:
for k, v in search_opts.items():
share_servers = [s for s in share_servers if
(hasattr(s, k) and
s[k] == v or k == 'share_network' and
v in [s.share_network_name,
s.share_network_id] or
k == 'share_network_subnet_id' and
v in s.share_network_subnet_ids)]
return self._view_builder.build_share_servers(req, share_servers)
@wsgi.Controller.authorize
def show(self, req, id):
"""Return data about the requested share server."""
context = req.environ['manila.context']
try:
server = db_api.share_server_get(context, id)
share_network = db_api.share_network_get(
context, server['share_network_id'])
server.project_id = share_network['project_id']
if share_network['name']:
server.share_network_name = share_network['name']
else:
server.share_network_name = share_network['id']
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
except exception.ShareNetworkNotFound:
msg = _("Share server could not be found. Its associated share "
"network %s does not exist.") % server['share_network_id']
raise exc.HTTPNotFound(explanation=msg)
return self._view_builder.build_share_server(req, server)
@wsgi.Controller.authorize
def details(self, req, id):
"""Return details for requested share server."""
context = req.environ['manila.context']
try:
share_server = db_api.share_server_get(context, id)
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
return self._view_builder.build_share_server_details(
share_server['backend_details'])
@wsgi.Controller.authorize
def delete(self, req, id):
"""Delete specified share server."""
context = req.environ['manila.context']
try:
share_server = db_api.share_server_get(context, id)
except exception.ShareServerNotFound as e:
raise exc.HTTPNotFound(explanation=e.msg)
allowed_statuses = [constants.STATUS_ERROR, constants.STATUS_ACTIVE]
if share_server['status'] not in allowed_statuses:
data = {
'status': share_server['status'],
'allowed_statuses': allowed_statuses,
}
msg = _("Share server's actual status is %(status)s, allowed "
"statuses for deletion are %(allowed_statuses)s.") % (data)
raise exc.HTTPForbidden(explanation=msg)
LOG.debug("Deleting share server with id: %s.", id)
try:
self.share_api.delete_share_server(context, share_server)
except exception.ShareServerInUse as e:
raise exc.HTTPConflict(explanation=e.msg)
return webob.Response(status_int=http_client.ACCEPTED)
def create_resource():
return wsgi.Resource(ShareServerController())
-51
View File
@@ -1,51 +0,0 @@
# Copyright 2013 NetApp
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""The share snapshots api."""
from oslo_log import log
from manila.api.openstack import wsgi
from manila.api.v2 import share_snapshots
from manila.api.views import share_snapshots as snapshot_views
from manila import share
LOG = log.getLogger(__name__)
class ShareSnapshotsController(
share_snapshots.ShareSnapshotMixin, wsgi.Controller,
wsgi.AdminActionsMixin
):
"""The Share Snapshots API controller for the OpenStack API."""
resource_name = 'share_snapshot'
_view_builder_class = snapshot_views.ViewBuilder
def __init__(self):
super(ShareSnapshotsController, self).__init__()
self.share_api = share.API()
@wsgi.action('os-reset_status')
def snapshot_reset_status_legacy(self, req, id, body):
return self._reset_status(req, id, body)
@wsgi.action('os-force_delete')
def snapshot_force_delete_legacy(self, req, id, body):
return self._force_delete(req, id, body)
def create_resource():
return wsgi.Resource(ShareSnapshotsController())
-80
View File
@@ -1,80 +0,0 @@
# Copyright 2013 NetApp
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
"""The shares api."""
from oslo_log import log
from manila.api.openstack import wsgi
from manila.api.v2 import shares
from manila.api.views import share_accesses as share_access_views
from manila.api.views import shares as share_views
from manila.lock import api as resource_locks
from manila import share
LOG = log.getLogger(__name__)
class ShareController(
wsgi.Controller, shares.ShareMixin, wsgi.AdminActionsMixin
):
"""The Shares API v1 controller for the OpenStack API."""
resource_name = 'share'
_view_builder_class = share_views.ViewBuilder
def __init__(self):
super(ShareController, self).__init__()
self.share_api = share.API()
self.resource_locks_api = resource_locks.API()
self._access_view_builder = share_access_views.ViewBuilder()
@wsgi.action('os-reset_status')
def share_reset_status(self, req, id, body):
"""Reset status of a share."""
return self._reset_status(req, id, body)
@wsgi.action('os-force_delete')
def share_force_delete(self, req, id, body):
"""Delete a share, bypassing the check for status."""
return self._force_delete(req, id, body)
@wsgi.action('os-allow_access')
def allow_access(self, req, id, body):
"""Add share access rule."""
return self._allow_access(req, id, body)
@wsgi.action('os-deny_access')
def deny_access(self, req, id, body):
"""Remove share access rule."""
return self._deny_access(req, id, body)
@wsgi.action('os-access_list')
def access_list(self, req, id, body):
"""List share access rules."""
return self._access_list(req, id, body)
@wsgi.action('os-extend')
def extend(self, req, id, body):
"""Extend size of a share."""
return self._extend(req, id, body)
@wsgi.action('os-shrink')
def shrink(self, req, id, body):
"""Shrink size of a share."""
return self._shrink(req, id, body)
def create_resource():
return wsgi.Resource(ShareController())
+1 -1
View File
@@ -45,7 +45,7 @@ class AvailabilityZoneControllerLegacy(AvailabilityZoneMixin, wsgi.Controller):
'os-availability-zone'.
"""
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
@validation.request_query_schema(schema.index_request_query)
@validation.response_body_schema(schema.index_response_body)
def index(self, req):
+2 -2
View File
@@ -75,13 +75,13 @@ class QuotaClassSetsControllerLegacy(QuotaClassSetsMixin, wsgi.Controller):
'os-quota-class-sets'.
"""
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
@validation.request_query_schema(schema.show_request_query)
@validation.response_body_schema(schema.show_response_body)
def show(self, req, id):
return self._show(req, id)
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
@validation.request_body_schema(schema.update_request_body)
@validation.response_body_schema(schema.update_response_body)
def update(self, req, id, body):
+4 -4
View File
@@ -289,16 +289,16 @@ class QuotaSetsControllerLegacy(QuotaSetsMixin, wsgi.Controller):
'os-quota-sets'.
"""
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def show(self, req, id):
self._ensure_share_type_arg_is_absent(req)
return self._show(req, id)
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def defaults(self, req, id):
return self._defaults(req, id)
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def update(self, req, id, body):
self._ensure_share_type_arg_is_absent(req)
self._ensure_specific_microversion_args_are_absent(
@@ -307,7 +307,7 @@ class QuotaSetsControllerLegacy(QuotaSetsMixin, wsgi.Controller):
body, ['share_replicas', 'replica_gigabytes'], "2.53")
return self._update(req, id, body)
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def delete(self, req, id):
self._ensure_share_type_arg_is_absent(req)
return self._delete(req, id)
+2 -2
View File
@@ -31,7 +31,7 @@ class SchedulerStatsController(wsgi.Controller):
self._view_builder_class = scheduler_stats_views.ViewBuilder
super(SchedulerStatsController, self).__init__()
@wsgi.Controller.api_version('1.0', '2.22')
@wsgi.Controller.api_version('2.0', '2.22')
@wsgi.Controller.authorize('index')
def pools_index(self, req):
"""Returns a list of storage pools known to the scheduler."""
@@ -42,7 +42,7 @@ class SchedulerStatsController(wsgi.Controller):
def pools_index(self, req): # pylint: disable=function-redefined # noqa F811
return self._pools(req, action='index', enable_share_type=True)
@wsgi.Controller.api_version('1.0', '2.22')
@wsgi.Controller.api_version('2.0', '2.22')
@wsgi.Controller.authorize('detail')
def pools_detail(self, req):
"""Returns a detailed list of storage pools known to the scheduler."""
+2 -2
View File
@@ -130,11 +130,11 @@ class ServiceControllerLegacy(ServiceMixin, wsgi.Controller):
'os-services'.
"""
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def index(self, req):
return self._index(req)
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def update(self, req, id, body):
return self._update(req, id, body, support_disabled_reason=False)
+1 -1
View File
@@ -136,7 +136,7 @@ class ShareManageController(ShareManageMixin, wsgi.Controller):
super(ShareManageController, self).__init__(*args, **kwargs)
self.share_api = share.API()
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def create(self, req, body):
"""Legacy method for 'manage share' operation.
+1 -1
View File
@@ -146,7 +146,7 @@ class ShareTypesController(wsgi.Controller):
context, search_opts=filters).values()
return list(limited_types)
@wsgi.Controller.api_version("1.0", "2.23")
@wsgi.Controller.api_version("2.0", "2.23")
@wsgi.action("create")
def create(self, req, body):
return self._create(req, body, set_defaults=True)
+1 -1
View File
@@ -138,7 +138,7 @@ class ShareTypeExtraSpecsController(wsgi.Controller):
else:
raise webob.exc.HTTPNotFound()
@wsgi.Controller.api_version('1.0', '2.23')
@wsgi.Controller.api_version('2.0', '2.23')
@wsgi.Controller.authorize
def delete(self, req, type_id, id):
"""Deletes an existing extra spec."""
+1 -1
View File
@@ -89,7 +89,7 @@ class ShareUnmanageController(ShareUnmanageMixin, wsgi.Controller):
super(ShareUnmanageController, self).__init__(*args, **kwargs)
self.share_api = share.API()
@wsgi.Controller.api_version('1.0', '2.6')
@wsgi.Controller.api_version('2.0', '2.6')
def unmanage(self, req, id):
return self._unmanage(req, id)
+3 -22
View File
@@ -38,15 +38,6 @@ _MEDIA_TYPES = [{
}]
_KNOWN_VERSIONS = {
'v1.0': {
'id': 'v1.0',
'status': 'DEPRECATED',
'version': '',
'min_version': '',
'updated': '2015-08-27T11:33:21Z',
'links': _LINKS,
'media-types': _MEDIA_TYPES,
},
'v2.0': {
'id': 'v2.0',
'status': 'CURRENT',
@@ -75,27 +66,17 @@ class VersionsRouter(openstack.APIRouter):
class VersionsController(wsgi.Controller):
def __init__(self):
super(VersionsController, self).__init__(None)
@wsgi.Controller.api_version('1.0', '1.0')
def index(self, req):
"""Return versions supported prior to the microversions epoch."""
builder = views_versions.get_view_builder(req)
known_versions = copy.deepcopy(_KNOWN_VERSIONS)
known_versions.pop('v2.0')
return builder.build_versions(known_versions)
super().__init__(None)
@wsgi.Controller.api_version('2.0') # noqa
def index(self, req): # pylint: disable=function-redefined # noqa F811
"""Return versions supported after the start of microversions."""
builder = views_versions.get_view_builder(req)
known_versions = copy.deepcopy(_KNOWN_VERSIONS)
known_versions.pop('v1.0')
return builder.build_versions(known_versions)
# NOTE (cknight): Calling the versions API without
# /v1 or /v2 in the URL will lead to this unversioned
# method, which should always return info about all
# NOTE (cknight): Calling the versions API without /v2 in the URL will lead
# to this unversioned method, which should always return info about all
# available versions.
@wsgi.response(300)
def all(self, req):
+1 -1
View File
@@ -89,7 +89,7 @@ class ViewBuilder(common.ViewBuilder):
metadata = {item['key']: item['value'] for item in metadata}
access_dict['metadata'] = metadata
@common.ViewBuilder.versioned_method("1.0", "2.27")
@common.ViewBuilder.versioned_method("2.0", "2.27")
def translate_transitional_statuses(self, context, access_dict, access):
"""In 2.28, the per access rule status was (re)introduced."""
api = share_api.API()
+1 -1
View File
@@ -97,7 +97,7 @@ class ViewBuilder(common.ViewBuilder):
instance_dict['cast_rules_to_readonly'] = share_instance.get(
'cast_rules_to_readonly', False)
@common.ViewBuilder.versioned_method("1.0", "2.53")
@common.ViewBuilder.versioned_method("2.0", "2.53")
def translate_creating_from_snapshot_status(self, context, instance_dict,
share_instance):
if (share_instance.get('status') ==
+1 -1
View File
@@ -137,7 +137,7 @@ class ViewBuilder(common.ViewBuilder):
def add_mtu(self, context, network_dict, network):
network_dict['mtu'] = network.get('mtu')
@common.ViewBuilder.versioned_method("1.0", "2.25")
@common.ViewBuilder.versioned_method("2.0", "2.25")
def add_nova_net_id(self, context, network_dict, network):
network_dict['nova_net_id'] = None
+1 -1
View File
@@ -192,7 +192,7 @@ class ViewBuilder(common.ViewBuilder):
return shares_dict
@common.ViewBuilder.versioned_method("1.0", "2.53")
@common.ViewBuilder.versioned_method("2.0", "2.53")
def translate_creating_from_snapshot_status(self, context, share_dict,
share):
if share.get('status') == constants.STATUS_CREATING_FROM_SNAPSHOT:
+1 -1
View File
@@ -66,7 +66,7 @@ class ViewBuilder(common.ViewBuilder):
share_type_dict['share_type_access:is_public'] = share_type.get(
'is_public', True)
@common.ViewBuilder.versioned_method("1.0", "2.6")
@common.ViewBuilder.versioned_method("2.0", "2.6")
def add_is_public_attr_extension_like(self, context, share_type_dict,
share_type):
share_type_dict['os-share-type-access:is_public'] = share_type.get(
+1 -5
View File
@@ -23,9 +23,6 @@ def get_view_builder(req):
return ViewBuilder(req.application_url)
_URL_SUFFIX = {'v1.0': 'v1', 'v2.0': 'v2'}
class ViewBuilder(object):
def __init__(self, base_url):
"""Initialize ViewBuilder.
@@ -47,9 +44,8 @@ class ViewBuilder(object):
def _build_links(self, version_data):
"""Generate a container of links that refer to the provided version."""
links = copy.deepcopy(version_data.get('links', {}))
version = _URL_SUFFIX.get(version_data['id'])
links.append({'rel': 'self',
'href': self._generate_href(version=version)})
'href': self._generate_href(version='v2')})
return links
def _generate_href(self, version='v1', path=None):
+2 -4
View File
@@ -25,8 +25,7 @@ from manila.api import common as api_common
from manila.api.openstack import api_version_request as api_version
from manila.api.openstack import wsgi as os_wsgi
from manila.api import urlmap
from manila.api.v1 import router as router_v1
from manila.api.v2 import router as router_v2
from manila.api.v2 import router as router
from manila.common import constants
from manila import context
from manila import exception
@@ -155,8 +154,7 @@ def app():
No auth, just let environ['manila.context'] pass through.
"""
mapper = urlmap.URLMap()
mapper['/v1'] = router_v1.APIRouter()
mapper['/v2'] = router_v2.APIRouter()
mapper['/v2'] = router.APIRouter()
return mapper
+1 -4
View File
@@ -176,12 +176,9 @@ class RequestTest(test.TestCase):
self.assertIsNone(request.set_api_version_request())
if not resource or not ('/v1' in resource or '/v2' in resource):
if not resource or '/v2' not in resource:
self.assertEqual(api_version.APIVersionRequest(),
request.api_version_request)
elif 'v1' in resource:
self.assertEqual(api_version.APIVersionRequest('1.0'),
request.api_version_request)
else:
self.assertEqual(api_version.APIVersionRequest('2.117'),
request.api_version_request)
+1 -1
View File
@@ -23,7 +23,7 @@ from oslo_utils import timeutils
import webob
from manila.api import extensions
from manila.api.v1 import router
from manila.api.v2 import router
from manila import policy
from manila import test
+2 -30
View File
@@ -21,7 +21,7 @@ from oslo_utils import encodeutils
from manila.api.openstack import api_version_request
from manila.api.openstack import wsgi
from manila.api.v1 import router
from manila.api.v2 import router
from manila.api import versions
from manila import test
from manila.tests.api import fakes
@@ -51,15 +51,10 @@ class VersionsControllerTestCase(test.TestCase):
version_list = body['versions']
ids = [v['id'] for v in version_list]
self.assertEqual({'v1.0', 'v2.0'}, set(ids))
self.assertEqual({'v2.0'}, set(ids))
self.assertNotIn(version_header_name, response.headers)
self.assertNotIn('Vary', response.headers)
v1 = [v for v in version_list if v['id'] == 'v1.0'][0]
self.assertEqual('', v1.get('min_version'))
self.assertEqual('', v1.get('version'))
self.assertEqual('DEPRECATED', v1.get('status'))
v2 = [v for v in version_list if v['id'] == 'v2.0'][0]
self.assertEqual(api_version_request._MIN_API_VERSION,
v2.get('min_version'))
@@ -67,29 +62,6 @@ class VersionsControllerTestCase(test.TestCase):
v2.get('version'))
self.assertEqual('CURRENT', v2.get('status'))
@ddt.data('1.0',
'1.1',
api_version_request._MIN_API_VERSION,
api_version_request._MAX_API_VERSION)
def test_versions_v1(self, version):
req = fakes.HTTPRequest.blank('/', base_url='http://localhost/v1')
req.method = 'GET'
req.content_type = 'application/json'
req.headers = {version_header_name: version}
response = req.get_response(router.APIRouter())
self.assertEqual(200, response.status_int)
body = jsonutils.loads(response.body)
version_list = body['versions']
ids = [v['id'] for v in version_list]
self.assertEqual({'v1.0'}, set(ids))
self.assertEqual('1.0', response.headers[version_header_name])
self.assertEqual(version_header_name, response.headers['Vary'])
self.assertEqual('', version_list[0].get('min_version'))
self.assertEqual('', version_list[0].get('version'))
self.assertEqual('DEPRECATED', version_list[0].get('status'))
@ddt.data(api_version_request._MIN_API_VERSION,
api_version_request._MAX_API_VERSION)
def test_versions_v2(self, version):
@@ -0,0 +1,6 @@
---
upgrade:
- |
The Manila v1 API, first deprecated in the Mitaka (v2.0.0) release, has now
been removed. The v2 API with the ``2.0`` microversion is a drop-in
replacement.