介绍
Paste Deployment 是用于查找和配置WSGI应用程序和服务器的系统。 对于WSGI应用程序使用者来说,Paste Deployment提供了一个简单的函数(loadapp),用于从配置文件或Python Egg加载WSGI应用程序。 对于WSGI应用程序提供者来说,Paste Deployment只要求你的应用程序有一个简单的入口点,这样应用程序用户就不需要公开应用程序的实现细节。
安装
pip install PasteDeploy
使用介绍
与 Paste Deploy的主要交互是通过其配置文件进行的。 了解使用 paster serve命令功能查看
配置文件解说
配置文件由各个不同的部分组成。 Paste Deploy会解析包含前缀的块,格式如:app:main或
filter:errors,在冒号后面的是块的名字,前面的是类型(type)。
块内容格式是一种简单的 :name = value。 可以通过缩进后续行来扩展该值。 #是一个注释。
通常可能会有一两个名为“main”的部分:一个应用程序部分([app:main])和一个服务器部分([server:main])。 [composite:...]表示分派给多个应用程序的东西 。
下面是一个典型的配置文件,它还展示了如何挂载多个应用程序 :
[composite:main]use = egg:Paste#urlmap/ = home/blog = blog/wiki = wiki/cms = config:cms.ini[app:home]use = egg:Paste#staticdocument_root = %(here)s/htdocs[filter-app:blog]use = egg:Authentication#authnext = blogapproles = adminhtpasswd = /home/me/users.htpasswd[app:blogapp]use = egg:BlogAppdatabase = sqlite:/home/me/blog.db[app:wiki]use = call:mywiki.main:applicationdatabase = sqlite:/home/me/wiki.db
现在我将详细解释每个部分:
[composite:main]use = egg:Paste#urlmap/ = home/blog = blog/cms = config:cms.ini
这是composite
块, 它将请求分发给其他应用程序。 use = egg:Paste#urlmap是指将请求进行分发的路由映射使用Paste包中的
urlmap模块。 urlmap是一个特别常见的 composite应用程序-- 它使用路径前缀将请求映射到另一个应用程序。 如例子所示这些应用程序包括“home”、“blog”、“wiki”和“config:cms.ini”。 最后一个分发的作用是将文件指向同目录 cms.ini
文件。
[app:home]use = egg:Paste#staticdocument_root = %(here)s/htdocs
egg:Paste#static
是另一个简单的应用程序,在本例中,它只提供非动态文件。 它需要一点配置: document_root
。 可以使用变量替换,它将使用%(var_name)s记从[DEFAULT](区分大小写!)中提取变量。 特殊变量%(here)s 是包含配置文件的目录; 你应该用它来代替相对应的文件名 (依赖于当前目录,可以根据服务器的运行方式进行更改) 。
[filter-app:blog]use = egg:Authentication#authnext = blogapproles = adminhtpasswd = /home/me/users.htpasswd[app:blogapp]use = egg:BlogAppdatabase = sqlite:/home/me/blog.db
[filter-app:blog]的设置应用了过滤器。被过滤的应用程序由
next(指向下一section)指示下一步。
egg:Authentication#auth 过滤器实际上并不存在,但可以想象它会登录用户并检查权限。
[app:blogapp] 部分只是对BLogApp(可能通过pip install BlogApp安装)应用程序的引用,
database是传递给BLogApp的一个配置
[app:wiki]use = call:mywiki.main:applicationdatabase = sqlite:/home/me/wiki.db
这一节与前一节类似,但有一个重要的区别。 它直接引用mywiki.main模块的application变量, 而不是egg中的入口点。 引用由两个部分组成,由冒号分隔。 左侧是模块的全名,右侧是变量的路径,它是相对于包含模块的Python表达式。
基本用法
使用 Paste Deployment的基本方法是加载应用程序。 许多Python框架现在都支持WSGI,因此为这些框架编写的应用程序应该是可用的。
主要功能是 paste.deploy.loadapp
。 这将加载给定的URI应用程序。 如下所示:
from paste.deploy import loadappwsgi_app = loadapp('config:/path/to/config.ini')
目前支持两种URI格式:config:和egg:。
使用config:的uri:指向配置文件。 如果将 relative_to
参数传递给loadapp(),则这些文件名可以是相对的。
注意: 文件名从来不被认为是相对于当前工作目录的,因为这是一个不可预测的位置。 通常,当URI具有上下文时,它将被视为相对于该上下文;例如,如果在另一个配置文件中有一个config: URI,则该路径被认为是相对于包含该配置文件的目录的。
配置格式
配置文件采用INI格式。如下是一个简单的格式例子:
[section_name]key = valueanother key = a long value that extends over multiple lines
所有值都是字符串(不需要引号)。keys和section名是区分大小写的, 可能包含标点符号和空格(尽管keys和values都去掉了前导空格和后置空格)。 行可以用前导空格继续 。
以#开头则是注释的内容。
可以在一个文件中定义多个应用程序;每个应用程序都有自己的section。 即使只有一个应用程序,也必须将其放在一个section中。 定义 application 的每个 section名都应该以app:作为前缀。 "main" section (仅定义一个应用程序时) 将进入[app:main]或[app]。
有两种方法可以指示应用程序的Python代码。 第一种是引用另一个URI或名称:
[app:myapp]use = config:another_config_file.ini#app_name# or any URI:[app:myotherapp]use = egg:MyApp# or a callable from a module:[app:mythirdapp]use = call:my.project:myapplication# or even another section:[app:mylastapp]use = myotherapp
乍一看,这似乎毫无意义;只是一种指向另一个位置的方法。 但是,除了从该位置加载应用程序之外,还可以添加或更改配置。
另一种定义应用程序的方法是准确地指向某些Python代码(如下):
[app:myapp]paste.app_factory = myapp.modulename:app_factory
必须提供一个明确的协议(在本例中是 paste.app_factory
)。在此例子中会加载myapp.modulename模块,并引用
app_factory
对象。
关于更多工厂的定义细节请查看 。
除了use
(或协议名称)外,通过keys进行配置。 任何在section找到的keys都将作为参数传递给factory。如一所示:
[app:blog]use = egg:MyBlogdatabase = mysql://localhost/blogdbblogname = This Is My Blog!
可以在其它sections对它进行override,如:
[app:otherblog]use = blogblogname = The other face of my blog
通过这种方式,一些设置可以在一个通用配置文件中定义 (如果有 use = config:other_config_file
) , 或者您可以通过添加一个section来发布多个(更专门化的)应用程序。
通常许多应用程序共享相同的配置。 虽然您可以通过使用其他配置部分和重写值来实现这一点,但通常您希望对一组不同的配置值执行此操作。 通常 applications不能接受“额外的”配置参数;使用全局配置,可以给 applications 传递更多的参数,如电子邮件等。
Applications是单独传递全局配置的,因此它们必须明确地从中提取值;通常,当没有传递本地配置时,全局配置作为默认值的基础。
应用于文件中定义的每个 application的全局配置应该放在名为[DEFAULT]的section中。
也可以在自已的section内override全局配置,如下:
[DEFAULT]admin_email = webmaster@example.com[app:main]use = ...set admin_email = bob@example.com
"Composite" 应用程序的行为类似于应用程序,但由其他应用程序组成。 一个最普遍的例子是URL映射器,您可以将应用程序挂载在不同的URL路径上。如下所示:
[composite:main]use = egg:Paste#urlmap/ = mainapp/files = staticapp[app:mainapp]use = egg:MyApp[app:staticapp]use = egg:Paste#staticdocument_root = /path/to/docroot
除了使用app:定义应用程序section外,还可以在配置文件中使用server:和filter:前缀来定义过滤器和服务器。 使用loadserver和loadfilter加载这些程序。 配置的工作原理是一样的;只是会得到不同种类型的对象。
有几种方法可以将filters应用于applications。这主要取决于有多少个 filters,以及应用它们的顺序。
第一种方法是使用filter-with
设置,比如:
[app:main]use = egg:MyEggfilter-with = printdebug[filter:printdebug]use = egg:Paste#printdebug# and you could have another filter-with here, and so on...
另外,存在两种特殊的section类型将过滤器应用于应用程序: [filter-app:...]
和 [pipeline:...]
。 这两个sections都定义了应用程序,因此可以在需要应用程序的任何地方使用。
filter-app定义了一个过滤器(就像在[filter:...]
section 定义的一样),
特殊键next向要应用过滤器的应用程序。
pipeline:
在需要应用多个过滤器时使用。 它需要配置一个pipeline键(或加上任何想要重载的全局配置)。 pipeline是应用程序结束的过滤器列表,如下:
[pipeline:main]pipeline = filter1 egg:FilterEgg#filter2 filter3 app[filter:filter1]# ...
获取配置
如果想在不创建应用程序的情况下获得配置,可以使用appconfig(uri)函数,该函数与loadapp()函数类似,只是它返回的是字典类型的配置。
全局和本地配置都会被组合到一个字典中, 但是您可以使用.local_conf和.global_conf属性来查看。
egg
是 和 生成的一种发行版和安装格式 ,用于将元数据添加到正常的python包中(以及其他内容)。
定义
这允许您指向工厂(遵守我们提到的特定协议)。 但是,除非您可以为应用程序创建工厂,否则这没有多大用处。
有几个协议: paste.app_factory
, paste.composite_factory
, paste.filter_factory
和 paste.server_factory。
它们都需要一个可调用的东西(比如函数、方法或类)。
应用程序是最常见的。 定义app工厂如下所示:
def app_factory(global_config, **local_conf): return wsgi_app
global_config
是一个字典, local配置是作为keyword参数传递进来。此方法应返回一个 WSGI application.。
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
方法与前面的方法工作方式一样。
一个更有趣的例子可能是一个composite工厂。 例如,“ pipeline ”应用程序 :
def pipeline_factory(loader, global_config, pipeline): # space-separated list of filter and app names: pipeline = pipeline.split() filters = [loader.get_filter(n) for n in pipeline[:-1]] app = loader.get_app(pipeline[-1]) filters.reverse() # apply in reverse order! for filter in filters: app = filter(app) return app
使用方式如下:
[composite:main]use =pipeline = egg:Paste#printdebug session myapp[filter:session]use = egg:Paste#sessionstore = memory[app:myapp]use = egg:MyApp
过滤器工厂有点像应用程序工厂(相同的签名),但过滤器工厂返回过滤器外。过滤器是可调用的,它接收WSGI应用程序作为唯一参数并返回该应用程序的已过滤版本。
下面是一个过滤器的示例,它检查远程用户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 filterclass 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 factory有点相似, 但它还需要接收wsgi应用程序参数,并返回一个wsgi应用程序。 所以上面的例子修改后如下:
class AuthFilter(object): def __init__(self, app, global_conf, req_usernames): # ...
然后AuthFilter将在 filter_app_factory里提供服务 (在本例中,req_usernames
是必需的本地配置键)。
它接收与 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
的实现留给了用户。
除了 wsgi_app
作为第一个参数传递, server应该立即运行外其它的都与paste.server factory一样。
使用例子
openstack服务项目都是使用paste来部署wsgi app的,可以参考nova-api的例子,查看