[openstack-dev] [Ceilometer] Question on decorators in Ceilometer pecan framework
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_idq.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 = {} 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)
Re: [openstack-dev] [Ceilometer] Question on decorators in Ceilometer pecan framework
Sorry, wrong BP review link below. Here is the correct one: https://review.openstack.org/#/c/112127/3. Please disregard the wiki link. From: Pendergrass, Eric Sent: Friday, August 08, 2014 6:50 AM To: openstack-dev@lists.openstack.org Cc: Giannetti, Fabio Subject: [Ceilometer] Question on decorators in Ceilometer pecan framework 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_idq.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 = {} 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 =
Re: [openstack-dev] [Ceilometer] Question on decorators in Ceilometer pecan framework
Wrong link again, this is embarrassing :( https://review.openstack.org/#/c/112137/3 From: Pendergrass, Eric Sent: Friday, August 08, 2014 7:15 AM To: openstack-dev@lists.openstack.org Subject: RE: [Ceilometer] Question on decorators in Ceilometer pecan framework Sorry, wrong BP review link below. Here is the correct one: https://review.openstack.org/#/c/112127/3. Please disregard the wiki link. From: Pendergrass, Eric Sent: Friday, August 08, 2014 6:50 AM To: openstack-dev@lists.openstack.orgmailto:openstack-dev@lists.openstack.org Cc: Giannetti, Fabio Subject: [Ceilometer] Question on decorators in Ceilometer pecan framework 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_idq.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 = {} 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)
Re: [openstack-dev] [Ceilometer] Question on decorators in Ceilometer pecan framework
It looks like maybe WSME or Pecan is inspecting the method signature. Have you tried to change the order of the decorators? On Aug 8, 2014, at 9:16, Pendergrass, Eric eric.pendergr...@hp.com wrote: Wrong link again, this is embarrassing L https://review.openstack.org/#/c/112137/3 From: Pendergrass, Eric Sent: Friday, August 08, 2014 7:15 AM To: openstack-dev@lists.openstack.org Subject: RE: [Ceilometer] Question on decorators in Ceilometer pecan framework Sorry, wrong BP review link below. Here is the correct one: https://review.openstack.org/#/c/112127/3. Please disregard the wiki link. From: Pendergrass, Eric Sent: Friday, August 08, 2014 6:50 AM To: openstack-dev@lists.openstack.org Cc: Giannetti, Fabio Subject: [Ceilometer] Question on decorators in Ceilometer pecan framework 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_idq.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 = {} 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 athttps://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)
Re: [openstack-dev] [Ceilometer] Question on decorators in Ceilometer pecan framework
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_idq.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)