pipeline = cors sizelimit url_normalize request_id admin_token_auth build_auth_context token_auth json_body ec2_extension_v3 s3_extension service_v3
pipeline对应调用代码如下
点击(此处)折叠或打开
- def _pipeline_app_context(self, object_type, section, name,
- global_conf, local_conf, global_additions):
- if 'pipeline' not in local_conf:
- raise LookupError(
- "The [%s] section in %s is missing a 'pipeline' setting"
- % (section, self.filename))
- pipeline = local_conf.pop('pipeline').split()
- if local_conf:
- raise LookupError(
- "The [%s] pipeline section in %s has extra "
- "(disallowed) settings: %s"
- % (', '.join(local_conf.keys())))
- context = LoaderContext(None, PIPELINE, None, global_conf,
- local_conf, self)
- context.app_context = self.get_context(
- APP, pipeline[-1], global_conf)
- context.filter_contexts = [
- self.get_context(FILTER, name, global_conf)
- for name in pipeline[:-1]]
- return context
-
- class _PipeLine(_ObjectType):
- name = 'pipeline'
- def invoke(self, context):
- app = context.app_context.create()
- filters = [c.create() for c in context.filter_contexts]
- filters.reverse()
- for filter in filters:
- app = filter(app)
- return app
app初始通过app = context.app_context.create()来初始化
定位app
[app:service_v3]
use = egg:keystone#service_v3
查找entry_point.txt
service_v3 = keystone.version.service:v3_app_factory
app的create()后返回的对象就是wsgi.ComposingRouter类实例
注: app继承的route的call方法比较绕,看不懂参数怎么传进去的,装饰器非常复杂
参考一个简要的说明http://blog.csdn.net/spch2008/article/details/9003410
下面的测试代码是模仿写的,知道能工作就可以了
点击(此处)折叠或打开
- import webob.dec
- import webob.exc
- from webob import Response
- from wsgiref.simple_server import make_server
- def loli(a, b):
- res = Response('wtf~~~')
- gg = res(a, b)
- return gg
- class Wtf():
- def __init__(self, fun):
- self.app = fun
- def __call__(self, a, b):
- return self.app(a, b)
- class Rtest(object):
- def __init__(self):
- self._router = Wtf(self._dispatch)
- @webob.dec.wsgify()
- def __call__(self, req):
- return self._router
- @staticmethod
- @webob.dec.wsgify()
- def _dispatch(req):
- return loli
- application = Rtest()
- httpd = make_server('localhost', 8080, application)
- httpd.serve_forever()
wsgi调用就没问题,那个装饰器会校验输入参数
妈的我越来越讨厌python的的装饰器了,顺便,根据https://www.ustack.com/blog/demoapi1/
openstack的新服务都不用Paste + PasteDeploy + Routes + WebOb的框架转用Pecan框架了
filter我们拿json_body来当例子
[filter:json_body]
use = egg:keystone#json_body
c.create()调用_Filter类的invoke方法
查找entry_point.txt
json_body = keystone.middleware:JsonBodyMiddleware.factory
定位到JsonBodyMiddleware的factory
和APP不同的是
c.create()最后返回的不是JsonBodyMiddleware类实例,而是一个函数
当这个函数输入参数app就返回JsonBodyMiddleware类
那参数app是什么呢......
看后面PipeLine类的invoke
点击(此处)折叠或打开
- # 倒转filter列表
- filters.reverse()
- for filter in filters:
- app = filter(app)
- return app
最后一个filter的初始化用的参数就是service_v3返回的wsgi.ComposingRouter类实例
然后倒着把每一个filter类作为前一个filter的参数来初始化
每个filter类实例都有一个属性application指向后一个filter
最后一个filter的application属性指向service_v3返回的wsgi.ComposingRouter类实例
最后urlmap字典里的app就是第一个filter的实例
所以,当一个请求过来的时候,执行的处理顺序为
请求-->cors-->sizelimit-->....顺序处理...service_v3
返回就是
service_v3-->s3_extension-->.......cors
每个filter有需要就重写处理请求的代码和处理返回的代码
没有对应操作,就传入下层或者返回给上层
看懂上面,通过openstack封装好的类写filter就非常简单了
一个最简单的方式就是继承wsgi.Middleware类
我们看看wsgi.Middleware
写自己的filter,只要重写process_request或者process_response方法就可以了
process_request方法非常简单,只要设置参数request的数据即可,如果process_request有返回值,必须返回response类,返回后不继续往下走(请求被中途拦截返回)
process_response不重写的话自动返回给上一层
process_request和process_response都在这里调用都是是封装在__call__里调用的
这个写filter的方法优点是处理请求和返回的数据简单,但没有添加路由的接口
所以添加路由的filter通过继承wsgi.V3ExtensionRouter
我们看s3_extension这个filter是怎么添加路由的
定义好controller,重写add_routes类添加路由....真TM简单
这个方法适合添加路由但是不适合做filter该干的事情——拦截、处理请求和返回
如果需要处理请求和返回需要重写__call__方法
所以
1、想通过filter扩展controller,集成wsgi.V3ExtensionRouter
2、通过filter做一些拦截、校验之类的功能,继承wsgi.Middleware
顺便总结下默认pipeline每个filter的作用
cors 跨域
sizelimit 限制bodysize
url_normalize 格式化url, 比如url最后一个字符串是/ 通过切片剔除最后一个字符串
request_id 生成request_id
admin_token_auth 允许使用admin_token_auth登陆,就是配置文件里写死的那个token, 这个在filter在创建管理员后需要剔除掉
build_auth_context 从request中获取auth_context并处理一下, 写入store中, 然后把auth_context塞到request.environ中
token_auth 没干什么事情,就是把获取到的数据 从head取出来塞到environ里 TokenAuthMiddleware
json_body 把request的body转换为dict塞到request.environ[PARAMS_ENV]中
ec2_extension_v3 加了几个ec2相关的登陆认证 顺便当headers['Content-Type'] != 'application/json-home' 把body转成了bytes
s3_extension 加了一个/s3tokens的路由 s3方式登陆 和上面一样body转bytes(都是集成V3ExtensionRouter)
service_v3 基本路由
也就是说
其实只用uuid不上ssl什么的v3的pipe只需要
sizelimit url_normalize request_id build_auth_context token_auth json_body service_v3
就够了
最后一个filter的application属性指向service_v3返回的wsgi.ComposingRouter类实例
最后urlmap字典里的app就是第一个filter的实例
所以,当一个请求过来的时候,执行的处理顺序为
请求-->cors-->sizelimit-->....顺序处理...service_v3
返回就是
service_v3-->s3_extension-->.......cors
每个filter有需要就重写处理请求的代码和处理返回的代码
没有对应操作,就传入下层或者返回给上层
看懂上面,通过openstack封装好的类写filter就非常简单了
一个最简单的方式就是继承wsgi.Middleware类
我们看看wsgi.Middleware
点击(此处)折叠或打开
- class Middleware(Application):
- @classmethod
- def factory(cls, global_config):
- # factory方法就是之前说的用来生成自身实例的方法
- def _factory(app):
- return cls(app)
- return _factory
- def __init__(self, application):
- super(Middleware, self).__init__()
- self.application = application
- def process_request(self, request):
- def process_response(self, request, response):
- @webob.dec.wsgify()
- def __call__(self, request):
- # 所有filter类都必须有
- # response = request.get_response(self.application)
- # 通过这个调用下层的filter
process_request方法非常简单,只要设置参数request的数据即可,如果process_request有返回值,必须返回response类,返回后不继续往下走(请求被中途拦截返回)
process_response不重写的话自动返回给上一层
process_request和process_response都在这里调用都是是封装在__call__里调用的
这个写filter的方法优点是处理请求和返回的数据简单,但没有添加路由的接口
所以添加路由的filter通过继承wsgi.V3ExtensionRouter
我们看s3_extension这个filter是怎么添加路由的
点击(此处)折叠或打开
- class S3Extension(wsgi.V3ExtensionRouter):
- def add_routes(self, mapper):
- controller = S3Controller()
- # validation
- self._add_resource(
- mapper, controller,
- path='/s3tokens',
- post_action='authenticate',
- rel=json_home.build_v3_extension_resource_relation(
- 's3tokens', '1.0', 's3tokens'))
这个方法适合添加路由但是不适合做filter该干的事情——拦截、处理请求和返回
如果需要处理请求和返回需要重写__call__方法
所以
1、想通过filter扩展controller,集成wsgi.V3ExtensionRouter
2、通过filter做一些拦截、校验之类的功能,继承wsgi.Middleware
顺便总结下默认pipeline每个filter的作用
cors 跨域
sizelimit 限制bodysize
url_normalize 格式化url, 比如url最后一个字符串是/ 通过切片剔除最后一个字符串
request_id 生成request_id
admin_token_auth 允许使用admin_token_auth登陆,就是配置文件里写死的那个token, 这个在filter在创建管理员后需要剔除掉
build_auth_context 从request中获取auth_context并处理一下, 写入store中, 然后把auth_context塞到request.environ中
token_auth 没干什么事情,就是把获取到的数据 从head取出来塞到environ里 TokenAuthMiddleware
json_body 把request的body转换为dict塞到request.environ[PARAMS_ENV]中
ec2_extension_v3 加了几个ec2相关的登陆认证 顺便当headers['Content-Type'] != 'application/json-home' 把body转成了bytes
s3_extension 加了一个/s3tokens的路由 s3方式登陆 和上面一样body转bytes(都是集成V3ExtensionRouter)
service_v3 基本路由
也就是说
其实只用uuid不上ssl什么的v3的pipe只需要
sizelimit url_normalize request_id build_auth_context token_auth json_body service_v3
就够了