From 4acc4a9757af6e68456aba1fea2b320b2311b971 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Fri, 5 Aug 2011 11:58:21 -0400 Subject: Pass tenant ids through on on requests --- nova/api/openstack/__init__.py | 17 ++++++++++++++++- nova/api/openstack/wsgi.py | 3 +++ 2 files changed, 19 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 9ab8aeb58..9475f961c 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -65,6 +65,15 @@ class FaultWrapper(base_wsgi.Middleware): return faults.Fault(exc) +class TenantMapper(routes.Mapper): + + def resource(self, member_name, collection_name, **kwargs): + routes.Mapper.resource(self, member_name, + collection_name, + path_prefix='{tenant_id}/', + **kwargs) + + class APIRouter(base_wsgi.Router): """ Routes requests on the OpenStack API to the appropriate controller @@ -168,6 +177,12 @@ class APIRouterV10(APIRouter): class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" + def __init__(self, ext_mgr=None): + mapper = TenantMapper() + self.server_members = {} + self._setup_routes(mapper) + super(APIRouter, self).__init__(mapper) + def _setup_routes(self, mapper): super(APIRouterV11, self)._setup_routes(mapper, '1.1') image_metadata_controller = image_metadata.create_resource() @@ -176,7 +191,7 @@ class APIRouterV11(APIRouter): parent_resource=dict(member_name='image', collection_name='images')) - mapper.connect("metadata", "/images/{image_id}/metadata", + mapper.connect("metadata", "{tenant_id}/images/{image_id}/metadata", controller=image_metadata_controller, action='update_all', conditions={"method": ['PUT']}) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 0eb47044e..7c22ed57a 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -486,6 +486,9 @@ class Resource(wsgi.Application): msg = _("Malformed request body") return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) + #Remove tenant id + args.pop("tenant_id") + try: action_result = self.dispatch(request, action, args) except webob.exc.HTTPException as ex: -- cgit From fe4c7ca6f21f367b3f6ca1a536fdcd550f301fba Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 8 Aug 2011 12:57:38 -0400 Subject: Assign tenant id in nova.context --- nova/api/openstack/wsgi.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 7c22ed57a..bf5697b7e 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -486,8 +486,8 @@ class Resource(wsgi.Application): msg = _("Malformed request body") return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) - #Remove tenant id - args.pop("tenant_id") + if 'tenant_id' in args: + request['nova.context']['tenant_id'] = args.pop("tenant_id") try: action_result = self.dispatch(request, action, args) -- cgit From b2b5131ac2ab532afb1a3e507992d60b15dd3855 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 8 Aug 2011 13:34:20 -0400 Subject: fixed wrong syntax --- nova/api/openstack/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index bf5697b7e..d834a62d8 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -487,7 +487,7 @@ class Resource(wsgi.Application): return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) if 'tenant_id' in args: - request['nova.context']['tenant_id'] = args.pop("tenant_id") + request.environ['nova.context']['tenant_id'] = args.pop("tenant_id") try: action_result = self.dispatch(request, action, args) -- cgit From 6107aeceab2f3226bb1f3bff820cdcc2bc9be3cc Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 8 Aug 2011 13:50:31 -0400 Subject: Don't do anything with tenant_id for now --- nova/api/openstack/wsgi.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index d834a62d8..34c31260b 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -487,7 +487,7 @@ class Resource(wsgi.Application): return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) if 'tenant_id' in args: - request.environ['nova.context']['tenant_id'] = args.pop("tenant_id") + args.pop("tenant_id") try: action_result = self.dispatch(request, action, args) -- cgit From d4d2227cd396455c881f2ed36008578b2d4a7720 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 9 Aug 2011 10:29:56 -0400 Subject: Updated TenantMapper to handle resources with parent resources --- nova/api/openstack/__init__.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 9475f961c..3e241cd91 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -68,9 +68,16 @@ class FaultWrapper(base_wsgi.Middleware): class TenantMapper(routes.Mapper): def resource(self, member_name, collection_name, **kwargs): + if not ('parent_resource' in kwargs): + kwargs['path_prefix'] = '{tenant_id}/' + else: + parent_resource = kwargs['parent_resource'] + p_collection = parent_resource['collection_name'] + p_member = parent_resource['member_name'] + kwargs['path_prefix'] = '{tenant_id}/%s/:%s_id' % (p_collection, + p_member) routes.Mapper.resource(self, member_name, collection_name, - path_prefix='{tenant_id}/', **kwargs) -- cgit From 05cbe3032dfdfb4229718ead981c982864118f15 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Tue, 9 Aug 2011 12:51:42 -0400 Subject: Updated extensions to expect tenant ids Updated extensions tests to use tenant ids --- nova/api/openstack/extensions.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index cc889703e..f81879e3b 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -219,12 +219,13 @@ class ExtensionMiddleware(base_wsgi.Middleware): for action in ext_mgr.get_actions(): if not action.collection in action_resources.keys(): resource = ActionExtensionResource(application) - mapper.connect("/%s/:(id)/action.:(format)" % + mapper.connect("/:(tenant_id)/%s/:(id)/action.:(format)" % action.collection, action='action', controller=resource, conditions=dict(method=['POST'])) - mapper.connect("/%s/:(id)/action" % action.collection, + mapper.connect("/:(tenant_id)/%s/:(id)/action" % + action.collection, action='action', controller=resource, conditions=dict(method=['POST'])) -- cgit From a8a5b27a577f8e007e2cc79570f97ae075fda767 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Tue, 9 Aug 2011 19:26:35 -0400 Subject: adding project_id to flavor, server, and image links for /servers requests --- nova/api/openstack/servers.py | 8 +++++--- nova/api/openstack/views/flavors.py | 15 +++++++++------ nova/api/openstack/views/images.py | 16 +++++++++++----- nova/api/openstack/views/servers.py | 8 +++++--- 4 files changed, 30 insertions(+), 17 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 4f34d63c9..127962ce2 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -596,14 +596,16 @@ class ControllerV11(Controller): return common.get_id_from_href(flavor_ref) def _build_view(self, req, instance, is_detail=False): + project_id = req.environ['nova.context'].project_id base_url = req.application_url flavor_builder = nova.api.openstack.views.flavors.ViewBuilderV11( - base_url) + base_url, project_id) image_builder = nova.api.openstack.views.images.ViewBuilderV11( - base_url) + base_url, project_id) addresses_builder = nova.api.openstack.views.addresses.ViewBuilderV11() builder = nova.api.openstack.views.servers.ViewBuilderV11( - addresses_builder, flavor_builder, image_builder, base_url) + addresses_builder, flavor_builder, image_builder, + base_url, project_id) return builder.build(instance, is_detail=is_detail) diff --git a/nova/api/openstack/views/flavors.py b/nova/api/openstack/views/flavors.py index 0403ece1b..aea34b424 100644 --- a/nova/api/openstack/views/flavors.py +++ b/nova/api/openstack/views/flavors.py @@ -15,6 +15,9 @@ # License for the specific language governing permissions and limitations # under the License. +import os.path + + from nova.api.openstack import common @@ -59,11 +62,12 @@ class ViewBuilder(object): class ViewBuilderV11(ViewBuilder): """Openstack API v1.1 flavors view builder.""" - def __init__(self, base_url): + def __init__(self, base_url, project_id=""): """ :param base_url: url of the root wsgi application """ self.base_url = base_url + self.project_id = project_id def _build_extra(self, flavor_obj): flavor_obj["links"] = self._build_links(flavor_obj) @@ -88,11 +92,10 @@ class ViewBuilderV11(ViewBuilder): def generate_href(self, flavor_id): """Create an url that refers to a specific flavor id.""" - return "%s/flavors/%s" % (self.base_url, flavor_id) + return os.path.join(self.base_url, self.project_id, + "flavors", str(flavor_id)) def generate_bookmark(self, flavor_id): """Create an url that refers to a specific flavor id.""" - return "%s/flavors/%s" % ( - common.remove_version_from_href(self.base_url), - flavor_id, - ) + return os.path.join(common.remove_version_from_href(self.base_url), + self.project_id, "flavors", str(flavor_id)) diff --git a/nova/api/openstack/views/images.py b/nova/api/openstack/views/images.py index 912303d14..21f1b2d3e 100644 --- a/nova/api/openstack/views/images.py +++ b/nova/api/openstack/views/images.py @@ -23,9 +23,10 @@ from nova.api.openstack import common class ViewBuilder(object): """Base class for generating responses to OpenStack API image requests.""" - def __init__(self, base_url): + def __init__(self, base_url, project_id=""): """Initialize new `ViewBuilder`.""" - self._url = base_url + self.base_url = base_url + self.project_id = project_id def _format_dates(self, image): """Update all date fields to ensure standardized formatting.""" @@ -54,7 +55,7 @@ class ViewBuilder(object): def generate_href(self, image_id): """Return an href string pointing to this object.""" - return os.path.join(self._url, "images", str(image_id)) + return os.path.join(self.base_url, "images", str(image_id)) def build(self, image_obj, detail=False): """Return a standardized image structure for display by the API.""" @@ -117,6 +118,11 @@ class ViewBuilderV11(ViewBuilder): except KeyError: return + def generate_href(self, image_id): + """Return an href string pointing to this object.""" + return os.path.join(self.base_url, self.project_id, + "images", str(image_id)) + def build(self, image_obj, detail=False): """Return a standardized image structure for display by the API.""" image = ViewBuilder.build(self, image_obj, detail) @@ -142,5 +148,5 @@ class ViewBuilderV11(ViewBuilder): def generate_bookmark(self, image_id): """Create an url that refers to a specific flavor id.""" - return os.path.join(common.remove_version_from_href(self._url), - "images", str(image_id)) + return os.path.join(common.remove_version_from_href(self.base_url), + self.project_id, "images", str(image_id)) diff --git a/nova/api/openstack/views/servers.py b/nova/api/openstack/views/servers.py index 2873a8e0f..18c1a9057 100644 --- a/nova/api/openstack/views/servers.py +++ b/nova/api/openstack/views/servers.py @@ -142,11 +142,12 @@ class ViewBuilderV10(ViewBuilder): class ViewBuilderV11(ViewBuilder): """Model an Openstack API V1.0 server response.""" def __init__(self, addresses_builder, flavor_builder, image_builder, - base_url): + base_url, project_id=""): ViewBuilder.__init__(self, addresses_builder) self.flavor_builder = flavor_builder self.image_builder = image_builder self.base_url = base_url + self.project_id = project_id def _build_detail(self, inst): response = super(ViewBuilderV11, self)._build_detail(inst) @@ -216,9 +217,10 @@ class ViewBuilderV11(ViewBuilder): def generate_href(self, server_id): """Create an url that refers to a specific server id.""" - return os.path.join(self.base_url, "servers", str(server_id)) + return os.path.join(self.base_url, self.project_id, + "servers", str(server_id)) def generate_bookmark(self, server_id): """Create an url that refers to a specific flavor id.""" return os.path.join(common.remove_version_from_href(self.base_url), - "servers", str(server_id)) + self.project_id, "servers", str(server_id)) -- cgit From e68ace1d6f7cb6db842aae69faa89cb4679016e7 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Wed, 10 Aug 2011 01:44:15 -0400 Subject: added project_id for images requests --- nova/api/openstack/images.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index 0aabb9e56..ea4209e16 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -169,7 +169,8 @@ class ControllerV11(Controller): def get_builder(self, request): """Property to get the ViewBuilder class we need to use.""" base_url = request.application_url - return images_view.ViewBuilderV11(base_url) + project_id = request.environ['nova.context'].project_id + return images_view.ViewBuilderV11(base_url, project_id) def index(self, req): """Return an index listing of images available to the request. -- cgit From 434801e22bbfe2d8e74e18773c109ee657b22616 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Wed, 10 Aug 2011 02:01:03 -0400 Subject: added project_id for flavors requests links --- nova/api/openstack/flavors.py | 3 ++- nova/api/openstack/images.py | 6 +++--- nova/api/openstack/servers.py | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/flavors.py b/nova/api/openstack/flavors.py index b4bda68d4..fd36060da 100644 --- a/nova/api/openstack/flavors.py +++ b/nova/api/openstack/flavors.py @@ -72,7 +72,8 @@ class ControllerV11(Controller): def _get_view_builder(self, req): base_url = req.application_url - return views.flavors.ViewBuilderV11(base_url) + project_id = getattr(req.environ['nova.context'], 'project_id', '') + return views.flavors.ViewBuilderV11(base_url, project_id) class FlavorXMLSerializer(wsgi.XMLDictSerializer): diff --git a/nova/api/openstack/images.py b/nova/api/openstack/images.py index ea4209e16..1c8fc10c9 100644 --- a/nova/api/openstack/images.py +++ b/nova/api/openstack/images.py @@ -166,10 +166,10 @@ class ControllerV10(Controller): class ControllerV11(Controller): """Version 1.1 specific controller logic.""" - def get_builder(self, request): + def get_builder(self, req): """Property to get the ViewBuilder class we need to use.""" - base_url = request.application_url - project_id = request.environ['nova.context'].project_id + base_url = req.application_url + project_id = getattr(req.environ['nova.context'], 'project_id', '') return images_view.ViewBuilderV11(base_url, project_id) def index(self, req): diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index a516173d0..45d7dc214 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -639,7 +639,7 @@ class ControllerV11(Controller): return common.get_id_from_href(flavor_ref) def _build_view(self, req, instance, is_detail=False): - project_id = req.environ['nova.context'].project_id + project_id = getattr(req.environ['nova.context'], 'project_id', '') base_url = req.application_url flavor_builder = nova.api.openstack.views.flavors.ViewBuilderV11( base_url, project_id) -- cgit From caf7312a479a634ab02ccf38f53d510d20e25646 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 10 Aug 2011 11:23:40 -0400 Subject: Fixed metadata PUT routing --- nova/api/openstack/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 86169dc24..ca6c1b5f1 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -203,7 +203,7 @@ class APIRouterV11(APIRouter): parent_resource=dict(member_name='image', collection_name='images')) - mapper.connect("metadata", "{tenant_id}/images/{image_id}/metadata", + mapper.connect("metadata", "/{tenant_id}/images/{image_id}/metadata", controller=image_metadata_controller, action='update_all', conditions={"method": ['PUT']}) @@ -215,7 +215,7 @@ class APIRouterV11(APIRouter): parent_resource=dict(member_name='server', collection_name='servers')) - mapper.connect("metadata", "/servers/{server_id}/metadata", + mapper.connect("metadata", "/{tenant_id}/servers/{server_id}/metadata", controller=server_metadata_controller, action='update_all', conditions={"method": ['PUT']}) -- cgit From 057449d4f96fd168b2e949b6ce429ce012911bec Mon Sep 17 00:00:00 2001 From: William Wolf Date: Wed, 10 Aug 2011 11:37:44 -0400 Subject: fix pep8 issues --- nova/api/openstack/contrib/floating_ips.py | 2 +- nova/api/openstack/servers.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/floating_ips.py b/nova/api/openstack/contrib/floating_ips.py index 52c9c6cf9..2aba1068a 100644 --- a/nova/api/openstack/contrib/floating_ips.py +++ b/nova/api/openstack/contrib/floating_ips.py @@ -102,7 +102,7 @@ class FloatingIPController(object): def delete(self, req, id): context = req.environ['nova.context'] ip = self.network_api.get_floating_ip(context, id) - + if 'fixed_ip' in ip: try: self.disassociate(req, id, '') diff --git a/nova/api/openstack/servers.py b/nova/api/openstack/servers.py index 45d7dc214..fec319d8e 100644 --- a/nova/api/openstack/servers.py +++ b/nova/api/openstack/servers.py @@ -647,7 +647,7 @@ class ControllerV11(Controller): base_url, project_id) addresses_builder = nova.api.openstack.views.addresses.ViewBuilderV11() builder = nova.api.openstack.views.servers.ViewBuilderV11( - addresses_builder, flavor_builder, image_builder, + addresses_builder, flavor_builder, image_builder, base_url, project_id) return builder.build(instance, is_detail=is_detail) -- cgit From 2046554bc54a2ebbc9ea681b9f35eef79e0a1c0c Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 10 Aug 2011 11:49:54 -0400 Subject: Updated extensions to use the TenantMapper --- nova/api/openstack/extensions.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index d7edd420c..f733b2d95 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -29,6 +29,7 @@ from nova import exception from nova import flags from nova import log as logging from nova import wsgi as base_wsgi +import nova.api.openstack from nova.api.openstack import common from nova.api.openstack import faults from nova.api.openstack import wsgi @@ -259,7 +260,7 @@ class ExtensionMiddleware(base_wsgi.Middleware): ext_mgr = ExtensionManager(FLAGS.osapi_extensions_path) self.ext_mgr = ext_mgr - mapper = routes.Mapper() + mapper = nova.api.openstack.TenantMapper() serializer = wsgi.ResponseSerializer( {'application/xml': ExtensionsXMLSerializer()}) @@ -267,12 +268,16 @@ class ExtensionMiddleware(base_wsgi.Middleware): for resource in ext_mgr.get_resources(): LOG.debug(_('Extended resource: %s'), resource.collection) - mapper.resource(resource.collection, resource.collection, + kargs = dict( controller=wsgi.Resource( resource.controller, serializer=serializer), collection=resource.collection_actions, - member=resource.member_actions, - parent_resource=resource.parent) + member=resource.member_actions) + + if resource.parent: + kargs['parent_resource'] = resource.parent + + mapper.resource(resource.collection, resource.collection, **kargs) # extended actions action_resources = self._action_ext_resources(application, ext_mgr, -- cgit From 203326be6c4acdd474fe307fb608ef35d95e0a4e Mon Sep 17 00:00:00 2001 From: William Wolf Date: Wed, 10 Aug 2011 15:47:22 -0400 Subject: tenant_id -> project_id --- nova/api/openstack/__init__.py | 9 +++++---- nova/api/openstack/extensions.py | 4 ++-- nova/api/openstack/wsgi.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index ca6c1b5f1..df8e0c564 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -72,12 +72,12 @@ class TenantMapper(routes.Mapper): def resource(self, member_name, collection_name, **kwargs): if not ('parent_resource' in kwargs): - kwargs['path_prefix'] = '{tenant_id}/' + kwargs['path_prefix'] = '{project_id}/' else: parent_resource = kwargs['parent_resource'] p_collection = parent_resource['collection_name'] p_member = parent_resource['member_name'] - kwargs['path_prefix'] = '{tenant_id}/%s/:%s_id' % (p_collection, + kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection, p_member) routes.Mapper.resource(self, member_name, collection_name, @@ -203,7 +203,7 @@ class APIRouterV11(APIRouter): parent_resource=dict(member_name='image', collection_name='images')) - mapper.connect("metadata", "/{tenant_id}/images/{image_id}/metadata", + mapper.connect("metadata", "/{project_id}/images/{image_id}/metadata", controller=image_metadata_controller, action='update_all', conditions={"method": ['PUT']}) @@ -215,7 +215,8 @@ class APIRouterV11(APIRouter): parent_resource=dict(member_name='server', collection_name='servers')) - mapper.connect("metadata", "/{tenant_id}/servers/{server_id}/metadata", + mapper.connect("metadata", + "/{project_id}/servers/{server_id}/metadata", controller=server_metadata_controller, action='update_all', conditions={"method": ['PUT']}) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index f733b2d95..530972bec 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -221,12 +221,12 @@ class ExtensionMiddleware(base_wsgi.Middleware): for action in ext_mgr.get_actions(): if not action.collection in action_resources.keys(): resource = ActionExtensionResource(application) - mapper.connect("/:(tenant_id)/%s/:(id)/action.:(format)" % + mapper.connect("/:(project_id)/%s/:(id)/action.:(format)" % action.collection, action='action', controller=resource, conditions=dict(method=['POST'])) - mapper.connect("/:(tenant_id)/%s/:(id)/action" % + mapper.connect("/:(project_id)/%s/:(id)/action" % action.collection, action='action', controller=resource, diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 34c31260b..82fef6df8 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -486,8 +486,8 @@ class Resource(wsgi.Application): msg = _("Malformed request body") return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) - if 'tenant_id' in args: - args.pop("tenant_id") + if "project_id" in args: + project_id = args.pop("project_id") try: action_result = self.dispatch(request, action, args) -- cgit From 01c7da9e861fee3201e2bc5dcc289024aa5ced61 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Thu, 11 Aug 2011 14:40:05 -0400 Subject: got rid of tenant_id everywhere, got rid of X-Auth-Project-Id header support (not in the spec), and updated tests --- nova/api/openstack/__init__.py | 4 ++-- nova/api/openstack/auth.py | 10 +++++++--- nova/api/openstack/extensions.py | 2 +- nova/api/openstack/wsgi.py | 5 +++-- 4 files changed, 13 insertions(+), 8 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index de2aee96a..8805c4ef6 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -68,7 +68,7 @@ class FaultWrapper(base_wsgi.Middleware): return faults.Fault(exc) -class TenantMapper(routes.Mapper): +class ProjectMapper(routes.Mapper): def resource(self, member_name, collection_name, **kwargs): if not ('parent_resource' in kwargs): @@ -191,7 +191,7 @@ class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" def __init__(self, ext_mgr=None): - mapper = TenantMapper() + mapper = ProjectMapper() self.server_members = {} self._setup_routes(mapper) super(APIRouter, self).__init__(mapper) diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index d42abe1f8..164a60cbc 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -55,9 +55,13 @@ class AuthMiddleware(wsgi.Middleware): LOG.warn(msg % locals()) return faults.Fault(webob.exc.HTTPUnauthorized()) - try: - project_id = req.headers["X-Auth-Project-Id"] - except KeyError: + project_id = "" + path_parts = req.path.split('/') + # TODO(wwolf): this v1.1 check will be temporary as + # keystone should be taking this over at some point + if len(path_parts) > 1 and path_parts[1] == 'v1.1': + project_id = path_parts[2] + elif len(path_parts) > 1 and path_parts[1] == 'v1.0': # FIXME(usrleon): It needed only for compatibility # while osapi clients don't use this header projects = self.auth.get_projects(user_id) diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index 86ffb91c6..9c4d32eb4 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -260,7 +260,7 @@ class ExtensionMiddleware(base_wsgi.Middleware): ext_mgr = ExtensionManager(FLAGS.osapi_extensions_path) self.ext_mgr = ext_mgr - mapper = nova.api.openstack.TenantMapper() + mapper = nova.api.openstack.ProjectMapper() serializer = wsgi.ResponseSerializer( {'application/xml': ExtensionsXMLSerializer()}) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 82fef6df8..dc0f1b93e 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -486,8 +486,9 @@ class Resource(wsgi.Application): msg = _("Malformed request body") return faults.Fault(webob.exc.HTTPBadRequest(explanation=msg)) - if "project_id" in args: - project_id = args.pop("project_id") + project_id = args.pop("project_id", None) + if 'nova.context' in request.environ and project_id: + request.environ['nova.context'].project_id = project_id try: action_result = self.dispatch(request, action, args) -- cgit From 4275c9062e2d89c30472ba6646fd3c2503c0e984 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Thu, 11 Aug 2011 15:49:28 -0400 Subject: fixed v1.0 stuff with X-Auth-Project-Id header, and fixed broken integrated tests --- nova/api/openstack/auth.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 164a60cbc..d13c19852 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -62,13 +62,16 @@ class AuthMiddleware(wsgi.Middleware): if len(path_parts) > 1 and path_parts[1] == 'v1.1': project_id = path_parts[2] elif len(path_parts) > 1 and path_parts[1] == 'v1.0': - # FIXME(usrleon): It needed only for compatibility - # while osapi clients don't use this header - projects = self.auth.get_projects(user_id) - if projects: - project_id = projects[0].id - else: - return faults.Fault(webob.exc.HTTPUnauthorized()) + try: + project_id = req.headers["X-Auth-Project-Id"] + except KeyError: + # FIXME(usrleon): It needed only for compatibility + # while osapi clients don't use this header + projects = self.auth.get_projects(user_id) + if projects: + project_id = projects[0].id + else: + return faults.Fault(webob.exc.HTTPUnauthorized()) is_admin = self.auth.is_admin(user_id) req.environ['nova.context'] = context.RequestContext(user_id, -- cgit From 8131a998bba1ec2893043e5e02b66ea7df38a4ba Mon Sep 17 00:00:00 2001 From: William Wolf Date: Thu, 11 Aug 2011 16:06:28 -0400 Subject: fix pep8 --- nova/api/openstack/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index d13c19852..c9c740a1d 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -57,7 +57,7 @@ class AuthMiddleware(wsgi.Middleware): project_id = "" path_parts = req.path.split('/') - # TODO(wwolf): this v1.1 check will be temporary as + # TODO(wwolf): this v1.1 check will be temporary as # keystone should be taking this over at some point if len(path_parts) > 1 and path_parts[1] == 'v1.1': project_id = path_parts[2] -- cgit From a1dc7e0dbcff7130adb0274e6628ce30d1ac83c1 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Mon, 15 Aug 2011 09:35:44 -0400 Subject: Dryed up contructors --- nova/api/openstack/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/__init__.py b/nova/api/openstack/__init__.py index 8805c4ef6..3b74fefc9 100644 --- a/nova/api/openstack/__init__.py +++ b/nova/api/openstack/__init__.py @@ -97,10 +97,13 @@ class APIRouter(base_wsgi.Router): def __init__(self, ext_mgr=None): self.server_members = {} - mapper = routes.Mapper() + mapper = self._mapper() self._setup_routes(mapper) super(APIRouter, self).__init__(mapper) + def _mapper(self): + return routes.Mapper() + def _setup_routes(self, mapper): raise NotImplementedError(_("You must implement _setup_routes.")) @@ -190,11 +193,8 @@ class APIRouterV10(APIRouter): class APIRouterV11(APIRouter): """Define routes specific to OpenStack API V1.1.""" - def __init__(self, ext_mgr=None): - mapper = ProjectMapper() - self.server_members = {} - self._setup_routes(mapper) - super(APIRouter, self).__init__(mapper) + def _mapper(self): + return ProjectMapper() def _setup_routes(self, mapper): self._setup_base_routes(mapper, '1.1') -- cgit From 8e7163cd413eebd2e08b5ad32d155f643e972740 Mon Sep 17 00:00:00 2001 From: William Wolf Date: Mon, 15 Aug 2011 15:41:07 -0400 Subject: put tenant_id back in places where it was --- nova/api/openstack/contrib/security_groups.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/security_groups.py b/nova/api/openstack/contrib/security_groups.py index 6c1043c83..d1230df69 100644 --- a/nova/api/openstack/contrib/security_groups.py +++ b/nova/api/openstack/contrib/security_groups.py @@ -56,7 +56,7 @@ class SecurityGroupController(object): if rule.group_id: source_group = db.security_group_get(context, rule.group_id) sg_rule['group'] = {'name': source_group.name, - 'project_id': source_group.project_id} + 'tenant_id': source_group.project_id} else: sg_rule['ip_range'] = {'cidr': rule.cidr} return sg_rule @@ -66,7 +66,7 @@ class SecurityGroupController(object): security_group['id'] = group.id security_group['description'] = group.description security_group['name'] = group.name - security_group['project_id'] = group.project_id + security_group['tenant_id'] = group.project_id security_group['rules'] = [] for rule in group.rules: security_group['rules'] += [self._format_security_group_rule( @@ -118,7 +118,7 @@ class SecurityGroupController(object): return {'security_groups': list(sorted(result, - key=lambda k: (k['project_id'], k['name'])))} + key=lambda k: (k['tenant_id'], k['name'])))} def create(self, req, body): """Creates a new security group.""" -- cgit From f4d608549f0a539e48276be163593ced558a136f Mon Sep 17 00:00:00 2001 From: William Wolf Date: Tue, 16 Aug 2011 15:11:32 -0400 Subject: make project_id authorization work properly, with test --- nova/api/openstack/auth.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index c9c740a1d..8f1319cca 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -55,23 +55,36 @@ class AuthMiddleware(wsgi.Middleware): LOG.warn(msg % locals()) return faults.Fault(webob.exc.HTTPUnauthorized()) + # Get all valid projects for the user + projects = self.auth.get_projects(user_id) + if not projects: + return faults.Fault(webob.exc.HTTPUnauthorized()) + project_id = "" path_parts = req.path.split('/') # TODO(wwolf): this v1.1 check will be temporary as # keystone should be taking this over at some point if len(path_parts) > 1 and path_parts[1] == 'v1.1': project_id = path_parts[2] + # Check that the project for project_id exists, and that user + # is authorized to use it + try: + project = self.auth.get_project(project_id) + except exception.ProjectNotFound: + project = None + if project: + user = self.auth.get_user(user_id) + if not project.has_member(user): + return faults.Fault(webob.exc.HTTPUnauthorized()) + else: + return faults.Fault(webob.exc.HTTPUnauthorized()) elif len(path_parts) > 1 and path_parts[1] == 'v1.0': try: project_id = req.headers["X-Auth-Project-Id"] except KeyError: # FIXME(usrleon): It needed only for compatibility # while osapi clients don't use this header - projects = self.auth.get_projects(user_id) - if projects: - project_id = projects[0].id - else: - return faults.Fault(webob.exc.HTTPUnauthorized()) + project_id = projects[0].id is_admin = self.auth.is_admin(user_id) req.environ['nova.context'] = context.RequestContext(user_id, -- cgit From 3dc1c357ca280705bc745b601daaa81e679d08d3 Mon Sep 17 00:00:00 2001 From: Naveed Massjouni Date: Wed, 17 Aug 2011 01:18:16 -0400 Subject: Append the project_id to the SERVER-MANAGEMENT-URL header for v1.1 requests. Also, ensure that the project_id is correctly parsed from the request. --- nova/api/openstack/auth.py | 47 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 14 deletions(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index 8f1319cca..d14553cd4 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -28,6 +28,7 @@ from nova import flags from nova import log as logging from nova import utils from nova import wsgi +from nova.api.openstack import common from nova.api.openstack import faults LOG = logging.getLogger('nova.api.openstack') @@ -71,19 +72,16 @@ class AuthMiddleware(wsgi.Middleware): try: project = self.auth.get_project(project_id) except exception.ProjectNotFound: - project = None - if project: - user = self.auth.get_user(user_id) - if not project.has_member(user): - return faults.Fault(webob.exc.HTTPUnauthorized()) - else: return faults.Fault(webob.exc.HTTPUnauthorized()) - elif len(path_parts) > 1 and path_parts[1] == 'v1.0': + if project_id not in [p.id for p in projects]: + return faults.Fault(webob.exc.HTTPUnauthorized()) + else: + # As a fallback, set project_id from the headers, which is the v1.0 + # behavior. As a last resort, be forgiving to the user and set + # project_id based on a valid project of theirs. try: project_id = req.headers["X-Auth-Project-Id"] except KeyError: - # FIXME(usrleon): It needed only for compatibility - # while osapi clients don't use this header project_id = projects[0].id is_admin = self.auth.is_admin(user_id) @@ -115,12 +113,20 @@ class AuthMiddleware(wsgi.Middleware): LOG.warn(msg) return faults.Fault(webob.exc.HTTPUnauthorized(explanation=msg)) + # Gabe did this. + def _get_auth_header(key): + """Ensures that the KeyError returned is meaningful.""" + try: + return req.headers[key] + except KeyError as ex: + raise KeyError(key) try: - username = req.headers['X-Auth-User'] - key = req.headers['X-Auth-Key'] + username = _get_auth_header('X-Auth-User') + key = _get_auth_header('X-Auth-Key') except KeyError as ex: - LOG.warn(_("Could not find %s in request.") % ex) - return faults.Fault(webob.exc.HTTPUnauthorized()) + msg = _("Could not find %s in request.") % ex + LOG.warn(msg) + return faults.Fault(webob.exc.HTTPUnauthorized(explanation=msg)) token, user = self._authorize_user(username, key, req) if user and token: @@ -169,6 +175,16 @@ class AuthMiddleware(wsgi.Middleware): """ ctxt = context.get_admin_context() + project_id = req.headers.get('X-Auth-Project-Id') + if project_id is None: + # If the project_id is not provided in the headers, be forgiving to + # the user and set project_id based on a valid project of theirs. + user = self.auth.get_user_from_access_key(key) + projects = self.auth.get_projects(user.id) + if not projects: + raise webob.exc.HTTPUnauthorized() + project_id = projects[0].id + try: user = self.auth.get_user_from_access_key(key) except exception.NotFound: @@ -182,7 +198,10 @@ class AuthMiddleware(wsgi.Middleware): token_dict['token_hash'] = token_hash token_dict['cdn_management_url'] = '' os_url = req.url - token_dict['server_management_url'] = os_url + token_dict['server_management_url'] = os_url.strip('/') + version = common.get_version_from_href(os_url) + if version == '1.1': + token_dict['server_management_url'] += '/' + project_id token_dict['storage_url'] = '' token_dict['user_id'] = user.id token = self.db.auth_token_create(ctxt, token_dict) -- cgit From 289219f8ef7ae677aaa8d0720167470e80843fe1 Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 17 Aug 2011 12:36:39 -0400 Subject: Undo an unecessary change --- nova/api/openstack/contrib/security_groups.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/contrib/security_groups.py b/nova/api/openstack/contrib/security_groups.py index d1230df69..6c57fbb51 100644 --- a/nova/api/openstack/contrib/security_groups.py +++ b/nova/api/openstack/contrib/security_groups.py @@ -458,7 +458,7 @@ class SecurityGroupRulesXMLDeserializer(wsgi.MetadataXMLDeserializer): def _get_metadata(): metadata = { "attributes": { - "security_group": ["id", "project_id", "name"], + "security_group": ["id", "tenant_id", "name"], "rule": ["id", "parent_group_id"], "security_group_rule": ["id", "parent_group_id"], } -- cgit From fdfd551dd46b831f5c44a8c62614de7bcbc1a5eb Mon Sep 17 00:00:00 2001 From: Alex Meade Date: Wed, 17 Aug 2011 12:37:50 -0400 Subject: very minor cleanup --- nova/api/openstack/auth.py | 1 - 1 file changed, 1 deletion(-) (limited to 'nova/api') diff --git a/nova/api/openstack/auth.py b/nova/api/openstack/auth.py index d14553cd4..b6ff1126b 100644 --- a/nova/api/openstack/auth.py +++ b/nova/api/openstack/auth.py @@ -113,7 +113,6 @@ class AuthMiddleware(wsgi.Middleware): LOG.warn(msg) return faults.Fault(webob.exc.HTTPUnauthorized(explanation=msg)) - # Gabe did this. def _get_auth_header(key): """Ensures that the KeyError returned is meaningful.""" try: -- cgit