wsgiref+Paste Deployment的使用


大部分Openstack项目中的api模块都采用了wsgiref+ Paste Deployment的组合。 它们的目的很简单, 是将后端程序(application)提供的服务以WSGI的方式暴露给用户使用。


Paste Deployment是一个可以查找以及配置WSGI应用程序或者服务器的系统。 当正确的配置好WSGI服务之后,用户只需要调用一个简单的方法(loadapp)就可以使用WSGI的服务,而Paste也只需要应用程序的开发者提供应用程序的入口, 对用户屏蔽应用程序的实现细节。 总的来说,Paste Deployment可以使WSGI的部署变得简单。


wsgiref 是WSGI规范在python上的一个参考实现,它可以加到现有的web程序或者框架中以使其支持WSGI服务。它提供了一些工具来操作WSGI的环境变量、头文件等来实现WSGI应用程序。


为了能更好的理解这两个python框架,下面举一个简单的能运行的例子:

我们希望提供一个WSGI服务,目前只需要提供三个接口:

        1.  http://localhost:8001   返回默认的版本

        2.  http://localhost:8001/v1  返回当前访问的版本号1

        3.  http://localhost:8001/v2  返回当前访问的版本号2

同时我们希望用户在/v1和/v2 api的时候需要传入用户的认证信息,认证通过才能继续访问api。

根据这个功能信息我们将paste deployment配置文件api-paste.ini如下:

[composite:main]
use = egg:Paste#urlmap
/: mainversions
/v1: main_api_v1
/v2: main_api_v2

[pipeline:main_api_v1]
pipeline = auth main_api_app_v1

[pipeline:main_api_v2]
pipeline = auth main_api_app_v2

[filter:auth]
paste.filter_factory = test_paste_wsgiref:auth_factory

[app:mainversions]
paste.app_factory = test_paste_wsgiref:version_app_factory

[app:main_api_app_v1]
paste.app_factory = test_paste_wsgiref:apiV1_app_factory

[app:main_api_app_v2]
paste.app_factory = test_paste_wsgiref:apiV2_app_factory

看到这个配置文件,可以理解为java 中servlet和filter在web.xml中的配置。

从下往上来解释这个配置文件可能更好理解一点,最下面三段分别定义了三个application,他们的名字分别为mainversions、main_api_app_v1、main_api_app_v2。同时,通过paste.app_factory对应的方法可以返回相应的app。

倒数第四段[filter:auth],定义了一个认证的过滤器,它将过滤掉所有没有授权的请求。

第二段和第三段定义了两个pipeline,表示在访问v1app 和v2app之前需要先进行认证操作。

第一段表示当前存在三个主api接口,其中根目录直接访问mainversions app,v1和v2需要进行pipeline的一系列操作,目前只包括两步(auth,app)


接下来就可以实现相应的application逻辑了:

import cgi
import sys
import os
from paste import deploy
from wsgiref import simple_server

class VersionSelectorApplication(object):
    def __init__(self,version = 2):
        self._version = version

    def __call__(self, environ, start_response):
        versions = 'version =' + self._version
        status = '200 OK'
        header = [('Content-type', 'text/plain')]
        start_response(status, header)
        return versions

class V1Application(object):
    def __call__(self, environ, start_response):
        result = 'call api version 1'
        status = '200 OK'
        header = [('Content-type', 'text/plain')]
        start_response(status, header)
        return result


class V2Application(object):
    def __call__(self, environ, start_response):
        result = 'call api version 2'
        status = '200 OK'
        header = [('Content-type', 'text/plain')]
        start_response(status, header)
        return result

class _MiniResp(object):
    def __init__(self, error_msg, env, headers=[]):
        self.body = [error_msg.encode()]
        self.headers = list(headers)
        self.headers.append(('Content-type', 'text/plain'))

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

    def __call__(self, environ, start_response):
        query = cgi.parse_qs(environ['QUERY_STRING'])
        username = query.get('username',[''])[0]
        password = query.get('password',[''])[0]
        if username != 'admin' or password != 'admin':
            msg = '401 UnAuthorized'
            resp = _MiniResp(msg, environ)
            start_response(msg, resp.headers)
            return resp.body
        else:
            status = '200 OK'
            return self._app(environ, start_response)

def auth_factory(global_config, **local_config):
    def auth_filter(app):
        return AuthFilter(app)
    return auth_filter

def version_app_factory(global_config, **local_config):
    return VersionSelectorApplication()

def apiV1_app_factory(global_config, **local_config):
    return V1Application()

def apiV2_app_factory(global_config, **local_config):
    return V2Application()


if  __name__ == '__main__':
    sys.path.append(os.path.abspath('.'))
    paste_file = 'api-paste.ini'
    app = deploy.loadapp("config:%s" % os.path.abspath(paste_file))
    server = simple_server.make_server('127.0.0.1', 8001, app)
    server.serve_forever()
application的实现也很简单,先看main方法,主要实现了以下几步:

1.调用loadapp来加载api-paste.ini中定义的app

2.调用make_server来创建服务WSGI的web应用程序,并关联相应的app

3.调用serve_forever表示不断的接收web请求

接着是各个factory的实现,它们都是访问相应的application类。同时,各个application类中都实现了内置的__call__方法,因为这个相应请求时默认调用的方法。其中,_MiniResp类模拟了认证失败时的响应对象。


通过对paste deployment 和wsgiref的学习,希望能对openstack中api模块有更好的了解。



参考文献:

paste deployment官网:http://pythonpaste.org/deploy/

wsgiref官网:https://docs.python.org/2/library/wsgiref.html





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值