博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Paste Deployment
阅读量:6271 次
发布时间:2019-06-22

本文共 7924 字,大约阅读时间需要 26 分钟。

hot3.png

介绍

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_factorypaste.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_filterget_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的例子,查看

 

 

 

 

 

转载于:https://my.oschina.net/jennerlo/blog/3004127

你可能感兴趣的文章
Android事件分发机制源代码分析
查看>>
《设计模式》结构型模式
查看>>
[javase学习笔记]-8.3 statickeyword使用的注意细节
查看>>
Spring集成RabbitMQ-使用RabbitMQ更方便
查看>>
Nginx 设置域名转向配置
查看>>
.net core 实现简单爬虫—抓取博客园的博文列表
查看>>
FP-Tree算法的实现
查看>>
Android 用Handler和Message实现计时效果及其中一些疑问
查看>>
Dos命令删除添加新服务
查看>>
C#.NET常见问题(FAQ)-索引器indexer有什么用
查看>>
hadoop YARN配置参数剖析—MapReduce相关参数
查看>>
Java 正则表达式详细使用
查看>>
【ADO.NET】SqlBulkCopy批量添加DataTable
查看>>
SqlServer--bat批处理执行sql语句1-osql
查看>>
Linux系列教程(十八)——Linux文件系统管理之文件系统常用命令
查看>>
laravel安装初体验
查看>>
用yum查询想安装的软件
查看>>
TIJ -- 吐司BlockingQueue
查看>>
数据库分页查询
查看>>
[编程] C语言枚举类型(Enum)
查看>>