[openstack][keystone]架构分析

首先介绍一下keystone的整体代码框架,就是:

Paste + PasteDeploy + Routes + WebOb

 

    文章整体以ubuntu14.04操作系统为平台,如果为CentOS或其他系统相关文件目录可能会有区别,请注意。

 

1、WSGI入口

 

Keystone的入口其实就是WSGI的入口,WSGI可以通过两种方式进行部署。Apache和evenlet,自然keystone也同时支持这两种方式。

对于Apache部署而言,他的文件保存在/etc/apache2/sites-available/目录下。其中,wsgi-keystone.conf是一个mod_wsgi的示例配置文件。

keystone.py则是WSGI应用程序的入口文件。文件位置为:httpd/keystone.py也就是我们要找的入口文件之一。这个文件比较简单,从中可以看到,关键的一行代码就是:

application = wsgi_server.initialize_application(name)

从中看到他创建了WSGI入口所需要使用的application对象。

而对于eventlet而言,他的部署主要是通过keystone-all命令。从setup.cfg中看到该命令的入口是:

keystone-all = keystone.cmd.all:main

找到keystone/cmd/all.py中的main函数,其中的内容证明了我们上面所述:

 

def main():

    eventlet_server.run(possible_topdir)

 

上面的main()函数主要作用是根据配置文件possible_topdir去启动一个eventlet_server。对于eventlet先介绍到这里。

下面的重点以httpd/keystone.py文件作为入口来看。

 

2、Paste和PasteDeploy

 

上述讲到keystone.py主要调用了initialize_application(name)函数来载入整个WSGI应用。这里用到了Paste和PasteDeploy库。

到keystone/server/wsgi.py中查看具体的函数。

其中config.find_paste_config()用来查找PasteDeploy需要用到的WSGI配置文件,这个文件在源码中是etc/keystone-paste.ini文件。keystone_service.loadapp()函数内部则调用了paste.deploy.loadapp()函数来加载WSGI应用,如何加载则使用了刚才提到的keystone-paste.ini文件,这个文件也是看懂整个程序的关键。

 

3、Paste.ini

      对于整个openstack而言经常会看到ini文件,下面来具体解析一下这个文件。

他由多个section组成,每个section的格式为[type:name]。

         不同type的section的不同作用也是理解这个文件的关键,主要是有这么几个type:

Composite:用于将http请求分发给制定的app。这个的关键字use = egg:Paste#urlmap标示到Paste模块的egg-info中寻找urlmap对应的函数。其中不同URL path前缀,把请求路由给不同的app。比如/v2.0=public_api,标示以/v2.0开头的url会路由给public_api处理。路由的对象即为其他section的名字,类型必须为app或者pipline。

Pipline:将一系列filter和app串联起来。其中的关键字为其他section的名字。其中有一个规则为最后一项必须是一个app,而其他项都为filter。

Filter:实现一个过滤器中间件,过滤请求和响应。其中的关键字表明调用哪个函数来获取这个filter中间件。比如:

[filter:debug]

paste.filter_factory = keystone.common.wsgi:Debug.factory

调用的即为keystone/common/wsgi.py中的classDebug(Middleware):。

从中可以看到这个类是以WSGI中间件的方式实现。

App:表示具体的一个app,为一个标准的WSGI application。其中的关键字也为调用哪个函数来获取这个app。

         整一套keystone有两个app,admin和main。在实际部署过程中,httpd/keystone.py会重命名为admin.py或main.py。其中admin来监听35357端口,main来监听5000端口。

         所以总结来说paste.ini中这一大堆配置的作用就是把我们用Python写的WSGI application和middleware串起来,规定好HTTP请求处理的路径。

在上述的application =wsgi_server.initialize_application(name)存在一个name变量,这个变量来确定入口,在Keystone的paste.ini中,请求必须先由[composite:main]或者[composite:admin]处理,所以在keystone项目中,name的值必须是main或者admin。

举一个例子: POST http://localhost:35357/v3/auth/tokens

发到keystone获取一个token时是如何操作的?大致流程就是解析这个URL:

(1)       hostname:35357 这一部分是由Web服务器处理的,比如Apache。然后,请求会被转到WSGI的入口,也就是httpd/keystone.py中的application对象来处理。

(2)       application对象是根据paste.ini中的配置来处理的。这里会先由[composite:admin]来处理(一般是admin监听35357端口,main监听5000端口)。

(3)       [composite:admin]发现请求的path是/v3开头的,于是就把请求转发给[pipeline:api_v3]去处理,转发之前,会把/v3这个部分去掉。

(4)       [pipeline:api_v3]收到请求,path是/auth/tokens,然后开始调用各个filter来处理请求。最后会把请求交给[app:service_v3]进行处理。

(5)      [app:service_v3]收到请求,path是/auth/tokens,http请求的方法为POST然后交给最终的WSGI app去处理。

4、中间件(Middleware)

         Middleware是WSGI架构中重要的组成部分。同时具备Server和application的角色。

从代码上来讲,上述的中间件实际是调用Middleware作为基类的。这边主要是一个__call__()方法。

@webob.dec.wsgify()

    def __call__(self, request):

        try:

            response =self.process_request(request)

            if response:

                return response

            response =request.get_response(self.application)

            return self.process_response(request,response)

        except exceptin.Error as e:

从代码中可以看到,他的实现主要是接受一个request对象,然后返回一个response对象。然后使用WebOB模块的装饰器webob.dec.wsgify()将它变成标准的WSGI application接口。这里的request和response对象分别是webob.Request和webob.Response。

 

5、Routes

         上述的URL还剩下/auth/tokens来实现URL路由。这边就要使用Routes模块。

         Routes模块是用Python实现的类似Rails的URL路由系统,它的主要功能就是把path映射到对应的动作。

         Routes模块的一般用法是创建一个Mapper对象,然后调用该对象的connect()方法把path和method映射到一个controller的某个action上,这里controller是一个自定义的类实例,action是表示controller对象的方法的字符串。一般调用的时候还会指定映射哪些方法,比如GET或者POST之类的。

 

总结一下:整个keystone的代码流程其实就是解析整个URL的过程。通过ini文件进行解析,根据不同的version找到不同的factory,路径为keystone/service.py。然后找到具体的执行内容。整个keystone根据文件名来进行区分,比较方便查找。找到之后根据各个controller.py

core.pyrouters.py三个文件来进行具体的处理。其中routers.py实现URL路由,把URL和controller.py中的action对应起来。Controllers.py中的action调用core.py中的底层接口实现RESTfulAPI承诺的功能。Core.py中定义了Manager类和Driver类。其中Manager负责基于不同的Backend Driver对请求进一步处理。

你可能感兴趣的:(openstack)