diff --git a/etc/manila/api-paste.ini b/etc/manila/api-paste.ini index 42395c1618..8605c353a8 100644 --- a/etc/manila/api-paste.ini +++ b/etc/manila/api-paste.ini @@ -17,6 +17,7 @@ keystone_nolimit = cors faultwrap http_proxy_to_wsgi sizelimit authtoken keyston [composite:openstack_share_api_v2] use = call:manila.api.middleware.auth:pipeline_factory noauth = cors faultwrap http_proxy_to_wsgi sizelimit noauth apiv2 +noauthv2 = cors faultwrap http_proxy_to_wsgi sizelimit noauthv2 apiv2 keystone = cors faultwrap http_proxy_to_wsgi sizelimit authtoken keystonecontext apiv2 keystone_nolimit = cors faultwrap http_proxy_to_wsgi sizelimit authtoken keystonecontext apiv2 @@ -26,6 +27,9 @@ paste.filter_factory = manila.api.middleware.fault:FaultWrapper.factory [filter:noauth] paste.filter_factory = manila.api.middleware.auth:NoAuthMiddleware.factory +[filter:noauthv2] +paste.filter_factory = manila.api.middleware.auth:NoAuthMiddlewarev2_60.factory + [filter:sizelimit] paste.filter_factory = oslo_middleware.sizelimit:RequestBodySizeLimiter.factory diff --git a/manila/api/common.py b/manila/api/common.py index 8484d1c9fb..9ba79b86d9 100644 --- a/manila/api/common.py +++ b/manila/api/common.py @@ -260,6 +260,17 @@ class ViewBuilder(object): _collection_name = None _detail_version_modifiers = [] + def _get_project_id(self, request): + project_id = request.environ["manila.context"].project_id + if '/v1/' in request.url: + # project_ids are mandatory in v1 URLs + return project_id + elif project_id and ("/v2/%s" % project_id in request.url): + # project_ids are not mandatory within v2 URLs, but links need + # to include them if the request does. + return project_id + return '' + def _get_links(self, request, identifier): return [{"rel": "self", "href": self._get_href_link(request, identifier), }, @@ -273,7 +284,7 @@ class ViewBuilder(object): prefix = self._update_link_prefix(request.application_url, CONF.osapi_share_base_URL) url = os.path.join(prefix, - request.environ["manila.context"].project_id, + self._get_project_id(request), self._collection_name) return "%s?%s" % (url, dict_to_query_str(params)) @@ -282,7 +293,7 @@ class ViewBuilder(object): prefix = self._update_link_prefix(request.application_url, CONF.osapi_share_base_URL) return os.path.join(prefix, - request.environ["manila.context"].project_id, + self._get_project_id(request), self._collection_name, str(identifier)) @@ -292,7 +303,7 @@ class ViewBuilder(object): base_url = self._update_link_prefix(base_url, CONF.osapi_share_base_URL) return os.path.join(base_url, - request.environ["manila.context"].project_id, + self._get_project_id(request), self._collection_name, str(identifier)) diff --git a/manila/api/middleware/auth.py b/manila/api/middleware/auth.py index cd6b5490f4..bdea028da2 100644 --- a/manila/api/middleware/auth.py +++ b/manila/api/middleware/auth.py @@ -116,15 +116,17 @@ class ManilaKeystoneContext(base_wsgi.Middleware): return self.application -class NoAuthMiddleware(base_wsgi.Middleware): +class NoAuthMiddlewareBase(base_wsgi.Middleware): """Return a fake token if one isn't specified.""" - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): + def base_call(self, req, project_id_in_path=False): if 'X-Auth-Token' not in req.headers: user_id = req.headers.get('X-Auth-User', 'admin') project_id = req.headers.get('X-Auth-Project-Id', 'admin') - os_url = os.path.join(req.url, project_id) + if project_id_in_path: + os_url = os.path.join(req.url.rstrip('/'), project_id) + else: + os_url = req.url.rstrip('/') res = webob.Response() # NOTE(vish): This is expecting and returning Auth(1.1), whereas # keystone uses 2.0 auth. We should probably allow @@ -148,3 +150,24 @@ class NoAuthMiddleware(base_wsgi.Middleware): req.environ['manila.context'] = ctx return self.application + + +class NoAuthMiddleware(NoAuthMiddlewareBase): + """Return a fake token if one isn't specified. + + Sets project_id in URLs. + """ + + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + return self.base_call(req, project_id_in_path=True) + + +class NoAuthMiddlewarev2_60(NoAuthMiddlewareBase): + """Return a fake token if one isn't specified. + + Does not set project_id in URLs. + """ + @webob.dec.wsgify(RequestClass=wsgi.Request) + def __call__(self, req): + return self.base_call(req) diff --git a/manila/api/openstack/__init__.py b/manila/api/openstack/__init__.py index 249a50c90d..8eaad9fa4e 100644 --- a/manila/api/openstack/__init__.py +++ b/manila/api/openstack/__init__.py @@ -18,6 +18,7 @@ WSGI middleware for OpenStack API controllers. """ +from oslo_config import cfg from oslo_log import log from oslo_service import wsgi as base_wsgi import routes @@ -25,6 +26,16 @@ import routes from manila.api.openstack import wsgi from manila.i18n import _ +openstack_api_opts = [ + cfg.StrOpt('project_id_regex', + default=r"[0-9a-f\-]+", + help=r'The validation regex for project_ids used in urls. ' + r'This defaults to [0-9a-f\\-]+ if not set, ' + r'which matches normal uuids created by keystone.'), +] + +CONF = cfg.CONF +CONF.register_opts(openstack_api_opts) LOG = log.getLogger(__name__) @@ -47,14 +58,43 @@ class APIMapper(routes.Mapper): class ProjectMapper(APIMapper): def resource(self, member_name, collection_name, **kwargs): + """Base resource path handler + + This method is compatible with resource paths that include a + project_id and those that don't. Including project_id in the URLs + was a legacy API requirement; and making API requests against + such endpoints won't work for users that don't belong to a + particular project. + """ + # NOTE(gouthamr): project_id parameter is only valid if its hex + # or hex + dashes (note, integers are a subset of this). This + # is required to handle our overlapping routes issues. + project_id_regex = CONF.project_id_regex + project_id_token = '{project_id:%s}' % project_id_regex if 'parent_resource' not in kwargs: - kwargs['path_prefix'] = '{project_id}/' + kwargs['path_prefix'] = '%s/' % project_id_token else: parent_resource = kwargs['parent_resource'] p_collection = parent_resource['collection_name'] p_member = parent_resource['member_name'] - kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection, - p_member) + kwargs['path_prefix'] = '%s/%s/:%s_id' % (project_id_token, + p_collection, + p_member) + routes.Mapper.resource(self, + member_name, + collection_name, + **kwargs) + + # NOTE(gouthamr): while we are in transition mode to not needing + # project_ids in URLs, we'll need additional routes without project_id. + if 'parent_resource' not in kwargs: + del kwargs['path_prefix'] + else: + parent_resource = kwargs['parent_resource'] + p_collection = parent_resource['collection_name'] + p_member = parent_resource['member_name'] + kwargs['path_prefix'] = '%s/:%s_id' % (p_collection, + p_member) routes.Mapper.resource(self, member_name, collection_name, diff --git a/manila/api/openstack/api_version_request.py b/manila/api/openstack/api_version_request.py index 55b1930829..291ac68909 100644 --- a/manila/api/openstack/api_version_request.py +++ b/manila/api/openstack/api_version_request.py @@ -159,13 +159,14 @@ REST_API_VERSION_HISTORY = """ * 2.58 - Added 'share_groups' and 'share_group_snapshots' to the limits view. * 2.59 - Add driver ``details`` field to migration get progress. + * 2.60 - API URLs no longer need to include a project_id parameter. """ # The minimum and maximum versions of the API supported # The default api version request is defined to be the # minimum version of the API supported. _MIN_API_VERSION = "2.0" -_MAX_API_VERSION = "2.59" +_MAX_API_VERSION = "2.60" DEFAULT_API_VERSION = _MIN_API_VERSION diff --git a/manila/api/openstack/rest_api_version_history.rst b/manila/api/openstack/rest_api_version_history.rst index bb65f059ca..9f4641fcb4 100644 --- a/manila/api/openstack/rest_api_version_history.rst +++ b/manila/api/openstack/rest_api_version_history.rst @@ -323,3 +323,11 @@ user documentation. ---- Added 'details' field to migration get progress api, which optionally may hold additional driver data related to the progress of share migration. + +2.60 +---- + API URLs no longer need a "project_id" argument in them. For example, the + API route: https://$(controller)s/share/v2/$(project_id)s/shares is + equivalent to https://$(controller)s/share/v2/shares. When interacting + with the manila service as system or domain scoped users, project_id should + not be specified in the API path. diff --git a/manila/api/v2/router.py b/manila/api/v2/router.py index 643a93b449..4292d0a81d 100644 --- a/manila/api/v2/router.py +++ b/manila/api/v2/router.py @@ -155,11 +155,13 @@ class APIRouter(manila.api.openstack.APIRouter): collection={"detail": "GET"}, member={"action": "POST"}) - mapper.connect("shares", - "/{project_id}/shares/manage", - controller=self.resources["shares"], - action="manage", - conditions={"method": ["POST"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("shares", + "%s/shares/manage" % path_prefix, + controller=self.resources["shares"], + action="manage", + conditions={"method": ["POST"]}) self.resources["share_instances"] = share_instances.create_resource() mapper.resource("share_instance", "share_instances", @@ -169,40 +171,46 @@ class APIRouter(manila.api.openstack.APIRouter): self.resources["share_instance_export_locations"] = ( share_instance_export_locations.create_resource()) - mapper.connect("share_instances", - ("/{project_id}/share_instances/{share_instance_id}/" - "export_locations"), - controller=self.resources[ - "share_instance_export_locations"], - action="index", - conditions={"method": ["GET"]}) - mapper.connect("share_instances", - ("/{project_id}/share_instances/{share_instance_id}/" - "export_locations/{export_location_uuid}"), - controller=self.resources[ - "share_instance_export_locations"], - action="show", - conditions={"method": ["GET"]}) - mapper.connect("share_instance", - "/{project_id}/shares/{share_id}/instances", - controller=self.resources["share_instances"], - action="get_share_instances", - conditions={"method": ["GET"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("share_instances", + ("%s/share_instances/{share_instance_id}" + "/export_locations" % path_prefix), + controller=self.resources[ + "share_instance_export_locations"], + action="index", + conditions={"method": ["GET"]}) - self.resources["share_export_locations"] = ( - share_export_locations.create_resource()) - mapper.connect("shares", - "/{project_id}/shares/{share_id}/export_locations", - controller=self.resources["share_export_locations"], - action="index", - conditions={"method": ["GET"]}) - mapper.connect("shares", - ("/{project_id}/shares/{share_id}/" - "export_locations/{export_location_uuid}"), - controller=self.resources["share_export_locations"], - action="show", - conditions={"method": ["GET"]}) + mapper.connect("share_instances", + ("%s/share_instances/{share_instance_id}" + "/export_locations" + "/{export_location_uuid}" % path_prefix), + controller=self.resources[ + "share_instance_export_locations"], + action="show", + conditions={"method": ["GET"]}) + + mapper.connect("share_instance", + "%s/shares/{share_id}/instances" % path_prefix, + controller=self.resources["share_instances"], + action="get_share_instances", + conditions={"method": ["GET"]}) + + self.resources["share_export_locations"] = ( + share_export_locations.create_resource()) + mapper.connect("shares", + "%s/shares/{share_id}" + "/export_locations" % path_prefix, + controller=self.resources["share_export_locations"], + action="index", + conditions={"method": ["GET"]}) + mapper.connect("shares", + ("%s/shares/{share_id}/export_locations" + "/{export_location_uuid}" % path_prefix), + controller=self.resources["share_export_locations"], + action="show", + conditions={"method": ["GET"]}) self.resources["snapshots"] = share_snapshots.create_resource() mapper.resource("snapshot", "snapshots", @@ -210,35 +218,38 @@ class APIRouter(manila.api.openstack.APIRouter): collection={"detail": "GET"}, member={"action": "POST"}) - mapper.connect("snapshots", - "/{project_id}/snapshots/manage", - controller=self.resources["snapshots"], - action="manage", - conditions={"method": ["POST"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("snapshots", + "%s/snapshots/manage" % path_prefix, + controller=self.resources["snapshots"], + action="manage", + conditions={"method": ["POST"]}) - mapper.connect("snapshots", - "/{project_id}/snapshots/{snapshot_id}/access-list", - controller=self.resources["snapshots"], - action="access_list", - conditions={"method": ["GET"]}) + mapper.connect("snapshots", + "%s/snapshots/{snapshot_id}" + "/access-list" % path_prefix, + controller=self.resources["snapshots"], + action="access_list", + conditions={"method": ["GET"]}) - self.resources["share_snapshot_export_locations"] = ( - share_snapshot_export_locations.create_resource()) - mapper.connect("snapshots", - "/{project_id}/snapshots/{snapshot_id}/" - "export-locations", - controller=self.resources[ - "share_snapshot_export_locations"], - action="index", - conditions={"method": ["GET"]}) + self.resources["share_snapshot_export_locations"] = ( + share_snapshot_export_locations.create_resource()) + mapper.connect("snapshots", + "%s/snapshots/{snapshot_id}" + "/export-locations" % path_prefix, + controller=self.resources[ + "share_snapshot_export_locations"], + action="index", + conditions={"method": ["GET"]}) - mapper.connect("snapshots", - "/{project_id}/snapshots/{snapshot_id}/" - "export-locations/{export_location_id}", - controller=self.resources[ - "share_snapshot_export_locations"], - action="show", - conditions={"method": ["GET"]}) + mapper.connect("snapshots", + "%s/snapshots/{snapshot_id}/export-locations" + "/{export_location_id}" % path_prefix, + controller=self.resources[ + "share_snapshot_export_locations"], + action="show", + conditions={"method": ["GET"]}) self.resources['snapshot_instances'] = ( share_snapshot_instances.create_resource()) @@ -249,22 +260,25 @@ class APIRouter(manila.api.openstack.APIRouter): self.resources["share_snapshot_instance_export_locations"] = ( share_snapshot_instance_export_locations.create_resource()) - mapper.connect("snapshot-instance", - "/{project_id}/snapshot-instances/" - "{snapshot_instance_id}/export-locations", - controller=self.resources[ - "share_snapshot_instance_export_locations"], - action="index", - conditions={"method": ["GET"]}) - mapper.connect("snapshot-instance", - "/{project_id}/snapshot-instances/" - "{snapshot_instance_id}/export-locations/" - "{export_location_id}", - controller=self.resources[ - "share_snapshot_instance_export_locations"], - action="show", - conditions={"method": ["GET"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("snapshot-instance", + "%s/snapshot-instances/{snapshot_instance_id}" + "/export-locations" % path_prefix, + controller=self.resources[ + "share_snapshot_instance_export_locations"], + action="index", + conditions={"method": ["GET"]}) + + mapper.connect("snapshot-instance", + "%s/snapshot-instances/{snapshot_instance_id}" + "/export-locations" + "/{export_location_id}" % path_prefix, + controller=self.resources[ + "share_snapshot_instance_export_locations"], + action="show", + conditions={"method": ["GET"]}) self.resources["share_metadata"] = share_metadata.create_resource() share_metadata_controller = self.resources["share_metadata"] @@ -274,11 +288,13 @@ class APIRouter(manila.api.openstack.APIRouter): 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"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("metadata", + "%s/shares/{share_id}/metadata" % path_prefix, + controller=share_metadata_controller, + action="update_all", + conditions={"method": ["PUT"]}) self.resources["limits"] = limits.create_resource() mapper.resource("limit", "limits", @@ -297,48 +313,53 @@ class APIRouter(manila.api.openstack.APIRouter): collection={"detail": "GET"}, member={"action": "POST"}) - self.resources["share_network_subnets"] = ( - share_network_subnets.create_resource()) - mapper.connect("share-networks", - "/{project_id}/share-networks/{share_network_id}/" - "subnets", - controller=self.resources["share_network_subnets"], - action="create", - conditions={"method": ["POST"]}) - mapper.connect("share-networks", - "/{project_id}/share-networks/{share_network_id}/" - "subnets/{share_network_subnet_id}", - controller=self.resources["share_network_subnets"], - action="delete", - conditions={"method": ["DELETE"]}) - mapper.connect("share-networks", - "/{project_id}/share-networks/{share_network_id}/" - "subnets/{share_network_subnet_id}", - controller=self.resources["share_network_subnets"], - action="show", - conditions={"method": ["GET"]}) - mapper.connect("share-networks", - "/{project_id}/share-networks/{share_network_id}/" - "subnets", - controller=self.resources["share_network_subnets"], - action="index", - conditions={"method": ["GET"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + self.resources["share_network_subnets"] = ( + share_network_subnets.create_resource()) + mapper.connect("share-networks", + "%s/share-networks/{share_network_id}" + "/subnets" % path_prefix, + controller=self.resources["share_network_subnets"], + action="create", + conditions={"method": ["POST"]}) + mapper.connect("share-networks", + "%s/share-networks/{share_network_id}" + "/subnets/{share_network_subnet_id}" % path_prefix, + controller=self.resources["share_network_subnets"], + action="delete", + conditions={"method": ["DELETE"]}) + mapper.connect("share-networks", + "%s/share-networks/{share_network_id}" + "/subnets/{share_network_subnet_id}" % path_prefix, + controller=self.resources["share_network_subnets"], + action="show", + conditions={"method": ["GET"]}) + mapper.connect("share-networks", + "%s/share-networks/{share_network_id}" + "/subnets" % path_prefix, + controller=self.resources["share_network_subnets"], + action="index", + conditions={"method": ["GET"]}) self.resources["share_servers"] = share_servers.create_resource() mapper.resource("share_server", "share-servers", controller=self.resources["share_servers"], member={"action": "POST"}) - mapper.connect("details", - "/{project_id}/share-servers/{id}/details", - controller=self.resources["share_servers"], - action="details", - conditions={"method": ["GET"]}) - mapper.connect("share_servers", - "/{project_id}/share-servers/manage", - controller=self.resources["share_servers"], - action="manage", - conditions={"method": ["POST"]}) + + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("details", + "%s/share-servers/{id}/details" % path_prefix, + controller=self.resources["share_servers"], + action="details", + conditions={"method": ["GET"]}) + mapper.connect("share_servers", + "%s/share-servers/manage" % path_prefix, + controller=self.resources["share_servers"], + action="manage", + conditions={"method": ["POST"]}) self.resources["types"] = share_types.create_resource() mapper.resource("type", "types", @@ -356,14 +377,18 @@ class APIRouter(manila.api.openstack.APIRouter): 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"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("pools", + "%s/scheduler-stats/pools" % path_prefix, + controller=self.resources["scheduler_stats"], + action="pools_index", + conditions={"method": ["GET"]}) + mapper.connect("pools", + "%s/scheduler-stats/pools/detail" % path_prefix, + controller=self.resources["scheduler_stats"], + action="pools_detail", + conditions={"method": ["GET"]}) self.resources["share-groups"] = share_groups.create_resource() mapper.resource( @@ -371,12 +396,14 @@ class APIRouter(manila.api.openstack.APIRouter): "share-groups", controller=self.resources["share-groups"], collection={"detail": "GET"}) - mapper.connect( - "share-groups", - "/{project_id}/share-groups/{id}/action", - controller=self.resources["share-groups"], - action="action", - conditions={"method": ["POST"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect( + "share-groups", + "%s/share-groups/{id}/action" % path_prefix, + controller=self.resources["share-groups"], + action="action", + conditions={"method": ["POST"]}) self.resources["share-group-types"] = ( share_group_types.create_resource()) @@ -386,47 +413,52 @@ class APIRouter(manila.api.openstack.APIRouter): controller=self.resources["share-group-types"], collection={"detail": "GET", "default": "GET"}, member={"action": "POST"}) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/access", - controller=self.resources["share-group-types"], - action="share_group_type_access", - conditions={"method": ["GET"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/access" % path_prefix, + controller=self.resources["share-group-types"], + action="share_group_type_access", + conditions={"method": ["GET"]}) # NOTE(ameade): These routes can be simplified when the following # issue is fixed: https://github.com/bbangert/routes/issues/68 self.resources["group-specs"] = ( share_group_type_specs.create_resource()) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/group-specs", - controller=self.resources["group-specs"], - action="index", - conditions={"method": ["GET"]}) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/group-specs", - controller=self.resources["group-specs"], - action="create", - conditions={"method": ["POST"]}) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/group-specs/{key}", - controller=self.resources["group-specs"], - action="show", - conditions={"method": ["GET"]}) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/group-specs/{key}", - controller=self.resources["group-specs"], - action="delete", - conditions={"method": ["DELETE"]}) - mapper.connect( - "share-group-types", - "/{project_id}/share-group-types/{id}/group-specs/{key}", - controller=self.resources["group-specs"], - action="update", - conditions={"method": ["PUT"]}) + + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/group-specs" % path_prefix, + controller=self.resources["group-specs"], + action="index", + conditions={"method": ["GET"]}) + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/group-specs" % path_prefix, + controller=self.resources["group-specs"], + action="create", + conditions={"method": ["POST"]}) + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/group-specs/{key}" % path_prefix, + controller=self.resources["group-specs"], + action="show", + conditions={"method": ["GET"]}) + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/group-specs/{key}" % path_prefix, + controller=self.resources["group-specs"], + action="delete", + conditions={"method": ["DELETE"]}) + mapper.connect( + "share-group-types", + "%s/share-group-types/{id}/group-specs/{key}" % path_prefix, + controller=self.resources["group-specs"], + action="update", + conditions={"method": ["PUT"]}) self.resources["share-group-snapshots"] = ( share_group_snapshots.create_resource()) @@ -436,34 +468,41 @@ class APIRouter(manila.api.openstack.APIRouter): controller=self.resources["share-group-snapshots"], collection={"detail": "GET"}, member={"members": "GET", "action": "POST"}) - mapper.connect( - "share-group-snapshots", - "/{project_id}/share-group-snapshots/{id}/action", - controller=self.resources["share-group-snapshots"], - action="action", - conditions={"method": ["POST"]}) + + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect( + "share-group-snapshots", + "%s/share-group-snapshots/{id}/action" % path_prefix, + controller=self.resources["share-group-snapshots"], + action="action", + conditions={"method": ["POST"]}) self.resources['share-replicas'] = share_replicas.create_resource() mapper.resource("share-replica", "share-replicas", controller=self.resources['share-replicas'], collection={'detail': 'GET'}, member={'action': 'POST'}) + self.resources["share-replica-export-locations"] = ( share_replica_export_locations.create_resource()) - mapper.connect("share-replicas", - ("/{project_id}/share-replicas/{share_replica_id}/" - "export-locations"), - controller=self.resources[ - "share-replica-export-locations"], - action="index", - conditions={"method": ["GET"]}) - mapper.connect("share-replicas", - ("/{project_id}/share-replicas/{share_replica_id}/" - "export-locations/{export_location_uuid}"), - controller=self.resources[ - "share-replica-export-locations"], - action="show", - conditions={"method": ["GET"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + mapper.connect("share-replicas", + ("%s/share-replicas/{share_replica_id}" + "/export-locations" % path_prefix), + controller=self.resources[ + "share-replica-export-locations"], + action="index", + conditions={"method": ["GET"]}) + mapper.connect("share-replicas", + ("%s/share-replicas/{share_replica_id}" + "/export-locations" + "/{export_location_uuid}" % path_prefix), + controller=self.resources[ + "share-replica-export-locations"], + action="show", + conditions={"method": ["GET"]}) self.resources['messages'] = messages.create_resource() mapper.resource("message", "messages", @@ -476,18 +515,21 @@ class APIRouter(manila.api.openstack.APIRouter): controller=self.resources["share-access-rules"], collection={"detail": "GET"}) - self.resources["access-metadata"] = ( - share_access_metadata.create_resource()) - access_metadata_controller = self.resources["access-metadata"] - mapper.connect("share-access-rules", - "/{project_id}/share-access-rules/{access_id}/metadata", - controller=access_metadata_controller, - action="update", - conditions={"method": ["PUT"]}) + for path_prefix in ['/{project_id}', '']: + # project_id is optional + self.resources["access-metadata"] = ( + share_access_metadata.create_resource()) + access_metadata_controller = self.resources["access-metadata"] + mapper.connect("share-access-rules", + "%s/share-access-rules" + "/{access_id}/metadata" % path_prefix, + controller=access_metadata_controller, + action="update", + conditions={"method": ["PUT"]}) - mapper.connect("share-access-rules", - "/{project_id}/share-access-rules/" - "{access_id}/metadata/{key}", - controller=access_metadata_controller, - action="delete", - conditions={"method": ["DELETE"]}) + mapper.connect("share-access-rules", + "%s/share-access-rules" + "/{access_id}/metadata/{key}" % path_prefix, + controller=access_metadata_controller, + action="delete", + conditions={"method": ["DELETE"]}) diff --git a/manila/common/config.py b/manila/common/config.py index bab5e74db6..c76630065d 100644 --- a/manila/common/config.py +++ b/manila/common/config.py @@ -128,7 +128,7 @@ global_opts = [ cfg.StrOpt('auth_strategy', default='keystone', help='The strategy to use for auth. Supports noauth, keystone, ' - 'and deprecated.'), + 'and noauthv2.'), cfg.ListOpt('enabled_share_backends', help='A list of share backend names to use. These backend ' 'names should be backed by a unique [CONFIG] group ' diff --git a/manila/tests/api/fakes.py b/manila/tests/api/fakes.py index b71ae42d71..568c54e770 100644 --- a/manila/tests/api/fakes.py +++ b/manila/tests/api/fakes.py @@ -86,7 +86,11 @@ class HTTPRequest(os_wsgi.Request): @classmethod def blank(cls, *args, **kwargs): if not kwargs.get('base_url'): - kwargs['base_url'] = 'http://localhost/v1' + method_url = args[0] + if method_url.startswith('/v2'): + kwargs['base_url'] = 'http://localhost/share/v2' + else: + kwargs['base_url'] = 'http://localhost/share/v1' use_admin_context = kwargs.pop('use_admin_context', False) version = kwargs.pop('version', api_version.DEFAULT_API_VERSION) experimental = kwargs.pop('experimental', False) diff --git a/manila/tests/api/v1/test_share_snapshots.py b/manila/tests/api/v1/test_share_snapshots.py index 7e3f06b443..c5db90ab5c 100644 --- a/manila/tests/api/v1/test_share_snapshots.py +++ b/manila/tests/api/v1/test_share_snapshots.py @@ -65,7 +65,7 @@ class ShareSnapshotAPITest(test.TestCase): } self.mock_object(share_api.API, 'get_snapshot', mock.Mock(return_value=return_snapshot)) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/fake/snapshots/200') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, '200') @@ -82,7 +82,7 @@ class ShareSnapshotAPITest(test.TestCase): 'description': 'displaysnapdesc', } } - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/fake/snapshots') res_dict = self.controller.create(req, body) @@ -105,7 +105,7 @@ class ShareSnapshotAPITest(test.TestCase): 'description': 'fake_share_description', } } - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/fake/snapshots') self.assertRaises( webob.exc.HTTPUnprocessableEntity, @@ -115,7 +115,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_create_no_body(self): body = {} - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/fake/snapshots') self.assertRaises(webob.exc.HTTPUnprocessableEntity, self.controller.create, req, @@ -124,21 +124,21 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_delete(self): self.mock_object(share_api.API, 'delete_snapshot', stubs.stub_snapshot_delete) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/fake/snapshots/200') resp = self.controller.delete(req, 200) self.assertEqual(202, resp.status_int) def test_snapshot_delete_nofound(self): self.mock_object(share_api.API, 'get_snapshot', stubs.stub_snapshot_get_notfound) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/fake/snapshots/200') self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, 200) def test_snapshot_show(self): - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/fake/snapshots/200') res_dict = self.controller.show(req, 200) expected = fake_share.expected_snapshot(id=200) self.assertEqual(expected, res_dict) @@ -146,7 +146,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_show_nofound(self): self.mock_object(share_api.API, 'get_snapshot', stubs.stub_snapshot_get_notfound) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/fake/snapshots/200') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, '200') @@ -154,7 +154,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_list_summary(self): self.mock_object(share_api.API, 'get_all_snapshots', stubs.stub_snapshot_get_all_by_project) - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/fake/snapshots') res_dict = self.controller.index(req) expected = { 'snapshots': [ @@ -163,12 +163,12 @@ class ShareSnapshotAPITest(test.TestCase): 'id': 2, 'links': [ { - 'href': 'http://localhost/v1/fake/' + 'href': 'http://localhost/share/v1/fake/' 'snapshots/2', 'rel': 'self' }, { - 'href': 'http://localhost/fake/snapshots/2', + 'href': 'http://localhost/share/fake/snapshots/2', 'rel': 'bookmark' } ], @@ -180,7 +180,7 @@ class ShareSnapshotAPITest(test.TestCase): def _snapshot_list_summary_with_search_opts(self, use_admin_context): search_opts = fake_share.search_opts() # fake_key should be filtered for non-admin - url = '/snapshots?fake_key=fake_value' + url = '/fake/snapshots?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) @@ -225,7 +225,7 @@ class ShareSnapshotAPITest(test.TestCase): def _snapshot_list_detail_with_search_opts(self, use_admin_context): search_opts = fake_share.search_opts() # fake_key should be filtered for non-admin - url = '/shares/detail?fake_key=fake_value' + url = '/fake/shares/detail?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) @@ -289,7 +289,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_list_detail(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env) + req = fakes.HTTPRequest.blank('/fake/shares/detail', environ=env) res_dict = self.controller.detail(req) expected_s = fake_share.expected_snapshot(id=2) expected = {'snapshots': [expected_s['snapshot']]} @@ -316,7 +316,7 @@ class ShareSnapshotAPITest(test.TestCase): ] self.mock_object(share_api.API, 'get_all_snapshots', mock.Mock(return_value=snapshots)) - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/fake/snapshots') result = self.controller.index(req) self.assertEqual(1, len(result['snapshots'])) self.assertEqual(snapshots[0]['id'], result['snapshots'][0]['id']) @@ -325,7 +325,7 @@ class ShareSnapshotAPITest(test.TestCase): snp = self.snp_example body = {"snapshot": snp} - req = fakes.HTTPRequest.blank('/snapshot/1') + req = fakes.HTTPRequest.blank('/fake/snapshot/1') res_dict = self.controller.update(req, 1, body) self.assertEqual(snp["display_name"], res_dict['snapshot']["name"]) @@ -333,7 +333,7 @@ class ShareSnapshotAPITest(test.TestCase): snp = self.snp_example body = {"snapshot": snp} - req = fakes.HTTPRequest.blank('/snapshot/1') + req = fakes.HTTPRequest.blank('/fake/snapshot/1') res_dict = self.controller.update(req, 1, body) self.assertEqual(snp["display_description"], @@ -343,7 +343,7 @@ class ShareSnapshotAPITest(test.TestCase): snp = self.snp_example body = {"snapshot": snp} - req = fakes.HTTPRequest.blank('/snapshot/1') + req = fakes.HTTPRequest.blank('/fake/snapshot/1') res_dict = self.controller.update(req, 1, body) self.assertNotEqual(snp["size"], res_dict['snapshot']["size"]) diff --git a/manila/tests/api/v1/test_shares.py b/manila/tests/api/v1/test_shares.py index e621290fdc..11f9a033de 100644 --- a/manila/tests/api/v1/test_shares.py +++ b/manila/tests/api/v1/test_shares.py @@ -117,11 +117,11 @@ class ShareAPITest(test.TestCase): 'is_public': False, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v1/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -143,7 +143,7 @@ class ShareAPITest(test.TestCase): def test_share_create_original(self, microversion): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -157,7 +157,7 @@ class ShareAPITest(test.TestCase): def test_share_create_with_snapshot_support_without_cg(self, microversion): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/v1/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -173,7 +173,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') res_dict = self.controller.create(req, body) self.mock_policy_check.assert_called_once_with( @@ -191,7 +191,7 @@ class ShareAPITest(test.TestCase): self.vt['name'])), ) CONF.set_default("default_share_type", self.vt['name']) - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') self.assertRaises(exception.ShareTypeNotFoundByName, self.controller.create, req, {'share': self.share}) @@ -212,7 +212,7 @@ class ShareAPITest(test.TestCase): mock.Mock(return_value=fake_share_type), ) CONF.set_default("default_share_type", fake_share_type['name']) - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, {'share': self.share}) @@ -244,7 +244,7 @@ class ShareAPITest(test.TestCase): mock.Mock(return_value={'id': 'fakesubnetid'})) body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') res_dict = self.controller.create(req, body) self.mock_policy_check.assert_called_once_with( @@ -276,7 +276,7 @@ class ShareAPITest(test.TestCase): share_network_id=shr['share_network_id'])) self.mock_object(share_api.API, 'create', create_mock) body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') res_dict = self.controller.create(req, body) @@ -320,7 +320,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') res_dict = self.controller.create(req, body) @@ -367,7 +367,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') res_dict = self.controller.create(req, body) @@ -392,7 +392,7 @@ class ShareAPITest(test.TestCase): "share_network_id": 1234 } body = {"share": shr} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v1/fake/shares') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, @@ -439,7 +439,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/v1/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -459,7 +459,7 @@ class ShareAPITest(test.TestCase): "share_proto": "fakeproto", "availability_zone": "zone1:host1"} body = {"share": shr} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/fake/shares') self.assertRaises(exception.InvalidInput, self.controller.create, req, @@ -469,7 +469,7 @@ class ShareAPITest(test.TestCase): def test_share_create_no_body(self): body = {} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/fake/shares') self.assertRaises(webob.exc.HTTPUnprocessableEntity, self.controller.create, req, @@ -485,7 +485,7 @@ class ShareAPITest(test.TestCase): ) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/fake/shares') self.assertRaises(webob.exc.HTTPNotFound, self.controller.create, req, @@ -507,14 +507,14 @@ class ShareAPITest(test.TestCase): body = {"share": fake_share_with_sn} - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/fake/shares') self.assertRaises(exception_to_raise, self.controller.create, req, body) def test_share_show(self): - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/fake/shares/1') expected = self._get_expected_share_detailed_response() expected['share'].pop('snapshot_support') @@ -523,7 +523,7 @@ class ShareAPITest(test.TestCase): self.assertEqual(expected, res_dict) def test_share_show_with_share_type_name(self): - req = fakes.HTTPRequest.blank('/shares/1', version='2.6') + req = fakes.HTTPRequest.blank('/fake/shares/1', version='2.6') res_dict = self.controller.show(req, '1') expected = self._get_expected_share_detailed_response() expected['share']['share_type_name'] = None @@ -531,7 +531,7 @@ class ShareAPITest(test.TestCase): self.assertEqual(expected, res_dict) def test_share_show_admin(self): - req = fakes.HTTPRequest.blank('/shares/1', use_admin_context=True) + req = fakes.HTTPRequest.blank('/fake/shares/1', use_admin_context=True) expected = self._get_expected_share_detailed_response(admin=True) expected['share'].pop('snapshot_support') @@ -542,13 +542,13 @@ class ShareAPITest(test.TestCase): def test_share_show_no_share(self): self.mock_object(share_api.API, 'get', stubs.stub_share_get_notfound) - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/fake/shares/1') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, '1') def test_share_delete(self): - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/fake/shares/1') resp = self.controller.delete(req, 1) self.assertEqual(202, resp.status_int) @@ -580,7 +580,7 @@ class ShareAPITest(test.TestCase): def test_share_delete_no_share(self): self.mock_object(share_api.API, 'get', stubs.stub_share_get_notfound) - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/fake/shares/1') self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, @@ -605,7 +605,7 @@ class ShareAPITest(test.TestCase): if use_admin_context: search_opts['host'] = 'fake_host' # fake_key should be filtered for non-admin - url = '/shares?fake_key=fake_value' + url = '/fake/shares?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) @@ -657,7 +657,7 @@ class ShareAPITest(test.TestCase): def test_share_list_summary(self): self.mock_object(share_api.API, 'get_all', stubs.stub_share_get_all_by_project) - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/fake/shares') res_dict = self.controller.index(req) expected = { 'shares': [ @@ -666,11 +666,11 @@ class ShareAPITest(test.TestCase): 'id': '1', 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v1/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -698,7 +698,7 @@ class ShareAPITest(test.TestCase): if use_admin_context: search_opts['host'] = 'fake_host' # fake_key should be filtered for non-admin - url = '/shares/detail?fake_key=fake_value' + url = '/fake/shares/detail?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) @@ -792,11 +792,11 @@ class ShareAPITest(test.TestCase): 'is_public': False, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v1/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -815,14 +815,14 @@ class ShareAPITest(test.TestCase): def test_share_list_detail(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env) + req = fakes.HTTPRequest.blank('/fake/shares/detail', environ=env) expected = self._list_detail_common_expected() expected['shares'][0].pop('snapshot_support') self._list_detail_test_common(req, expected) def test_share_list_detail_with_task_state(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env, + req = fakes.HTTPRequest.blank('/fake/shares/detail', environ=env, version="2.5") expected = self._list_detail_common_expected() expected['shares'][0]['task_state'] = None @@ -896,7 +896,7 @@ class ShareActionsTest(test.TestCase): id = 'fake_share_id' body = {'os-allow_access': access} expected = {'access': {'fake': 'fake'}} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) res = self.controller._allow_access(req, id, body) @@ -924,7 +924,7 @@ class ShareActionsTest(test.TestCase): def test_allow_access_error(self, access): id = 'fake_share_id' body = {'os-allow_access': access} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPBadRequest, self.controller._allow_access, req, id, body) @@ -940,7 +940,7 @@ class ShareActionsTest(test.TestCase): id = 'fake_share_id' body = {"os-deny_access": {"access_id": 'fake_acces_id'}} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) res = self.controller._deny_access(req, id, body) @@ -957,7 +957,7 @@ class ShareActionsTest(test.TestCase): id = 'super_fake_share_id' body = {"os-deny_access": {"access_id": 'fake_acces_id'}} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPNotFound, self.controller._deny_access, @@ -969,7 +969,7 @@ class ShareActionsTest(test.TestCase): @ddt.data('_allow_access', '_deny_access') def test_allow_access_deny_access_policy_not_authorized(self, method): - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/someuuid/action') + req = fakes.HTTPRequest.blank('/tenant1/shares/someuuid/action') action = method[1:] body = {action: None} noauthexc = exception.PolicyNotAuthorized(action=action) @@ -996,7 +996,7 @@ class ShareActionsTest(test.TestCase): fake_access_list})) id = 'fake_share_id' body = {"os-access_list": None} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/tenant1/shares/%s/action' % id) res_dict = self.controller._access_list(req, id, body) self.assertEqual({'access_list': fake_access_list}, res_dict) @@ -1009,7 +1009,7 @@ class ShareActionsTest(test.TestCase): size = '123' body = {"os-extend": {'new_size': size}} - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) actual_response = self.controller._extend(req, id, body) @@ -1023,7 +1023,7 @@ class ShareActionsTest(test.TestCase): {"os-extend": {"new_size": {'foo': 'bar'}}}) def test_extend_invalid_body(self, body): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPBadRequest, self.controller._extend, req, id, body) @@ -1037,7 +1037,7 @@ class ShareActionsTest(test.TestCase): @ddt.unpack def test_extend_exception(self, source, target): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) body = {"os-extend": {'new_size': '123'}} self.mock_object(share_api.API, "extend", mock.Mock(side_effect=source('fake'))) @@ -1052,7 +1052,7 @@ class ShareActionsTest(test.TestCase): size = '123' body = {"os-shrink": {'new_size': size}} - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) actual_response = self.controller._shrink(req, id, body) @@ -1066,7 +1066,7 @@ class ShareActionsTest(test.TestCase): {"os-shrink": {"new_size": {'foo': 'bar'}}}) def test_shrink_invalid_body(self, body): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPBadRequest, self.controller._shrink, req, id, body) @@ -1078,7 +1078,7 @@ class ShareActionsTest(test.TestCase): @ddt.unpack def test_shrink_exception(self, source, target): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/fake/shares/%s/action' % id) body = {"os-shrink": {'new_size': '123'}} self.mock_object(share_api.API, "shrink", mock.Mock(side_effect=source('fake'))) @@ -1162,7 +1162,7 @@ class ShareAdminActionsAPITest(test.TestCase): def test_share_reset_status_for_missing(self): fake_share = {'id': 'missing-share-id'} - req = webob.Request.blank('/v1/fake/shares/%s/action' % + req = webob.Request.blank('/fake/shares/%s/action' % fake_share['id']) self._reset_status(self.admin_context, fake_share, req, diff --git a/manila/tests/api/v2/test_messages.py b/manila/tests/api/v2/test_messages.py index a43de7d5b1..7ff91f2eee 100644 --- a/manila/tests/api/v2/test_messages.py +++ b/manila/tests/api/v2/test_messages.py @@ -43,9 +43,9 @@ class MessageApiTest(test.TestCase): def _expected_message_from_controller(self, id, **kwargs): message = stubs.stub_message(id, **kwargs) links = [ - {'href': 'http://localhost/v2/fake/messages/%s' % id, + {'href': 'http://localhost/share/v2/fake/messages/%s' % id, 'rel': 'self'}, - {'href': 'http://localhost/fake/messages/%s' % id, + {'href': 'http://localhost/share/fake/messages/%s' % id, 'rel': 'bookmark'}, ] return { @@ -71,9 +71,8 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get', stubs.stub_message_get) req = fakes.HTTPRequest.blank( - '/messages/%s' % fakes.FAKE_UUID, - version=messages.MESSAGES_BASE_MICRO_VERSION, - base_url='http://localhost/v2') + '/v2/fake/messages/%s' % fakes.FAKE_UUID, + version=messages.MESSAGES_BASE_MICRO_VERSION) req.environ['manila.context'] = self.ctxt res_dict = self.controller.show(req, fakes.FAKE_UUID) @@ -91,9 +90,9 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get', mock_get) req = fakes.HTTPRequest.blank( - '/messages/%s' % fakes.FAKE_UUID, + '/v2/fake/messages/%s' % fakes.FAKE_UUID, version=messages.MESSAGES_BASE_MICRO_VERSION, - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt res_dict = self.controller.show(req, fakes.FAKE_UUID) @@ -109,9 +108,9 @@ class MessageApiTest(test.TestCase): mock.Mock(side_effect=fake_not_found)) req = fakes.HTTPRequest.blank( - '/messages/%s' % fakes.FAKE_UUID, + '/v2/fake/messages/%s' % fakes.FAKE_UUID, version=messages.MESSAGES_BASE_MICRO_VERSION, - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, @@ -120,9 +119,9 @@ class MessageApiTest(test.TestCase): def test_show_pre_microversion(self): self.mock_object(message_api.API, 'get', stubs.stub_message_get) - req = fakes.HTTPRequest.blank('/messages/%s' % fakes.FAKE_UUID, + req = fakes.HTTPRequest.blank('/v2/fake/messages/%s' % fakes.FAKE_UUID, version='2.35', - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt self.assertRaises(exception.VersionNotFoundForAPIMethod, @@ -133,7 +132,7 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'delete') req = fakes.HTTPRequest.blank( - '/messages/%s' % fakes.FAKE_UUID, + '/v2/fake/messages/%s' % fakes.FAKE_UUID, version=messages.MESSAGES_BASE_MICRO_VERSION) req.environ['manila.context'] = self.ctxt @@ -148,7 +147,7 @@ class MessageApiTest(test.TestCase): mock.Mock(side_effect=fake_not_found)) req = fakes.HTTPRequest.blank( - '/messages/%s' % fakes.FAKE_UUID, + '/v2/fake/messages/%s' % fakes.FAKE_UUID, version=messages.MESSAGES_BASE_MICRO_VERSION) self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, @@ -160,9 +159,9 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get_all', mock.Mock( return_value=[msg1, msg2])) req = fakes.HTTPRequest.blank( - '/messages', + '/v2/fake/messages', version=messages.MESSAGES_BASE_MICRO_VERSION, - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt res_dict = self.controller.index(req) @@ -177,9 +176,8 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get_all', mock.Mock( return_value=[msg2])) req = fakes.HTTPRequest.blank( - '/messages?limit=1&offset=1', - version=messages.MESSAGES_BASE_MICRO_VERSION, - base_url='http://localhost/v2') + '/v2/fake/messages?limit=1&offset=1', + version=messages.MESSAGES_BASE_MICRO_VERSION) req.environ['manila.context'] = self.ctxt res_dict = self.controller.index(req) @@ -195,10 +193,10 @@ class MessageApiTest(test.TestCase): self.mock_object(message_api.API, 'get_all', mock.Mock( return_value=[msg])) req = fakes.HTTPRequest.blank( - '/messages?created_since=1900-01-01T01:01:01&' + '/fake/messages?created_since=1900-01-01T01:01:01&' 'created_before=1900-03-01T01:01:01', version=messages.MESSAGES_QUERY_BY_TIMESTAMP, - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt res_dict = self.controller.index(req) @@ -213,7 +211,7 @@ class MessageApiTest(test.TestCase): req = fakes.HTTPRequest.blank( '/messages?created_since=invalid_time_str', version=messages.MESSAGES_QUERY_BY_TIMESTAMP, - base_url='http://localhost/v2') + base_url='http://localhost/share/v2') req.environ['manila.context'] = self.ctxt self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req) diff --git a/manila/tests/api/v2/test_share_instances.py b/manila/tests/api/v2/test_share_instances.py index 3462944280..da4425161d 100644 --- a/manila/tests/api/v2/test_share_instances.py +++ b/manila/tests/api/v2/test_share_instances.py @@ -97,7 +97,7 @@ class ShareInstancesAPITest(test.TestCase): req_context, self.resource_name, 'index') def test_index_with_limit(self): - req = self._get_request('/share_instances') + req = self._get_request('/v2/fake/share_instances') req_context = req.environ['manila.context'] share_instances_count = 3 test_instances = [ @@ -107,13 +107,13 @@ class ShareInstancesAPITest(test.TestCase): expect_links = [ { 'href': ( - 'http://localhost/v1/fake/share_instances?' + 'http://localhost/share/v2/fake/share_instances?' 'limit=3&marker=%s' % test_instances[2]['id']), 'rel': 'next', } ] - url = 'share_instances?limit=3' + url = '/v2/fake/share_instances?limit=3' req = self._get_request(url) actual_result = self.controller.index(req) diff --git a/manila/tests/api/v2/test_share_snapshot_export_locations.py b/manila/tests/api/v2/test_share_snapshot_export_locations.py index ca960e31b4..6c9c9f14e9 100644 --- a/manila/tests/api/v2/test_share_snapshot_export_locations.py +++ b/manila/tests/api/v2/test_share_snapshot_export_locations.py @@ -32,7 +32,7 @@ class ShareSnapshotExportLocationsAPITest(test.TestCase): def _get_request(self, version="2.32", use_admin_context=True): req = fakes.HTTPRequest.blank( - '/snapshots/%s/export-locations' % self.snapshot['id'], + '/v2/fake/snapshots/%s/export-locations' % self.snapshot['id'], version=version, use_admin_context=use_admin_context) return req @@ -75,12 +75,12 @@ class ShareSnapshotExportLocationsAPITest(test.TestCase): 'is_admin_only': True, 'id': self.exp_loc['id'], 'links': [{ - 'href': 'http://localhost/v1/fake/' + 'href': 'http://localhost/share/v2/fake/' 'share_snapshot_export_locations/' + self.exp_loc['id'], 'rel': 'self' }, { - 'href': 'http://localhost/fake/' + 'href': 'http://localhost/share/fake/' 'share_snapshot_export_locations/' + self.exp_loc['id'], 'rel': 'bookmark' diff --git a/manila/tests/api/v2/test_share_snapshot_instance_export_locations.py b/manila/tests/api/v2/test_share_snapshot_instance_export_locations.py index 4f6cb295c2..8a166a4bc3 100644 --- a/manila/tests/api/v2/test_share_snapshot_instance_export_locations.py +++ b/manila/tests/api/v2/test_share_snapshot_instance_export_locations.py @@ -32,7 +32,7 @@ class ShareSnapshotInstanceExportLocationsAPITest(test.TestCase): def _get_request(self, version="2.32", use_admin_context=True): req = fakes.HTTPRequest.blank( - '/snapshot-instances/%s/export-locations' % + '/v2/fake/snapshot-instances/%s/export-locations' % self.snapshot_instance['id'], version=version, use_admin_context=use_admin_context) return req @@ -74,11 +74,11 @@ class ShareSnapshotInstanceExportLocationsAPITest(test.TestCase): 'is_admin_only': True, 'id': self.el['id'], 'links': [{ - 'href': 'http://localhost/v1/fake/' + 'href': 'http://localhost/share/v2/fake/' 'share_snapshot_export_locations/' + self.el['id'], 'rel': 'self' }, { - 'href': 'http://localhost/fake/' + 'href': 'http://localhost/share/fake/' 'share_snapshot_export_locations/' + self.el['id'], 'rel': 'bookmark' }], diff --git a/manila/tests/api/v2/test_share_snapshots.py b/manila/tests/api/v2/test_share_snapshots.py index 68eb49659a..cf5f3034a1 100644 --- a/manila/tests/api/v2/test_share_snapshots.py +++ b/manila/tests/api/v2/test_share_snapshots.py @@ -87,7 +87,10 @@ class ShareSnapshotAPITest(test.TestCase): 'description': 'displaysnapdesc', } } - req = fakes.HTTPRequest.blank('/snapshots', version=version) + url = ('/v2/fake/snapshots' + if version.startswith('2.') + else '/v1/fake/snapshots') + req = fakes.HTTPRequest.blank(url, version=version) res_dict = self.controller.create(req, body) @@ -110,7 +113,7 @@ class ShareSnapshotAPITest(test.TestCase): 'description': 'fake_share_description', } } - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots') self.assertRaises( webob.exc.HTTPUnprocessableEntity, @@ -120,7 +123,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_create_no_body(self): body = {} - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots') self.assertRaises(webob.exc.HTTPUnprocessableEntity, self.controller.create, req, @@ -129,14 +132,14 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_delete(self): self.mock_object(share_api.API, 'delete_snapshot', stubs.stub_snapshot_delete) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/200') resp = self.controller.delete(req, 200) self.assertEqual(202, resp.status_int) def test_snapshot_delete_nofound(self): self.mock_object(share_api.API, 'get_snapshot', stubs.stub_snapshot_get_notfound) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/200') self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, @@ -144,7 +147,8 @@ class ShareSnapshotAPITest(test.TestCase): @ddt.data('2.0', '2.16', '2.17') def test_snapshot_show(self, version): - req = fakes.HTTPRequest.blank('/snapshots/200', version=version) + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/200', + version=version) expected = fake_share.expected_snapshot(version=version, id=200) res_dict = self.controller.show(req, 200) @@ -154,7 +158,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_show_nofound(self): self.mock_object(share_api.API, 'get_snapshot', stubs.stub_snapshot_get_notfound) - req = fakes.HTTPRequest.blank('/snapshots/200') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/200') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, '200') @@ -162,7 +166,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_list_summary(self): self.mock_object(share_api.API, 'get_all_snapshots', stubs.stub_snapshot_get_all_by_project) - req = fakes.HTTPRequest.blank('/snapshots') + req = fakes.HTTPRequest.blank('/v2/fake/snapshots') res_dict = self.controller.index(req) expected = { 'snapshots': [ @@ -171,12 +175,12 @@ class ShareSnapshotAPITest(test.TestCase): 'id': 2, 'links': [ { - 'href': 'http://localhost/v1/fake/' + 'href': 'http://localhost/share/v2/fake/' 'snapshots/2', 'rel': 'self' }, { - 'href': 'http://localhost/fake/snapshots/2', + 'href': 'http://localhost/share/fake/snapshots/2', 'rel': 'bookmark' } ], @@ -193,7 +197,7 @@ class ShareSnapshotAPITest(test.TestCase): search_opts.pop('name') search_opts['display_name~'] = 'fake_name' # fake_key should be filtered for non-admin - url = '/snapshots?fake_key=fake_value' + url = '/v2/fake/snapshots?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank( @@ -244,7 +248,7 @@ class ShareSnapshotAPITest(test.TestCase): def _snapshot_list_detail_with_search_opts(self, use_admin_context): search_opts = fake_share.search_opts() # fake_key should be filtered for non-admin - url = '/shares/detail?fake_key=fake_value' + url = '/v2/fake/shares/detail?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context) @@ -307,7 +311,8 @@ class ShareSnapshotAPITest(test.TestCase): @ddt.data('2.0', '2.16', '2.17') def test_snapshot_list_detail(self, version): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/snapshots/detail', environ=env, + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/detail', + environ=env, version=version) expected_s = fake_share.expected_snapshot(version=version, id=2) expected = {'snapshots': [expected_s['snapshot']]} @@ -320,7 +325,7 @@ class ShareSnapshotAPITest(test.TestCase): def test_snapshot_updates_display_name_and_description(self, version): snp = self.snp_example body = {"snapshot": snp} - req = fakes.HTTPRequest.blank('/snapshot/1', version=version) + req = fakes.HTTPRequest.blank('/v2/fake/snapshot/1', version=version) res_dict = self.controller.update(req, 1, body) @@ -338,7 +343,7 @@ class ShareSnapshotAPITest(test.TestCase): snp = self.snp_example body = {"snapshot": snp} - req = fakes.HTTPRequest.blank('/snapshot/1') + req = fakes.HTTPRequest.blank('/v2/fake/snapshot/1') res_dict = self.controller.update(req, 1, body) self.assertNotEqual(snp["size"], res_dict['snapshot']["size"]) @@ -358,7 +363,7 @@ class ShareSnapshotAPITest(test.TestCase): mock.Mock(return_value=expected)) id = 'fake_snap_id' - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % id, + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/%s/action' % id, version='2.32') actual = self.controller.access_list(req, id) @@ -388,8 +393,8 @@ class ShareSnapshotAPITest(test.TestCase): allow_access = self.mock_object(share_api.API, 'snapshot_allow_access', mock.Mock(return_value=access)) body = {'allow_access': access} - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version=version) + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version=version) actual = self.controller.allow_access(req, snapshot['id'], body) @@ -406,8 +411,8 @@ class ShareSnapshotAPITest(test.TestCase): share = db_utils.create_share(mount_snapshot_support=True) snapshot = db_utils.create_snapshot( status=constants.STATUS_AVAILABLE, share_id=share['id']) - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') body = {} self.assertRaises(webob.exc.HTTPBadRequest, @@ -418,8 +423,8 @@ class ShareSnapshotAPITest(test.TestCase): share = db_utils.create_share(mount_snapshot_support=True) snapshot = db_utils.create_snapshot( status=constants.STATUS_AVAILABLE, share_id=share['id']) - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') access = { 'id': 'fake_id', 'access_type': 'ip', @@ -468,8 +473,8 @@ class ShareSnapshotAPITest(test.TestCase): mock.Mock(return_value=share)) body = {'allow_access': access} - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.allow_access, req, @@ -490,8 +495,8 @@ class ShareSnapshotAPITest(test.TestCase): 'access_to': ''} body = {'allow_access': access} - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.allow_access, req, @@ -513,8 +518,8 @@ class ShareSnapshotAPITest(test.TestCase): deny_access = self.mock_object(share_api.API, 'snapshot_deny_access') body = {'deny_access': {'access_id': access.id}} - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') resp = self.controller.deny_access(req, snapshot['id'], body) @@ -533,8 +538,8 @@ class ShareSnapshotAPITest(test.TestCase): share = db_utils.create_share(mount_snapshot_support=True) snapshot = db_utils.create_snapshot( status=constants.STATUS_AVAILABLE, share_id=share['id']) - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') body = {} self.assertRaises(webob.exc.HTTPBadRequest, @@ -561,8 +566,8 @@ class ShareSnapshotAPITest(test.TestCase): mock.Mock(return_value=wrong_access)) body = {'deny_access': {'access_id': access.id}} - req = fakes.HTTPRequest.blank('/snapshots/%s/action' % snapshot['id'], - version='2.32') + req = fakes.HTTPRequest.blank( + '/v2/fake/snapshots/%s/action' % snapshot['id'], version='2.32') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.deny_access, req, snapshot['id'], @@ -588,11 +593,11 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase): self.resource_name = self.controller.resource_name self.manage_request = fakes.HTTPRequest.blank( - '/snapshots/manage', use_admin_context=True, + '/v2/fake/snapshots/manage', use_admin_context=True, version=MIN_MANAGE_SNAPSHOT_API_VERSION) self.snapshot_id = 'fake' self.unmanage_request = fakes.HTTPRequest.blank( - '/snapshots/%s/unmanage' % self.snapshot_id, + '/v2/fake/snapshots/%s/unmanage' % self.snapshot_id, use_admin_context=True, version=MIN_MANAGE_SNAPSHOT_API_VERSION) @@ -734,8 +739,9 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase): 'display_description': 'bar', } - req = fakes.HTTPRequest.blank( - '/snapshots/manage', use_admin_context=True, version=version) + req = fakes.HTTPRequest.blank('/v2/fake/snapshots/manage', + use_admin_context=True, + version=version) actual_result = self.controller.manage(req, data) @@ -793,7 +799,7 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase): share_id='fake', provider_location='fake_volume_snapshot_id', driver_options={}) fake_req = fakes.HTTPRequest.blank( - '/snapshots/manage', use_admin_context=True, + '/v2/fake/snapshots/manage', use_admin_context=True, version=version) self.assertRaises(exception.VersionNotFoundForAPIMethod, @@ -804,10 +810,9 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase): body = {} snapshot = {'status': constants.STATUS_AVAILABLE, 'id': 'bar_id', 'share_id': 'bar_id'} - fake_req = fakes.HTTPRequest.blank( - '/snapshots/unmanage', - use_admin_context=True, - version='2.49') + fake_req = fakes.HTTPRequest.blank('/v2/fake/snapshots/unmanage', + use_admin_context=True, + version='2.49') mock_unmanage = self.mock_object(self.controller, '_unmanage') self.controller.unmanage(fake_req, snapshot['id'], body) @@ -948,7 +953,7 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase): def test_unmanage_version_not_found(self, version): snapshot_id = 'fake' fake_req = fakes.HTTPRequest.blank( - '/snapshots/%s/unmanage' % snapshot_id, + '/v2/fake/snapshots/%s/unmanage' % snapshot_id, use_admin_context=True, version=version) diff --git a/manila/tests/api/v2/test_shares.py b/manila/tests/api/v2/test_shares.py index 0d66d290a7..6c5df23059 100644 --- a/manila/tests/api/v2/test_shares.py +++ b/manila/tests/api/v2/test_shares.py @@ -165,11 +165,11 @@ class ShareAPITest(test.TestCase): 'share_type_name': None, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v2/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -205,8 +205,9 @@ class ShareAPITest(test.TestCase): snapshot = copy.deepcopy(self.snapshot) snapshot['status'] = constants.STATUS_AVAILABLE body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') mock_validate_revert_parameters = self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -243,8 +244,9 @@ class ShareAPITest(test.TestCase): snapshot['status'] = constants.STATUS_AVAILABLE snapshot['share_id'] = 'wrong_id' body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -268,8 +270,9 @@ class ShareAPITest(test.TestCase): snapshot['status'] = constants.STATUS_AVAILABLE snapshot['share_id'] = 'wrong_id' body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -309,8 +312,9 @@ class ShareAPITest(test.TestCase): snapshot = copy.deepcopy(self.snapshot) snapshot['status'] = snapshot_status body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -333,8 +337,9 @@ class ShareAPITest(test.TestCase): snapshot = copy.deepcopy(self.snapshot) snapshot['status'] = constants.STATUS_AVAILABLE body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -366,8 +371,9 @@ class ShareAPITest(test.TestCase): snapshot = copy.deepcopy(self.snapshot) snapshot['status'] = constants.STATUS_AVAILABLE body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -396,8 +402,9 @@ class ShareAPITest(test.TestCase): latest_snapshot['status'] = constants.STATUS_AVAILABLE latest_snapshot['id'] = '3' body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -442,8 +449,9 @@ class ShareAPITest(test.TestCase): def test__revert_exception(self, caught, exc_args, thrown): body = {'revert': {'snapshot_id': '2'}} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.27') self.mock_object( self.controller, '_validate_revert_parameters', mock.Mock(return_value=body['revert'])) @@ -483,7 +491,7 @@ class ShareAPITest(test.TestCase): def test_share_create_original(self, microversion): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/v2/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -495,7 +503,7 @@ class ShareAPITest(test.TestCase): def test_share_create_with_snapshot_support_without_cg(self, microversion): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/v2/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -506,7 +514,7 @@ class ShareAPITest(test.TestCase): def test_share_create_with_share_group(self): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version="2.31", + req = fakes.HTTPRequest.blank('/v2/fake/shares', version="2.31", experimental=True) res_dict = self.controller.create(req, body) @@ -532,7 +540,7 @@ class ShareAPITest(test.TestCase): "share_group_id": sg_id, }} req = fakes.HTTPRequest.blank( - '/shares', version="2.31", experimental=True) + '/v2/fake/shares', version="2.31", experimental=True) self.controller.create(req, body) @@ -570,7 +578,7 @@ class ShareAPITest(test.TestCase): "share_group_id": sg_id, }} req = fakes.HTTPRequest.blank( - '/shares', version="2.31", experimental=True) + '/v2/fake/shares', version="2.31", experimental=True) self.assertRaises( exception.InvalidInput, self.controller.create, req, body) @@ -595,7 +603,7 @@ class ShareAPITest(test.TestCase): "share_group_id": sg_id, }} req = fakes.HTTPRequest.blank( - '/shares', version="2.31", experimental=True) + '/v2/fake/shares', version="2.31", experimental=True) self.assertRaises( webob.exc.HTTPNotFound, self.controller.create, req, body) @@ -612,7 +620,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') res_dict = self.controller.create(req, body) expected = self._get_expected_share_detailed_response(self.share, @@ -628,7 +636,7 @@ class ShareAPITest(test.TestCase): self.vt['name'])), ) CONF.set_default("default_share_type", self.vt['name']) - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') self.assertRaises(exception.ShareTypeNotFoundByName, self.controller.create, req, {'share': self.share}) share_types.get_default_share_type.assert_called_once_with() @@ -638,7 +646,8 @@ class ShareAPITest(test.TestCase): body = {"share": copy.deepcopy(self.share)} req = fakes.HTTPRequest.blank( - '/shares', version=share_replicas.MIN_SUPPORTED_API_VERSION) + '/v2/fake/shares', + version=share_replicas.MIN_SUPPORTED_API_VERSION) res_dict = self.controller.create(req, body) @@ -670,7 +679,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') res_dict = self.controller.create(req, body) expected = self._get_expected_share_detailed_response( @@ -684,7 +693,7 @@ class ShareAPITest(test.TestCase): def test_share_create_original_with_user_id(self, microversion): self.mock_object(share_api.API, 'create', self.create_mock) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version=microversion) + req = fakes.HTTPRequest.blank('/v2/fake/shares', version=microversion) res_dict = self.controller.create(req, body) @@ -693,10 +702,10 @@ class ShareAPITest(test.TestCase): self.assertEqual(expected, res_dict) - @ddt.data(test_utils.annotated('v2.0_az_unsupported', ('2.0', False)), - test_utils.annotated('v2.0_az_supported', ('2.0', True)), - test_utils.annotated('v2.47_az_unsupported', ('2.47', False)), - test_utils.annotated('v2.47_az_supported', ('2.47', True))) + @ddt.data(test_utils.annotated('/v2.0_az_unsupported', ('2.0', False)), + test_utils.annotated('/v2.0_az_supported', ('2.0', True)), + test_utils.annotated('/v2.47_az_unsupported', ('2.47', False)), + test_utils.annotated('/v2.47_az_supported', ('2.47', True))) @ddt.unpack def test_share_create_with_share_type_azs(self, version, az_supported): """For API version<2.48, AZ validation should not be performed.""" @@ -709,7 +718,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_types, 'get_share_type', mock.Mock( return_value=stype_with_azs)) - req = fakes.HTTPRequest.blank('/shares', version=version) + req = fakes.HTTPRequest.blank('/v2/fake/shares', version=version) res_dict = self.controller.create(req, {'share': create_args}) @@ -742,7 +751,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_api.API, 'get_snapshot', stubs.stub_snapshot_get) - req = fakes.HTTPRequest.blank('/shares', version=version) + req = fakes.HTTPRequest.blank('/v2/fake/shares', version=version) self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, @@ -753,8 +762,10 @@ class ShareAPITest(test.TestCase): share = db_utils.create_share() share_network = db_utils.create_share_network() share_type = {'share_type_id': 'fake_type_id'} - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -797,8 +808,8 @@ class ShareAPITest(test.TestCase): def test_migration_start_conflict(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True) + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], use_admin_context=True) req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request = api_version.APIVersionRequest('2.29') @@ -825,9 +836,10 @@ class ShareAPITest(test.TestCase): 'preserve_snapshots', 'host', 'body') def test_migration_start_missing_mandatory(self, param): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, - version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -861,9 +873,10 @@ class ShareAPITest(test.TestCase): 'preserve_snapshots', 'force_host_assisted_migration') def test_migration_start_non_boolean(self, param): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, - version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -891,7 +904,7 @@ class ShareAPITest(test.TestCase): req, 'fake_id', body) def test_migration_start_no_share_id(self): - req = fakes.HTTPRequest.blank('/shares/%s/action' % 'fake_id', + req = fakes.HTTPRequest.blank('/v2/fake/shares/%s/action' % 'fake_id', use_admin_context=True, version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' @@ -908,8 +921,10 @@ class ShareAPITest(test.TestCase): def test_migration_start_new_share_network_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') context = req.environ['manila.context'] req.method = 'POST' req.headers['content-type'] = 'application/json' @@ -933,8 +948,10 @@ class ShareAPITest(test.TestCase): def test_migration_start_new_share_type_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') context = req.environ['manila.context'] req.method = 'POST' req.headers['content-type'] = 'application/json' @@ -958,8 +975,10 @@ class ShareAPITest(test.TestCase): def test_migration_start_invalid_force_host_assisted_migration(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -976,8 +995,10 @@ class ShareAPITest(test.TestCase): def test_migration_start_invalid_writable_preserve_metadata( self, parameter): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.29') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.29') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -992,8 +1013,10 @@ class ShareAPITest(test.TestCase): @ddt.data(constants.TASK_STATE_MIGRATION_ERROR, None) def test_reset_task_state(self, task_state): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1012,8 +1035,10 @@ class ShareAPITest(test.TestCase): def test_reset_task_state_error_body(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1027,8 +1052,10 @@ class ShareAPITest(test.TestCase): def test_reset_task_state_error_invalid(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1042,8 +1069,10 @@ class ShareAPITest(test.TestCase): def test_reset_task_state_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1063,8 +1092,10 @@ class ShareAPITest(test.TestCase): def test_migration_complete(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1085,8 +1116,10 @@ class ShareAPITest(test.TestCase): def test_migration_complete_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1103,8 +1136,10 @@ class ShareAPITest(test.TestCase): def test_migration_cancel(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1125,8 +1160,10 @@ class ShareAPITest(test.TestCase): def test_migration_cancel_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1144,8 +1181,10 @@ class ShareAPITest(test.TestCase): def test_migration_get_progress(self): share = db_utils.create_share( task_state=constants.TASK_STATE_MIGRATION_SUCCESS) - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1172,8 +1211,10 @@ class ShareAPITest(test.TestCase): def test_migration_get_progress_not_found(self): share = db_utils.create_share() - req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'], - use_admin_context=True, version='2.22') + req = fakes.HTTPRequest.blank( + '/v2/fake/shares/%s/action' % share['id'], + use_admin_context=True, + version='2.22') req.method = 'POST' req.headers['content-type'] = 'application/json' req.api_version_request.experimental = True @@ -1209,7 +1250,7 @@ class ShareAPITest(test.TestCase): share_network_id=shr['share_network_id']))) self.mock_object(share_api.API, 'create', create_mock) body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') res_dict = self.controller.create(req, body) @@ -1251,7 +1292,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') res_dict = self.controller.create(req, body) @@ -1296,7 +1337,7 @@ class ShareAPITest(test.TestCase): db, 'share_network_subnet_get_by_availability_zone_id') body = {"share": copy.deepcopy(shr)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') res_dict = self.controller.create(req, body) expected = self._get_expected_share_detailed_response( shr, version='2.7') @@ -1317,7 +1358,7 @@ class ShareAPITest(test.TestCase): "share_network_id": 1234, } body = {"share": shr} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/fake/shares', version='2.7') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.create, req, body) @@ -1370,14 +1411,14 @@ class ShareAPITest(test.TestCase): ) body = {"share": copy.deepcopy(self.share)} - req = fakes.HTTPRequest.blank('/shares', version='2.7') + req = fakes.HTTPRequest.blank('/v2/shares', version='2.7') self.assertRaises(webob.exc.HTTPNotFound, self.controller.create, req, body) def test_share_show(self): - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') expected = self._get_expected_share_detailed_response() res_dict = self.controller.show(req, '1') @@ -1386,7 +1427,7 @@ class ShareAPITest(test.TestCase): def test_share_show_with_share_group(self): req = fakes.HTTPRequest.blank( - '/shares/1', version='2.31', experimental=True) + '/v2/fake/shares/1', version='2.31', experimental=True) expected = self._get_expected_share_detailed_response(version='2.31') res_dict = self.controller.show(req, '1') @@ -1395,7 +1436,7 @@ class ShareAPITest(test.TestCase): def test_share_show_with_share_group_earlier_version(self): req = fakes.HTTPRequest.blank( - '/shares/1', version='2.23', experimental=True) + '/v2/fake/shares/1', version='2.23', experimental=True) expected = self._get_expected_share_detailed_response(version='2.23') res_dict = self.controller.show(req, '1') @@ -1403,7 +1444,7 @@ class ShareAPITest(test.TestCase): self.assertDictMatch(expected, res_dict) def test_share_show_with_share_type_name(self): - req = fakes.HTTPRequest.blank('/shares/1', version='2.6') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1', version='2.6') res_dict = self.controller.show(req, '1') @@ -1412,7 +1453,8 @@ class ShareAPITest(test.TestCase): @ddt.data("2.15", "2.16") def test_share_show_with_user_id(self, microversion): - req = fakes.HTTPRequest.blank('/shares/1', version=microversion) + req = fakes.HTTPRequest.blank('/v2/fake/shares/1', + version=microversion) res_dict = self.controller.show(req, '1') @@ -1422,7 +1464,8 @@ class ShareAPITest(test.TestCase): self.assertEqual(expected, res_dict) def test_share_show_admin(self): - req = fakes.HTTPRequest.blank('/shares/1', use_admin_context=True) + req = fakes.HTTPRequest.blank('/v2/fake/shares/1', + use_admin_context=True) expected = self._get_expected_share_detailed_response(admin=True) res_dict = self.controller.show(req, '1') @@ -1432,18 +1475,17 @@ class ShareAPITest(test.TestCase): def test_share_show_no_share(self): self.mock_object(share_api.API, 'get', stubs.stub_share_get_notfound) - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') self.assertRaises(webob.exc.HTTPNotFound, self.controller.show, req, '1') def test_share_show_with_replication_type(self): - req = fakes.HTTPRequest.blank( - '/shares/1', version=share_replicas.MIN_SUPPORTED_API_VERSION) + api_vers = share_replicas.MIN_SUPPORTED_API_VERSION + req = fakes.HTTPRequest.blank('/v2/fake/shares/1', version=api_vers) res_dict = self.controller.show(req, '1') - expected = self._get_expected_share_detailed_response( - version=share_replicas.MIN_SUPPORTED_API_VERSION) + expected = self._get_expected_share_detailed_response(version=api_vers) self.assertEqual(expected, res_dict) @@ -1456,7 +1498,7 @@ class ShareAPITest(test.TestCase): status=constants.STATUS_AVAILABLE) self.mock_object(share_api.API, 'get', mock.Mock(return_value=share)) req = fakes.HTTPRequest.blank( - '/shares/%s' % share['id'], version=version) + '/v2/fake/shares/%s' % share['id'], version=version) res_dict = self.controller.show(req, share['id']) @@ -1466,12 +1508,12 @@ class ShareAPITest(test.TestCase): self.assertEqual(expected, res_dict['share']['access_rules_status']) def test_share_delete(self): - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') resp = self.controller.delete(req, 1) self.assertEqual(202, resp.status_int) def test_share_delete_has_replicas(self): - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') self.mock_object(share_api.API, 'get', mock.Mock(return_value=self.share)) self.mock_object(share_api.API, 'delete', @@ -1485,7 +1527,7 @@ class ShareAPITest(test.TestCase): share_group_id='fake_group_id') self.mock_object(share_api.API, 'get', mock.Mock(return_value=fake_share)) - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete, req, 1) @@ -1495,7 +1537,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_api.API, 'get', mock.Mock(return_value=fake_share)) req = fakes.HTTPRequest.blank( - '/shares/1?share_group_id=fake_group_id') + '/v2/fake/shares/1?share_group_id=fake_group_id') resp = self.controller.delete(req, 1) self.assertEqual(202, resp.status_int) @@ -1505,7 +1547,7 @@ class ShareAPITest(test.TestCase): self.mock_object(share_api.API, 'get', mock.Mock(return_value=fake_share)) req = fakes.HTTPRequest.blank( - '/shares/1?share_group_id=not_fake_group_id') + '/v2/fake/shares/1?share_group_id=not_fake_group_id') self.assertRaises(webob.exc.HTTPBadRequest, self.controller.delete, req, 1) @@ -1513,7 +1555,7 @@ class ShareAPITest(test.TestCase): shr = self.share body = {"share": shr} - req = fakes.HTTPRequest.blank('/share/1') + req = fakes.HTTPRequest.blank('/v2/fake/share/1') res_dict = self.controller.update(req, 1, body) self.assertEqual(shr["display_name"], res_dict['share']["name"]) self.assertEqual(shr["display_description"], @@ -1526,7 +1568,7 @@ class ShareAPITest(test.TestCase): body = {"share": shr} req = fakes.HTTPRequest.blank( - '/share/1', version="2.31", experimental=True) + '/v2/fake/share/1', version="2.31", experimental=True) res_dict = self.controller.update(req, 1, body) @@ -1535,14 +1577,14 @@ class ShareAPITest(test.TestCase): res_dict['share']["source_share_group_snapshot_member_id"]) def test_share_not_updates_size(self): - req = fakes.HTTPRequest.blank('/share/1') + req = fakes.HTTPRequest.blank('/v2/fake/share/1') res_dict = self.controller.update(req, 1, {"share": self.share}) self.assertNotEqual(res_dict['share']["size"], self.share["size"]) def test_share_delete_no_share(self): self.mock_object(share_api.API, 'get', stubs.stub_share_get_notfound) - req = fakes.HTTPRequest.blank('/shares/1') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1') self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete, req, @@ -1587,7 +1629,7 @@ class ShareAPITest(test.TestCase): if use_admin_context: search_opts['host'] = 'fake_host' # fake_key should be filtered for non-admin - url = '/shares?fake_key=fake_value' + url = '/v2/fake/shares?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, version=version, @@ -1659,7 +1701,7 @@ class ShareAPITest(test.TestCase): if use_admin_context: search_opts['host'] = 'fake_host' # fake_key should be filtered - url = '/shares?fake_key=fake_value' + url = '/v2/fake/shares?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, version=version, @@ -1687,7 +1729,7 @@ class ShareAPITest(test.TestCase): def test_share_list_summary(self): self.mock_object(share_api.API, 'get_all', stubs.stub_share_get_all_by_project) - req = fakes.HTTPRequest.blank('/shares') + req = fakes.HTTPRequest.blank('/v2/fake/shares') res_dict = self.controller.index(req) expected = { 'shares': [ @@ -1696,11 +1738,11 @@ class ShareAPITest(test.TestCase): 'id': '1', 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v2/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -1741,7 +1783,7 @@ class ShareAPITest(test.TestCase): if use_admin_context: search_opts['host'] = 'fake_host' # fake_key should be filtered for non-admin - url = '/shares/detail?fake_key=fake_value' + url = '/v2/fake/shares/detail?fake_key=fake_value' for k, v in search_opts.items(): url = url + '&' + k + '=' + v req = fakes.HTTPRequest.blank(url, version=version, @@ -1844,11 +1886,11 @@ class ShareAPITest(test.TestCase): 'is_public': False, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v2/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -1867,15 +1909,17 @@ class ShareAPITest(test.TestCase): def test_share_list_detail(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env) + req = fakes.HTTPRequest.blank('/v2/fake/shares/detail', environ=env) expected = self._list_detail_common_expected() expected['shares'][0].pop('snapshot_support') self._list_detail_test_common(req, expected) def test_share_list_detail_with_share_group(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank( - '/shares/detail', environ=env, version="2.31", experimental=True) + req = fakes.HTTPRequest.blank('/v2/fake/shares/detail', + environ=env, + version="2.31", + experimental=True) expected = self._list_detail_common_expected() expected['shares'][0]['task_state'] = None expected['shares'][0]['share_type_name'] = None @@ -1893,7 +1937,7 @@ class ShareAPITest(test.TestCase): def test_share_list_detail_with_task_state(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env, + req = fakes.HTTPRequest.blank('/v2/fake/shares/detail', environ=env, version="2.5") expected = self._list_detail_common_expected() expected['shares'][0]['task_state'] = None @@ -1901,7 +1945,7 @@ class ShareAPITest(test.TestCase): def test_share_list_detail_without_export_locations(self): env = {'QUERY_STRING': 'name=Share+Test+Name'} - req = fakes.HTTPRequest.blank('/shares/detail', environ=env, + req = fakes.HTTPRequest.blank('/v2/fake/shares/detail', environ=env, version="2.9") expected = self._list_detail_common_expected() expected['shares'][0]['task_state'] = None @@ -1915,7 +1959,7 @@ class ShareAPITest(test.TestCase): stubs.stub_share_get_all_by_project) env = {'QUERY_STRING': 'name=Share+Test+Name'} req = fakes.HTTPRequest.blank( - '/shares/detail', environ=env, + '/v2/fake/shares/detail', environ=env, version=share_replicas.MIN_SUPPORTED_API_VERSION) res_dict = self.controller.detail(req) expected = { @@ -1944,11 +1988,11 @@ class ShareAPITest(test.TestCase): 'task_state': None, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/1', + 'href': 'http://localhost/share/v2/fake/shares/1', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/1', + 'href': 'http://localhost/share/fake/shares/1', 'rel': 'bookmark' } ], @@ -2292,7 +2336,7 @@ class ShareActionsTest(test.TestCase): id = 'fake_share_id' body = {"os-deny_access": {"access_id": 'fake_acces_id'}} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id) res = self.controller._deny_access(req, id, body) self.assertEqual(202, res.status_int) @@ -2305,7 +2349,7 @@ class ShareActionsTest(test.TestCase): id = 'super_fake_share_id' body = {"os-deny_access": {"access_id": 'fake_acces_id'}} - req = fakes.HTTPRequest.blank('/v1/tenant1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/tenant1/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPNotFound, self.controller._deny_access, req, @@ -2357,7 +2401,7 @@ class ShareActionsTest(test.TestCase): {"os-extend": {"new_size": {'foo': 'bar'}}}) def test_extend_invalid_body(self, body): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPBadRequest, self.controller._extend, req, id, body) @@ -2371,7 +2415,7 @@ class ShareActionsTest(test.TestCase): @ddt.unpack def test_extend_exception(self, source, target): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/shares/%s/action' % id) body = {"os-extend": {'new_size': '123'}} self.mock_object(share_api.API, "extend", mock.Mock(side_effect=source('fake'))) @@ -2404,7 +2448,7 @@ class ShareActionsTest(test.TestCase): {"os-shrink": {"new_size": {'foo': 'bar'}}}) def test_shrink_invalid_body(self, body): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/shares/%s/action' % id) self.assertRaises(webob.exc.HTTPBadRequest, self.controller._shrink, req, id, body) @@ -2416,7 +2460,7 @@ class ShareActionsTest(test.TestCase): @ddt.unpack def test_shrink_exception(self, source, target): id = 'fake_share_id' - req = fakes.HTTPRequest.blank('/v1/shares/%s/action' % id) + req = fakes.HTTPRequest.blank('/v2/shares/%s/action' % id) body = {"os-shrink": {'new_size': '123'}} self.mock_object(share_api.API, "shrink", mock.Mock(side_effect=source('fake'))) @@ -2561,7 +2605,7 @@ class ShareUnmanageTest(test.TestCase): stubs.stub_snapshot_get) self.share_id = 'fake' self.request = fakes.HTTPRequest.blank( - '/share/%s/unmanage' % self.share_id, + '/v2/fake/share/%s/unmanage' % self.share_id, use_admin_context=True, version='2.7', ) @@ -2587,8 +2631,9 @@ class ShareUnmanageTest(test.TestCase): def test__unmanage(self): body = {} - req = fakes.HTTPRequest.blank( - '/shares/1/action', use_admin_context=False, version='2.49') + req = fakes.HTTPRequest.blank('/v2/fake/shares/1/action', + use_admin_context=False, + version='2.49') share = dict(status=constants.STATUS_AVAILABLE, id='foo_id', instance={}) mock_unmanage = self.mock_object(self.controller, '_unmanage') @@ -2673,7 +2718,7 @@ class ShareUnmanageTest(test.TestCase): def test_wrong_permissions(self): share_id = 'fake' - req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id, + req = fakes.HTTPRequest.blank('/v2/fake/share/%s/unmanage' % share_id, use_admin_context=False, version='2.7') self.assertRaises(webob.exc.HTTPForbidden, @@ -2683,7 +2728,7 @@ class ShareUnmanageTest(test.TestCase): def test_unsupported_version(self): share_id = 'fake' - req = fakes.HTTPRequest.blank('/share/%s/unmanage' % share_id, + req = fakes.HTTPRequest.blank('/v2/fake/share/%s/unmanage' % share_id, use_admin_context=False, version='2.6') self.assertRaises(exception.VersionNotFoundForAPIMethod, @@ -2867,11 +2912,11 @@ class ShareManageTest(test.TestCase): 'task_state': None, 'links': [ { - 'href': 'http://localhost/v1/fake/shares/fake', + 'href': 'http://localhost/share/v2/fake/shares/fake', 'rel': 'self' }, { - 'href': 'http://localhost/fake/shares/fake', + 'href': 'http://localhost/share/fake/shares/fake', 'rel': 'bookmark' } ], @@ -2923,7 +2968,8 @@ class ShareManageTest(test.TestCase): api_version.APIVersionRequest('2.8')): share['is_public'] = data['share']['is_public'] - req = fakes.HTTPRequest.blank('/v2/shares/manage', version=version, + req = fakes.HTTPRequest.blank('/v2/fake/shares/manage', + version=version, use_admin_context=True) actual_result = self.controller.manage(req, data) @@ -2942,15 +2988,16 @@ class ShareManageTest(test.TestCase): self.assertRaises( webob.exc.HTTPForbidden, self.controller.manage, - fakes.HTTPRequest.blank( - '/share/manage', use_admin_context=False, version='2.7'), + fakes.HTTPRequest.blank('/v2/fake/share/manage', + use_admin_context=False, + version='2.7'), body, ) def test_unsupported_version(self): share_id = 'fake' req = fakes.HTTPRequest.blank( - '/share/manage', use_admin_context=False, version='2.6') + '/v2/fake/share/manage', use_admin_context=False, version='2.6') self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.manage, @@ -2962,8 +3009,9 @@ class ShareManageTest(test.TestCase): mock_revert = self.mock_object( self.controller, '_revert', mock.Mock(return_value='fake_response')) - req = fakes.HTTPRequest.blank( - '/shares/fake_id/action', use_admin_context=False, version='2.27') + req = fakes.HTTPRequest.blank('/v2/fake/shares/fake_id/action', + use_admin_context=False, + version='2.27') result = self.controller.revert(req, 'fake_id', 'fake_body') @@ -2973,8 +3021,9 @@ class ShareManageTest(test.TestCase): def test_revert_unsupported(self): - req = fakes.HTTPRequest.blank( - '/shares/fake_id/action', use_admin_context=False, version='2.24') + req = fakes.HTTPRequest.blank('/v2/shares/fake_id/action', + use_admin_context=False, + version='2.24') self.assertRaises(exception.VersionNotFoundForAPIMethod, self.controller.revert, diff --git a/manila/tests/conf_fixture.py b/manila/tests/conf_fixture.py index f4d0316ad7..61f3506446 100644 --- a/manila/tests/conf_fixture.py +++ b/manila/tests/conf_fixture.py @@ -41,6 +41,8 @@ def set_defaults(conf): 'etc/manila/api-paste.ini')) wsgi.register_opts(conf) _safe_set_of_opts(conf, 'api_paste_config', _API_PASTE_PATH) + # we use "fake" and "openstack" as project ID in a number of tests + _safe_set_of_opts(conf, 'project_id_regex', r"[0-9a-fopnstk\-]+") _safe_set_of_opts(conf, 'share_driver', 'manila.tests.fake_driver.FakeShareDriver') _safe_set_of_opts(conf, 'auth_strategy', 'noauth') diff --git a/manila/tests/fake_share.py b/manila/tests/fake_share.py index 6277e05e41..e1140f2773 100644 --- a/manila/tests/fake_share.py +++ b/manila/tests/fake_share.py @@ -175,8 +175,10 @@ def fake_snapshot_instance(base_snapshot=None, as_primitive=False, **kwargs): def expected_snapshot(version=None, id='fake_snapshot_id', **kwargs): - self_link = 'http://localhost/v1/fake/snapshots/%s' % id - bookmark_link = 'http://localhost/fake/snapshots/%s' % id + api_major_version = 'v2' if version and version.startswith('2.') else 'v1' + self_link = 'http://localhost/share/%s/fake/snapshots/%s' % ( + api_major_version, id) + bookmark_link = 'http://localhost/share/fake/snapshots/%s' % id snapshot = { 'id': id, 'share_id': 'fakeshareid', diff --git a/manila/tests/integrated/api/client.py b/manila/tests/integrated/api/client.py index d7fee8e6e4..e85039748f 100644 --- a/manila/tests/integrated/api/client.py +++ b/manila/tests/integrated/api/client.py @@ -71,12 +71,12 @@ class TestOpenStackClient(object): """ - def __init__(self, auth_user, auth_key, www_authenticate_uri): + def __init__(self, auth_user, auth_key, endpoint): super(TestOpenStackClient, self).__init__() self.auth_result = None self.auth_user = auth_user self.auth_key = auth_key - self.www_authenticate_uri = www_authenticate_uri + self.endpoint = endpoint # default project_id self.project_id = 'openstack' @@ -114,16 +114,15 @@ class TestOpenStackClient(object): if self.auth_result: return self.auth_result - www_authenticate_uri = self.www_authenticate_uri headers = {'X-Auth-User': self.auth_user, 'X-Auth-Key': self.auth_key, 'X-Auth-Project-Id': self.project_id} - response = self.request(www_authenticate_uri, + response = self.request(self.endpoint, headers=headers) http_status = response.status - LOG.debug("%(www_authenticate_uri)s => code %(http_status)s.", - {"www_authenticate_uri": www_authenticate_uri, + LOG.debug("%(endpoint)s => code %(http_status)s.", + {"endpoint": self.endpoint, "http_status": http_status}) if http_status == 401: diff --git a/manila/tests/integrated/integrated_helpers.py b/manila/tests/integrated/integrated_helpers.py index 45ba15c4ca..a956ac3d52 100644 --- a/manila/tests/integrated/integrated_helpers.py +++ b/manila/tests/integrated/integrated_helpers.py @@ -65,12 +65,12 @@ class _IntegratedTestBase(test.TestCase): self.flags(**f) # set up services - self.volume = self.start_service('share') + self.share = self.start_service('share') self.scheduler = self.start_service('scheduler') self._start_api_service() - self.api = client.TestOpenStackClient('fake', 'fake', self.auth_url) + self.api = client.TestOpenStackClient('fake', 'fake', self.endpoint) def tearDown(self): self.osapi.stop() @@ -79,10 +79,9 @@ class _IntegratedTestBase(test.TestCase): def _start_api_service(self): self.osapi = service.WSGIService("osapi_share") self.osapi.start() - # FIXME(ja): this is not the auth url - this is the service url - # FIXME(ja): this needs fixed in nova as well - self.auth_url = 'http://%s:%s/v1' % (self.osapi.host, self.osapi.port) - LOG.warning(self.auth_url) + self.endpoint = 'http://%s:%s/v2' % (self.osapi.host, + self.osapi.port) + LOG.info("Manila API started at %s", self.endpoint) def _get_flags(self): """An opportunity to setup flags, before the services are started.""" diff --git a/releasenotes/notes/bp-remove-project-id-from-urls-9f338371b8ffa203.yaml b/releasenotes/notes/bp-remove-project-id-from-urls-9f338371b8ffa203.yaml new file mode 100644 index 0000000000..9c91ffc7a3 --- /dev/null +++ b/releasenotes/notes/bp-remove-project-id-from-urls-9f338371b8ffa203.yaml @@ -0,0 +1,26 @@ +--- +prelude: > + Manila v2 API URLs no longer require a project_id to be specified. +features: + - | + It is now possible to omit the %{project_id}s from the API endpoints for + the v2 API. While the behavior of the APIs have not been altered, the + service recognizes URLs with and without project ids in the path. It is + recommended that you adjust the service catalog in your cloud to remove + the project_id substitution, especially if you would like to enable + users operating at system scope. + - | + A new "noauth" auth strategy is available, and is named "noauthv2". + It can be enabled by setting the configuration option + ``[DEFAULT]/auth_strategy`` to ``noauthv2``. This auth strategy can be + used when project_id substitution is removed from the manila endpoint URL. +upgrade: + - | + In order to make project_id optional in urls, the possible values of + project_id had to be constrained. A new configuration option called + ``project_id_regex`` has been added in the ``[DEFAULT]`` section. The + default value for this option is ``[0-9a-f\-]+`` and it matches hex + UUIDs with and without dashes, therefore covering the formats supported + by the OpenStack Identity service. If your cloud uses other formats, set + this configuration option accordingly, or remove project_id from the + manila endpoint URL in your service catalog.