nova的wsgi介绍【WIP】
有关openstack的所有的帖子。
https://www.ustack.com/blog/openstack_hacker/#Nova_Workflow
网上已经很多的分析文章了:
http://blog.csdn.net/ddl007/article/details/8602731?utm_source=tuicool
http://wenku.baidu.com/view/34892729af45b307e87197ec.html
今天liyong同学问起pecan的原理。
有必要写篇博客介绍, nova的wsgi。
改博客边走读代码,边写,是一个野路子开发者的流程。
不习惯使用 tox.
$ cat /usr/bin/pyunittest
python -m unittest `tr / . <<< ${@%.py*}`
1. 首先对wsgi有个形象的了解:
nova/tests/unit/api/test_wsgi.py
"""
Test WSGI basics and provide some helper functions for other WSGI tests.
""" from nova import test import routes
import webob from nova import wsgi class Test(test.NoDBTestCase): def test_debug(self): class Application(wsgi.Application):
"""Dummy application to test debug.""" def __call__(self, environ, start_response):
start_response("", [("X-Test", "checking")])
return ['Test result'] application = wsgi.Debug(Application())
result = webob.Request.blank('/').get_response(application)
self.assertEqual(result.body, "Test result") def test_router(self): class Application(wsgi.Application):
"""Test application to call from router.""" def __call__(self, environ, start_response):
start_response("", [])
return ['Router result'] class Router(wsgi.Router):
"""Test router.""" def __init__(self):
mapper = routes.Mapper()
mapper.connect("/test", controller=Application())
super(Router, self).__init__(mapper) result = webob.Request.blank('/test').get_response(Router())
self.assertEqual(result.body, "Router result")
result = webob.Request.blank('/bad').get_response(Router())
self.assertNotEqual(result.body, "Router result")
自己可以print打桩,了解有疑惑的代码。 然后运行。
$ pyunittest nova/tests/unit/api/test_wsgi.py
查看wsgi的实现。
$ git grep -n3 "class Router"
--
nova/wsgi.py-440- print()
nova/wsgi.py-441-
nova/wsgi.py-442-
nova/wsgi.py:443:class Router(object):
nova/wsgi.py-444- """WSGI middleware that maps incoming requests to WSGI apps."""
nova/wsgi.py-445-
nova/wsgi.py-446- def __init__(self, mapper):
class Router(object):
"""WSGI middleware that maps incoming requests to WSGI apps.""" def __init__(self, mapper):
"""Create a router for the given routes.Mapper. Each route in `mapper` must specify a 'controller', which is a
WSGI app to call. You'll probably want to specify an 'action' as
well and have your controller be an object that can route
the request to the action-specific method. Examples:
mapper = routes.Mapper()
sc = ServerController() # Explicit mapping of one route to a controller+action
mapper.connect(None, '/svrlist', controller=sc, action='list') # Actions are all implicitly defined
mapper.resource('server', 'servers', controller=sc)
# Pointing to an arbitrary WSGI app. You can specify the
# {path_info:.*} parameter so the target app can be handed just that
# section of the URL.
mapper.connect(None, '/v1.0/{path_info:.*}', controller=BlogApp()) """
self.map = mapper
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
self.map) @webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
"""Route the incoming request to a controller based on self.map. If no match, return a 404. """
return self._router @staticmethod
@webob.dec.wsgify(RequestClass=Request)
def _dispatch(req):
"""Dispatch the request to the appropriate controller. Called by self._router after matching the incoming request to a route
and putting the information into req.environ. Either returns 404
or the routed WSGI app's response. """
match = req.environ['wsgiorg.routing_args'][1]
if not match:
return webob.exc.HTTPNotFound()
app = match['controller']
return app
routes.middleware.RoutesMiddleware的帮助文档。
Constructor information:
Definition:routes.middleware.RoutesMiddleware(self, wsgi_app, mapper, use_method_override=True, path_info=True, singleton=True)
Docstring:
Create a Route middleware object Using the use_method_override keyword will require Paste to be
installed, and your application should use Paste's WSGIRequest
object as it will properly handle POST issues with wsgi.input
should Routes check it. If path_info is True, then should a route var contain
path_info, the SCRIPT_NAME and PATH_INFO will be altered
accordingly. This should be used with routes like: .. code-block:: python map.connect('blog/*path_info', controller='blog', path_info='')
文档中明确说明: use Paste's WSGIRequest
nova/wsgi.py 实现了load app功能, 从
class Loader(object):
"""Used to load WSGI applications from paste configurations.""" def __init__(self, config_path=None):
"""Initialize the loader, and attempt to find the config. :param config_path: Full or relative path to the paste config.
:returns: None """
self.config_path = None config_path = config_path or CONF.api_paste_config
if not os.path.isabs(config_path):
self.config_path = CONF.find_file(config_path)
elif os.path.exists(config_path):
self.config_path = config_path if not self.config_path:
raise exception.ConfigNotFound(path=config_path) def load_app(self, name):
"""Return the paste URLMap wrapped WSGI application. :param name: Name of the application to load.
:returns: Paste URLMap object wrapping the requested application.
:raises: `nova.exception.PasteAppNotFound` """
try:
LOG.debug("Loading app %(name)s from %(path)s",
{'name': name, 'path': self.config_path})
return deploy.loadapp("config:%s" % self.config_path, name=name)
except LookupError:
LOG.exception(_LE("Couldn't lookup app: %s"), name)
raise exception.PasteAppNotFound(name=name, path=self.config_path)
至于 server 怎么加载wsgi的,请参考:
nova/tests/unit/test_wsgi.py
$ pyunittest nova/tests/unit/test_wsgi.TestWSGIServerWithSSL.test_ssl_server
最终urlmap的事情交给 paste
请参考:
http://blog.csdn.net/sonicatnoc/article/details/6539716
一以下纯拷贝:
首先python paste是一个WSGI工具包,在WSGI的基础上包装了几层,让应用管理和实现变得方便。说实话,Python Paste的文档做的真差劲!加之python代码可读性本来就不怎么滴,真费劲。
paste.deploy关键部分留个抓印:
1)python paste.deploy不能只装个paste.deploy包就可以工作了,还需要paste.script包
2)python paste.deploy中loadapp给的路径可用os.path.abspath(配置文件相对路径)得到配置文件的绝对路径,否则报找不到relative_to path...没搞明白怎么回事,目前不重要,放过。
3)python paste.deploy中filter,filter_factory,app,app_factory的规范在文档中都没怎么写清楚,我来给你补上吧:
- app是一个callable object,接受的参数(environ,start_response),这是paste系统交给application的,符合
WSGI规范的参数. app需要完成的任务是响应envrion中的请求,准备好响应头和消息体,然后交给start_response处理,并返回响应消息体。
- filter是一个callable object,其唯一参数是(app),这是WSGI的application对象,见(1),filter需要完成的工作是将application包 装成另一个application(“过滤”),并返回这个包装后的application。
- app_factory是一个callable object,其接受的参数是一些关于application的配置信息:(global_conf,**kwargs),global_conf是在 ini文件中default section中定义的一系列key-value对,而**kwargs,即一些本地配置,是在ini文件中,app:xxx section中定义的一 系列key-value对。app_factory返回值是一个application对象
- filter_factory是一个callable object,其接受的参数是一系列关于filter的配置信息:(global_conf,**kwargs),global_conf是在ini文件 中default section中定义的一系列key-value对,而**kwargs,即一些本地配置,是在ini文件中,filter:xxx section中定 义的一系列key-value对。filter_factory返回一个filter对象
给个例子:
pastedeploylab.ini:
[DEFAULT]
key1=value1
key2=value2
key3=values
[composite:pdl]
use=egg:Paste#urlmap
/:root
/calc:calc
[pipeline:root]
pipeline = logrequest showversion
[pipeline:calc]
pipeline = logrequest calculator
[filter:logrequest]
username = root
password = root123
paste.filter_factory = pastedeploylab:LogFilter.factory
[app:showversion]
version = 1.0.0
paste.app_factory = pastedeploylab:ShowVersion.factory
[app:calculator]
description = This is an "+-*/" Calculator
paste.app_factory = pastedeploylab:Calculator.factory
pastedeploylab.py
'''''
Created on 2011-6-12
@author: Sonic
'''
import os
import webob
from webob import Request
from webob import Response
from paste.deploy import loadapp
from wsgiref.simple_server import make_server
#Filter
class LogFilter():
def __init__(self,app):
self.app = app
pass
def __call__(self,environ,start_response):
print "filter:LogFilter is called."
return self.app(environ,start_response)
@classmethod
def factory(cls, global_conf, **kwargs):
print "in LogFilter.factory", global_conf, kwargs
return LogFilter
class ShowVersion():
def __init__(self):
pass
def __call__(self,environ,start_response):
start_response("200 OK",[("Content-type", "text/plain")])
return ["Paste Deploy LAB: Version = 1.0.0",]
@classmethod
def factory(cls,global_conf,**kwargs):
print "in ShowVersion.factory", global_conf, kwargs
return ShowVersion()
class Calculator():
def __init__(self):
pass def __call__(self,environ,start_response):
req = Request(environ)
res = Response()
res.status = "200 OK"
res.content_type = "text/plain"
# get operands
operator = req.GET.get("operator", None)
operand1 = req.GET.get("operand1", None)
operand2 = req.GET.get("operand2", None)
print req.GET
opnd1 = int(operand1)
opnd2 = int(operand2)
if operator == u'plus':
opnd1 = opnd1 + opnd2
elif operator == u'minus':
opnd1 = opnd1 - opnd2
elif operator == u'star':
opnd1 = opnd1 * opnd2
elif operator == u'slash':
opnd1 = opnd1 / opnd2
res.body = "%s /nRESULT= %d" % (str(req.GET) , opnd1)
return res(environ,start_response)
@classmethod
def factory(cls,global_conf,**kwargs):
print "in Calculator.factory", global_conf, kwargs
return Calculator() if __name__ == '__main__':
configfile="pastedeploylab.ini"
appname="pdl"
wsgi_app = loadapp("config:%s" % os.path.abspath(configfile), appname)
server = make_server('localhost',8088,wsgi_app)
server.serve_forever()
pass
使用:
http://127.0.0.1:8080/
输出:
Paste Deploy LAB: Version = 1.0.0
http://127.0.0.1:8080/calc?operator=plus&operand1=12&operand2=23
输出:
UnicodeMultiDict([('operator', u'plus'), ('operand1', u'12'), ('operand2', u'23')])
RESULT= 35
====================================================
进一步猜测filter的使用过程:在paste deploy库中应该有类似这样的一段代码对application进行重组包装:
#
# 假设在ini文件中, 某条pipeline的顺序是filter1, filter2, filter3
# app, 那么,最终运行的app_real是这样组织的:
# app_real = filter1(filter2(filter3(app))) # 在app真正被调用的过程中,filter1.__call__(environ,start_response)被首先调用,若某种检查未通过,filter1做出反应;否则交给filter2__call__(environ,start_response)进一步处理,若某种检查未通过,filter2做出反应,中断链条,否则交给filter3.__call__(environ,start_response)处理,若filter3的某种检查都通过了,最后交给app.__call__(environ,start_response)进行处理。
看到令贤写了一篇更简单的。
http://blog.csdn.net/lynn_kong/article/details/8818005
nova的wsgi介绍【WIP】的更多相关文章
- 在Openstack H版部署Nova Cell 时 ,终端输入nova service-list 和 nova host-list 命令将报错
关于Cell的基本介绍,可以参考贤哥的一篇文章: [OpenStack]G版中关于Nova的Cell http://blog.csdn.net/lynn_kong/article/details/8 ...
- OpenStack Restful API框架介绍
1 pecan框架介绍 1.1 什么是pecan pecan是一个轻量级的python web框架,最主要的特点是提供了简单的配置即可创建一个wsgi对象并提供了基于对象的路由方式. 主要提供的功 ...
- ERROR (ClientException) nova image-list
nova image-listERROR (ClientException): The server has either erred or is incapable of performi9e-6c ...
- Nova 无法向虚机注入密钥
欢迎各位关注我的博客:http://weibo.com/u/216633637 废话开头: 之前参考这位同学的博客http://www.cnblogs.com/awy-blog/p/3447176.h ...
- 具体解释EBS接口开发之WIP模块接口
整体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对採用并发请求方式和调用API方式分别进行介绍 内容 WIP模块经常使用标准表简单介绍 WIP事物处理组成 WIP相关业务流程 W ...
- 【openstack N版】——计算服务nova
一.openstack计算服务nova 1.1nova介绍 Nova是openstack最早的两块模块之一,另一个是对象存储swift.在openstack体系中一个叫做计算节点,一个叫做控制节点.这 ...
- Django SimpleCMDB WSGI
一.WSGI 介绍 (1) 在前面的学习中,我们是通过 python manage.py runserver 0.0.0.0:8000 来启动并访问开发服务器的:(2) 但在实际中我们是通过直接访问 ...
- OpenStack之Nova模块
Nova简介 nova和swift是openstack最早的两个组件,nova分为控制节点和计算节点,计算节点通过nova computer进行虚拟机创建,通过libvirt调用kvm创建虚拟机,no ...
- Python归纳 | WSGI协议
1.WSGI介绍 1.1什么是WSGI 1.2怎么实现WSGI 2.由Django框架分析WSGI 3.实际环境使用的wsgi服务器 4.WSGI服务器比较
随机推荐
- Python学习笔记(二)Python的数据类型和变量
Python的字符串 Python使用''和""将字符串括起来,与ruby类似,特殊之处是Python可以使用r''表示''内部的字符串默认不转义,如: print(r'\\\t\ ...
- CSS随记
在CSS中,任何元素都可以浮动.浮动元素会生成一个块级框,而不论它本身是何种元素.如果浮动非替换元素,则要指定一个明确的宽度:否则,它们会尽可能地窄. 注释:float属性不具有继承特性,就是说子元素 ...
- C# 堆栈的数据结构 (二)
堆栈是一种常用的数据结构,并且是线性表操作的子集,即操作受限的线性表.因此需要用到Clist 线性表类 public class CStack { private Clist m_List;//创建链 ...
- 论山寨手机与Android联姻的技术基础 【序】
山寨手机的兴起,离不开 MTK(联发科).MTK为手机制造提供了一揽子解决方案,其中既包括硬件,也包括软件.软件方面最重要的,是操作系统.MTK方案的软件的稳定性非常高,一方面是因为其硬件系统变化不大 ...
- 【Daily】 2014-4-23
KEEP GOING Think more product when face difference Check value null when insert/remove/update/add ch ...
- 适合入门自学服装裁剪滴书(更新ing)
[♣]适合入门自学服装裁剪滴书(更新ing) [♣]适合入门自学服装裁剪滴书(更新ing) 适合入门自学服装裁剪滴书(更新ing) 来自: 裁缝阿普(不为良匠,便为良医.) 2014-04-06 23 ...
- Spring、实例化Bean的三种方法
1.使用类构造器进行实例化 <bean id="personIService" class="cn.server.impl.PersonServiceImpl&qu ...
- #include <QPushButton>
类QPushButton 命令按钮 #include "mainwindow.h" #include <QApplication> int main(int argc, ...
- 如何在TableView上添加悬浮按钮
如果直接在TableVIewController上贴Button的话会导致这个会随之滚动,下面解决在TableView上实现位置固定悬浮按钮的两种方法: 1.在view上贴tableView,然后将悬 ...
- 不同版本的 IIS 中使用 ASP.NET MVC(C#)【转】
由微软 ASP.NET 团队|2008 年 8 月 19 日 推特 在本教程中,您将学习在不同版本的 Internet Information Services 中如何使用 ASP.NET MVC 和 ...