On Aug 8, 2014, at 8:49 AM, Pendergrass, Eric <eric.pendergr...@hp.com> wrote:
> Hi, > > We have been struggling to get a decorator working for proposed new RBAC > functionality in ceilometer-api. We’re hitting a problem where GET request > query parameters are mucked up by our decorator. Here’s an example call: > > curl -H "X-Auth-Token:$TOKEN" > 'http://localhost:8777/v2/meters?q.field=project_id&q.value=8c678720fb5b4e3bb18dee222d7d7933' > > And here’s the decorator method (we’ve tried changing the kwargs, args, etc. > with no luck): > > _ENFORCER = None > > def protected(controller_class): > > global _ENFORCER > if not _ENFORCER: > _ENFORCER = policy.Enforcer() > > def wrapper(f): > @functools.wraps(f) > def inner(self, **kwargs): > pdb.set_trace() > self._rbac_context = {} You need to be careful saving request state on the controller. The controller may be shared by multiple requests (I see below that you’re creating a MeterController for each incoming request, but that won’t be the case for all controller types). It’s better to store the value in the pecan.request, which is a thread-safe request-specific object. If you just need to store some values, and not test ACLs it in the decorator, you could use a Pecan hook [1] like we do with the configuration settings [2]. Doug 1 - http://pecan.readthedocs.org/en/latest/hooks.html 2 - http://git.openstack.org/cgit/openstack/ceilometer/tree/ceilometer/api/hooks.py#n27 > if not _ENFORCER.enforce('context_is_admin', > {}, > {'roles': > pecan.request.headers.get('X-Roles', "").split(",")}): > self._rbac_context['project_id'] = > pecan.request.headers.get('X-Project-Id') > self._rbac_context['user_id'] = > pecan.request.headers.get('X-User-Id') > return f(self, **kwargs) > return inner > return wrapper > > tried this too: > > _ENFORCER = None > > def protected(*args): > > controller_class = 'meter' > global _ENFORCER > if not _ENFORCER: > _ENFORCER = policy.Enforcer() > > def wrapper(f, *args): > def inner(self, *args): > pdb.set_trace() > # self._rbac_context = {} > # if not _ENFORCER.enforce('context_is_admin', > # {}, > # {'roles': > pecan.request.headers.get('X-Roles', "").split(",")}): > # self._rbac_context['project_id'] = > pecan.request.headers.get('X-Project-Id') > # self._rbac_context['user_id'] = > pecan.request.headers.get('X-User-Id') > #return f(*args) > f(self, *args) > return inner > return wrapper > > and here’s how it’s used: > > class MetersController(rest.RestController): > """Works on meters.""" > > _rbac_context = {} > @pecan.expose() > def _lookup(self, meter_name, *remainder): > return MeterController(meter_name), remainder > > @wsme_pecan.wsexpose([Meter], [Query]) > @rbac_validate.protected('meters') > def get_all(self, q=None): > """Return all known meters, based on the data recorded so far. > > :param q: Filter rules for the meters to be returned. > """ > q = q or [] … > > > but we get errors similar to below where the arg parser cannot find the query > parameter because the decorator doesn’t take a q argument as > MetersController.get_all does. > > Is there any way to get a decorator to work within the v2 API code and wsme > framework or should we consider another approach? Decorators would really > simplify the RBAC idea we’re working on, which is mostly code-implemented > save for this fairly major problem. > > I have a WIP registered BP on this at > https://blueprints.launchpad.net/ceilometer/+spec/ready-ceilometer-rbac-keystone-v3. > > If I can provide more details I’ll be happy to. > > Thanks > Eric > > /usr/local/bin/ceilometer-api(10)<module>() > -> sys.exit(api()) > /opt/stack/ceilometer/ceilometer/cli.py(96)api() > -> srv.serve_forever() > /usr/lib/python2.7/SocketServer.py(227)serve_forever() > -> self._handle_request_noblock() > /usr/lib/python2.7/SocketServer.py(284)_handle_request_noblock() > -> self.process_request(request, client_address) > /usr/lib/python2.7/SocketServer.py(310)process_request() > -> self.finish_request(request, client_address) > /usr/lib/python2.7/SocketServer.py(323)finish_request() > -> self.RequestHandlerClass(request, client_address, self) > /usr/lib/python2.7/SocketServer.py(638)__init__() > -> self.handle() > /usr/lib/python2.7/wsgiref/simple_server.py(124)handle() > -> handler.run(self.server.get_app()) > /usr/lib/python2.7/wsgiref/handlers.py(85)run() > -> self.result = application(self.environ, self.start_response) > > /opt/stack/python-keystoneclient/keystoneclient/middleware/auth_token.py(663)__call__() > -> return self.app(env, start_response) > /opt/stack/ceilometer/ceilometer/api/app.py(97)__call__() > -> return self.v2(environ, start_response) > > /usr/local/lib/python2.7/dist-packages/pecan/middleware/static.py(151)__call__() > -> return self.app(environ, start_response) > > /usr/local/lib/python2.7/dist-packages/pecan/middleware/debug.py(289)__call__() > -> return self.app(environ, start_response) > > /usr/local/lib/python2.7/dist-packages/pecan/middleware/recursive.py(56)__call__() > -> return self.application(environ, start_response) > /opt/stack/ceilometer/ceilometer/api/middleware.py(83)__call__() > -> app_iter = self.app(environ, replacement_start_response) > /usr/local/lib/python2.7/dist-packages/pecan/core.py(750)__call__() > -> return super(Pecan, self).__call__(environ, start_response) > /usr/local/lib/python2.7/dist-packages/pecan/core.py(616)__call__() > -> self.invoke_controller(controller, args, kwargs, state) > /usr/local/lib/python2.7/dist-packages/pecan/core.py(526)invoke_controller() > -> result = controller(*args, **kwargs) > /usr/local/lib/python2.7/dist-packages/wsmeext/pecan.py(79)callfunction() > -> pecan.request.body, pecan.request.content_type > /usr/local/lib/python2.7/dist-packages/wsme/rest/args.py(276)get_args() > -> from_args = args_from_args(funcdef, args, kwargs) > > /usr/local/lib/python2.7/dist-packages/wsme/rest/args.py(189)args_from_args() > -> funcdef.get_arg(argname).datatype, value > > _______________________________________________ > OpenStack-dev mailing list > OpenStack-dev@lists.openstack.org > http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev
_______________________________________________ OpenStack-dev mailing list OpenStack-dev@lists.openstack.org http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev