enhancement for the common policy enforce

Now the magnum.common.policy just support an "enforce" method to
wsgi policy check.

And this "enforce" method should be inline the body of wsgi method.
Such as:
from magnum.common import policy
class BaysController(rest.RestController):
    ....
    @wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
    def delete(self, bay_ident):
        ... doc string ...
        policy.enforce(pecan.request.context, "bay:create")
        .... common stuff ....

This inline style is ugly.

Now this patch is improving it.
This patch uses a decorator for policy check.
With this decorator we can do the policy check as follow:
from magnum.common import policy
class BaysController(rest.RestController):
    ....
    @policy.enforce_wsgi("bay", "delete")
    @wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
    def delete(self, bay_ident):
        ...

Here: This decorator MUST appear first (the outermost decorator) on an API
method for it to work correctly.

The decorator use functools.wraps to decorator the wsgi function.
A common decorator(without functools.wraps) replaces the original function
with an new one, that means it will lose the information about the original
function, it would be a serious problem for pcen wsgi.
That's why we have functools.wraps. This takes a function used in a decorator
and adds the functionality of copying over the function name, docstring,
arguments list, etc.

ref: http://stackoverflow.com/questions/308999/what-does-functools-wraps-do

Co-Authored-By: yuntongjin <yuntong.jin@intel.com>
Change-Id: I9a7baf9559ff924ca4e261db2961b9d3c8763325
Partial-implements: blueprint policy-enforce
This commit is contained in:
ShaoHe Feng 2015-06-11 03:21:32 +08:00
parent 1c78cd834b
commit e8a77b6e1b

View File

@ -15,8 +15,10 @@
"""Policy Engine For magnum."""
import functools
from oslo_config import cfg
from oslo_policy import policy
import pecan
_ENFORCER = None
@ -88,3 +90,30 @@ def enforce(context, action=None, target=None,
'user_id': context.user_id}
return enforcer.enforce(action, target, credentials,
do_raise=do_raise, exc=exc, *args, **kwargs)
# NOTE(Shaohe Feng): This decorator MUST appear first (the outermost
# decorator) on an API method for it to work correctly
def enforce_wsgi(api_name, act=None):
"""This is a decorator to simplify wsgi action policy rule check.
:param api_name: The collection name to be evaluate.
:param act: The function name of wsgi action.
example:
from magnum.common import policy
class BaysController(rest.RestController):
....
@policy.enforce_wsgi("bay", "delete")
@wsme_pecan.wsexpose(None, types.uuid_or_name, status_code=204)
def delete(self, bay_ident):
...
"""
def wraper(fn):
action = "%s:%s" % (api_name, (act or fn.func_name))
@functools.wraps(fn)
def handle(self, *args, **kwargs):
enforce(pecan.request.context, action, None)
return fn(self, *args, **kwargs)
return handle
return wraper