openstack-PasteDeployment(源码解析二)

Paste Deployment是一个针对wsgi开发的库,用来配置和加载wsgi application和server。openstack中配置都是通过api-paste.ini文件提供。通过这个文件就可以直接调用Paste Deployment代码来加载web server和上面的application。

代码引用

from paste.deploy import loadapp
wsgi_app = loadapp('config:/path/to/config.ini')

定义Factories

有几个协议: paste.app_factory, paste.composite_factory, paste.filter_factory和 paste.server_factory。 它们都需要一个可调用的东西(比如函数、方法或类)。

paste.app_factory

#应用程序是最常见的。 定义app工厂如下所示:

def app_factory(global_config, **local_conf):
    return wsgi_app
#global_config 是一个字典, local配置是作为keyword参数传递进来。此方法应返回一个 WSGI application.。

paste.composite_factory

Composites只是稍微复杂一点 :

def composite_factory(loader, global_config, **local_conf):
    return wsgi_app
#loader参数是一个对象,它有两个有趣的方法。 get_app(name_or_uri, global_conf=None) 返回给定名称的WSGI应用程序 。 get_filter 和 get_server 方法与前面的方法工作方式一样。

paste.filter_factory

#下面是一个过滤器的示例,它检查远程用户CGI变量是否设置,从而创建一个非常简单的身份验证过滤器 :

def auth_filter_factory(global_conf, req_usernames):
    # space-separated list of usernames:
    req_usernames = req_usernames.split()
    def filter(app):
        return AuthFilter(app, req_usernames)
    return filter

class AuthFilter(object):
    def __init__(self, app, req_usernames):
        self.app = app
        self.req_usernames = req_usernames

    def __call__(self, environ, start_response):
        if environ.get('REMOTE_USER') in self.req_usernames:
            return self.app(environ, start_response)
        start_response(
            '403 Forbidden', [('Content-type', 'text/html')])
        return ['You are forbidden to view this resource']

paste.filter_app_factory

#它和 paste.filter factory有点相似, 但它还需要接收wsgi应用程序参数,并返回一个wsgi应用程序。 所以上面的例子修改后如下:

class AuthFilter(object):
    def __init__(self, app, global_conf, req_usernames):
        # ...
#然后AuthFilter将在 filter_app_factory里提供服务 (在本例中,req_usernames是必需的本地配置键)。

paste.server_factory

#它接收与 applications和filters相同的签名,但返回一个server。

#server 是可调用的,它接收一个参数,即WSGI应用程序。 然后它为应用程序服务。 例子如下:

def server_factory(global_conf, host, port):
    port = int(port)
    def serve(app):
        s = Server(app, host=host, port=port)
        s.serve_forever()
    return serve
#Server的实现留给了用户。

paste.server_runner

除了 wsgi_app 作为第一个参数传递, server应该立即运行外,其它的都与paste.server factory一样。

api-paste.ini

#url请求分发到对应的app,use表明的是分发的方式,这里是urlmap进行分发的
[composite:neutron]
use = egg:Paste#urlmap
/: neutronversions
/v2.0: neutronapi_v2_0

[composite:neutronapi_v2_0]
use = call:neutron.auth:pipeline_factory
noauth = request_id catch_errors extensions neutronapiapp_v2_0
keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0

[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory

[filter:catch_errors]
paste.filter_factory = oslo_middleware:CatchErrors.factory

[filter:keystonecontext]
paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory

[filter:authtoken]
paste.filter_factory = keystonemiddleware.auth_token:filter_factory

[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory

[app:neutronversions]
paste.app_factory = neutron.api.versions:Versions.factory

#创建app
[app:neutronapiapp_v2_0]
#初始化neutron.api.v2.router中APIRouter.factory
paste.app_factory = neutron.api.v2.router:APIRouter.factory

api-paste.ini中filter是定义过滤器,app是定义类似于java中service业务,composite定义类似于controller,use = egg:Paste#urlmap意思是用urlmap进行分发,类似于暴露向外接口。
例:[composite:neutron]
use = egg:Paste#urlmap
/v2.0: neutronapi_v2_0
[composite:neutronapi_v2_0]
use = call:neutron.auth:pipeline_factory
noauth = request_id catch_errors extensions neutronapiapp_v2_0
keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0

打开neutron/auth.py:

def pipeline_factory(loader, global_conf, **local_conf):
    """Create a paste pipeline based on the 'auth_strategy' config option."""
    pipeline = local_conf[cfg.CONF.auth_strategy] #auth_strategy='keystone'
    pipeline = pipeline.split() 
    filters = [loader.get_filter(n) for n in pipeline[:-1]] # filters就是上面keystone后面接的那一堆filters
    app = loader.get_app(pipeline[-1]) #基于pecan web框架获取响应REST请求的application,获取的app类型为pecan.middleware.recursive.RecursiveMiddleware对象
    filters.reverse() #把上述的filters进行逆序一下,即从最后一个filter开始操作
    for filter in filters:
        app = filter(app) #利用每一个filter封装一下app,返回最终封装的app
    return app

其中pipeline_factory函数会根据neutron.conf中cfg.CONF.auth_strategy的值来加载pipline,因为这个参数的值是keystone,因此会加载keystone = cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0,这一堆filters.

[app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
那么最后就是/v2.0会自动找到neutron.api.v2.router这个py文件中APIRouter类factory方法执行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小明程序猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值