问题导读
1、方法pipeline_factory中确定了哪些参数的具体信息?
2、WSGI Application是如何实现的?
3、三个参数noauth,keystone和keystone_nolimit的值是如何得到的?
上一篇:Paste Deployment简介以及cinder-api-paste.ini的解析(1)
在这篇博客中,我会依据上篇博客的内容来简单地解析cinder是如何通过api-paste.ini中的配置信息来进行指定WSGI Application的实现的。
首先来看api-paste.ini文件的具体内容:
- #############
- # OpenStack #
- #############
- [composite:osapi_volume]
- use = call:cinder.api:root_app_factory
- /: apiversions
- /v1: openstack_volume_api_v1
- /v2: openstack_volume_api_v2
- [composite:openstack_volume_api_v1]
- use = call:cinder.api.middleware.auth:pipeline_factory
- noauth = faultwrap sizelimit noauth apiv1
- keystone = faultwrap sizelimit authtoken keystonecontext apiv1
- keystone_nolimit = faultwrap sizelimit authtoken keystonecontext apiv1
- [composite:openstack_volume_api_v2]
- use = call:cinder.api.middleware.auth:pipeline_factory
- noauth = faultwrap sizelimit noauth apiv2
- keystone = faultwrap sizelimit authtoken keystonecontext apiv2
- keystone_nolimit = faultwrap sizelimit authtoken keystonecontext apiv2
- [filter:faultwrap]
- paste.filter_factory = cinder.api.middleware.fault:FaultWrapper.factory
- [filter:noauth]
- paste.filter_factory = cinder.api.middleware.auth:NoAuthMiddleware.factory
- [filter:sizelimit]
- paste.filter_factory = cinder.api.middleware.sizelimit:RequestBodySizeLimiter.factory
- [app:apiv1]
- paste.app_factory = cinder.api.v1.router:APIRouter.factory
- [app:apiv2]
- paste.app_factory = cinder.api.v2.router:APIRouter.factory
- [pipeline:apiversions]
- pipeline = faultwrap osvolumeversionapp
- [app:osvolumeversionapp]
- paste.app_factory = cinder.api.versions:Versions.factory
- ##########
- # Shared #
- ##########
- [filter:keystonecontext]
- paste.filter_factory = cinder.api.middleware.auth:CinderKeystoneContext.factory
- [filter:authtoken]
- paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
- # signing_dir is configurable, but the default behavior of the authtoken
复制代码
我们来逐个字段对文件api-paste.ini的内容进行解析:
首先来看字段:
- [composite:osapi_volume]
- use = call:cinder.api:root_app_factory
- /: apiversions
- /v1: openstack_volume_api_v1
- /v2: openstack_volume_api_v2
复制代码
针对于标志osapi_volume,这里使用composite的分解机制,实现XXXX/XXXX形式的API交给apiversions来处理,XXXX/V1/XXXX形式的API交给openstack_volume_api_v1来处理,XXXX/V2/XXXX形式的API交给openstack_volume_api_v2来处理。
来看apiversions的实现:
- [pipeline:apiversions]
- pipeline = faultwrap osvolumeversionapp
- [app:osvolumeversionapp]
- paste.app_factory = cinder.api.versions:Versions.factory
复制代码
这里使用pipeline section实现faultwrap对osvolumeversionapp的过滤操作,而osvolumeversionapp具体映射为Application:cinder.api.versions:Versions.factory。
来看openstack_volume_api_v1的实现:
- [composite:openstack_volume_api_v1]
- use = call:cinder.api.middleware.auth:pipeline_factory
- noauth = faultwrap sizelimit noauth apiv1
- keystone = faultwrap sizelimit authtoken keystonecontext apiv1
- keystone_nolimit = faultwrap sizelimit authtoken keystonecontext apiv1
复制代码
这里使用composite section实现了多个Application的集合应用,openstack_volume_api_v1具体映射到的Application为use =call:cinder.api.middleware.auth:pipeline_factory,这个Application对应了三个参数:noauth,keystone和keystone_nolimit。我们可以看到这里Application具体实现的方法是pipeline_factory,这个方法的实现机制和上一篇博客中所介绍的pipeline section的机制是类似的。
我们可以看到在参数noauth,keystone和keystone_nolimit中,分别集成了多个应用,实际上每个参数最终实现的Application分别是最后一个,即apiv1,apiv1和apiv1,其前面的Application都扮演这最后一个Application的过滤器。我们以参数keystone为例,实现参数keystone的Application为apiv1,它前面的faultwrap sizelimit authtoken keystonecontext等应用都是它的过滤器,其实现过程也就是faultwrap(sizelimit(authtoken(keystonecontext(apiv1)))),具体的调用过程就是apiv1->keystonecontext->authtoken->sizelimit->faultwrap,前面方法的执行结果作为后面方法的输入参数,最后得到的运行结果作为参数keystone的值。
可以说明,三个参数noauth,keystone和keystone_nolimit的值都是这样得到的,作为Application
use = call:cinder.api.middleware.auth:pipeline_factory的输入值。
从文件中可以看出:openstack_volume_api_v1和openstack_volume_api_v2的实现过程是一致的,这里不用进行说明。
再分别来看其他的Application的实现:
- [app:apiv1]
- paste.app_factory = cinder.api.v1.router:APIRouter.factory
- [app:apiv2]
- paste.app_factory = cinder.api.v2.router:APIRouter.factory
- [filter:faultwrap]
- paste.filter_factory = cinder.api.middleware.fault:FaultWrapper.factory
- [filter:noauth]
- paste.filter_factory = cinder.api.middleware.auth:NoAuthMiddleware.factory
- [filter:sizelimit]
- paste.filter_factory = cinder.api.middleware.sizelimit:RequestBodySizeLimiter.factory
- [filter:keystonecontext]
- paste.filter_factory = cinder.api.middleware.auth:CinderKeystoneContext.factory
- [filter:authtoken]
- paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
复制代码
我们可以看到这些应用的不同类型与上面的分析是一致的,faultwrap noauth sizelimit authtoken keystonecontext作为过滤器都是filter类型,而apiv1和apiv2作为最后实现的Application都是app类型。
经过分析代码,我看到这些过滤器的实现类FaultWrapper,NoAuthMiddleware,RequestBodySizeLimiter和CinderKeystoneContext都是属于cinder部分的源码,它们都继承于同一个类class Middleware(Application),在这个类中实现了方法factory,而过滤器authtoken实现的文件/keystoneclient/middleware/auth_token.py中也实现了filter_factory这个方法。
而在类FaultWrapper,NoAuthMiddleware,RequestBodySizeLimiter和CinderKeystoneContext之中都实现了方法__call__,而在方法filter_factory中最后返回了类AuthProtocol,而在类AuthProtocol中也实现了方法__call__,而在各个类的方法factory中都调用了对应的类的__call__方法,也就是具体实现了这些各种类型的Application的功能,其实我们可以看到这些Application主要就是实现了一些身份验证和请求参数限制等等验证性质的功能。上述就是各个Application的具体实现过程。
我在各个Application的factory方法中定制了一些参数的输出,来验证我们上述的分析(针对/v1)。这里我们以参数keystone = faultwrap sizelimit authtoken keystonecontext apiv1的实现过程为准来看:
- call def pipeline_factory
- loader =
- global_conf = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_conf = {'keystone': 'faultwrap sizelimit authtoken keystonecontext apiv1', 'noauth': 'faultwrap sizelimit noauth apiv1', 'keystone_nolimit': 'faultwrap sizelimit authtoken keystonecontext apiv1'}
- app =
复制代码
========================================================================================
- call class cinder.api.v1.router.APIRouter
- global_config = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_config = {}
复制代码
========================================================================================
- call class cinder.api.middleware.auth.CinderKeystoneContext
- global_config = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_config = {}
- app =
复制代码
========================================================================================
- call def filter_factory
- global_conf = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_conf = {'service_protocol': 'http', 'admin_user': 'cinder', 'service_port': '5000', 'admin_tenant_name': 'services', 'auth_port': '35357', 'auth_protocol': 'http', 'auth_uri': 'http://172.21.5.164:5000/', 'admin_password': '81641f54a6864291', 'auth_host': '172.21.5.164', 'service_host': '172.21.5.164'}
- app =
复制代码
========================================================================================
- call class cinder.api.middleware.sizelimit.RequestBodySizeLimiter
- global_config = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_config = {}
- app =
复制代码
========================================================================================
- call class cinder.api.middleware.fault.FaultWrapper
- global_config = {'__file__': '/etc/cinder/api-paste.ini', 'here': '/etc/cinder'}
- local_config = {}
- app =
复制代码
========================================================================================
我们可以看到方法pipeline_factory中确定了三个参数的具体信息后,先后调用APIRouter->CinderKeystoneContext->filter_factory->RequestBodySizeLimiter->FaultWrapper等类和方法中的factory方法,并且前一个Application作为后一个Application的输入参数,最后回到方法pipeline_factorypipeline_factory,而得到的最后的输入参数就是app= ,当然这么描述不是很准确,这里得到的app就是经过几个过滤器包装的apiv1。
好啦,分析完成了,分析的不是很深入,也不是很准确,但是挺累的哈!
作者:溜溜小哥
本文转载自:http://blog.csdn.net/gaoxingnengjisuan
|