一. 重要组件
WSGI规定应用程序必须是一个可调用的对象,且必须接收两个参数environ和start_response。
HELLO_WORLD = b"Hello world!\n"
# application函数
def wsgi_app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [HELLO_WORLD]
environ是一个字典,存储了HTTP request相关的所有内容。例如:header、请求参数等等.
start_response是一个WSGI服务器传递过来的函数,用于将response header、状态码传递给Server。调用 start_response 函数负责将响应头、状态码传递给服务器, 响应体则由application函数返回给服务器, 一个完整的http response 就由这两个函数提供。
WSGI服务器的工作就是负责接收HTTP请求,构建environ对象,然后调用application对象,最后将HTTP Response返回给浏览器。
2. PASTE(Paste Deployment):是一个针对WSGI开发的库,用来加载wsgi application和server。
openstack中配置都是通过api-paste.ini文件提供。通过这个文件可以直接调用Paste Deployment代码来加载web server和application
api-paste.ini配置文件通过配置多个filter,将url请求分发到对应的app上,类似于spring中的Service层。composite类似于controller。
#url请求分发到对应的app,use表明的是分发的方式,这里是urlmap进行分发的
[composite:neutron]
use = egg:Paste#urlmap
/: neutronversions
/v2.0: neutronapi_v2_0
[composite:neutronapi_v2_0]
noauth = cors http_proxy_to_wsgi request_id fake_project_id catch_errors osprofiler extensions neutronapiapp_v2_0
keystone = cors http_proxy_to_wsgi request_id catch_errors osprofiler authtoken keystonecontext extensions neutronapiapp_v2_0
......
[filter:request_id]
paste.filter_factory = oslo_middleware:RequestId.factory
......
[app:neutronversions]
paste.app_factory = neutron.api.versions:Versions.factory
#创建app
[app:neutronapiapp_v2_0]
#初始化neutron.api.v2.router中APIRouter.factory
paste.app_factory = neutron.api.v2.router:APIRouter.factory
以use composite为例,需要分发到neutron/auth/pipeline_factory函数去处理。接下来分析这个函数:
def pipeline_factory(loader, global_conf, **local_conf):
"""Create a paste pipeline based on the 'auth_strategy' config option."""
pipeline = local_conf[cfg.CONF.auth_strategy] #auth_strategy = “keywords” eg:keystone
pipeline = pipeline.split()
filters = [loader.get_filter(n) for n in pipeline[:-1]] #filters读取api-paste.ini中keystone的composite后的filters(从后往前读取)
app = loader.get_app(pipeline[-1]) #基于pecan web框架获取响应REST请求的application,获取的app类型为pecan.middleware.recursive.RecursiveMiddleware对象
filters.reverse() #上面split是倒序读取,reverse后变成顺序执行。
for filter in filters:
app = filter(app) #利用每一个filter封装一下app,返回最终封装的app
return app
当keyswords = keystone时,最后执行的filter是neutronapiapp_v2_0,会去neutron/api/v2/router.py中执行函数APIRouter.factory。
3. webob提供HHTP请求和相应的对象,通过包装WSGI请求环境和响应状态来实现。
在neutron中,webob提供了一系列的装饰器来将函数包装成WSGI应用。使用webob可以简化WSGI应用的开发。
class NoauthFakeProjectId(base.ConfigurableMiddleware):
"""Add fake project_id for noauth auth_strategy."""
@webob.dec.wsgify
def __call__(self, req):
ctx = context.Context.from_environ(req.environ)
if not ctx.project_id:
# Inject project_id
ctx.project_id = 'fake_project_id'
# Inject the context with the admin flag set
req.environ['neutron.context'] = ctx.elevated()
return self.application
例如:使用注解@webob.dec.wsgify包装_call_方法,这样调用类NoauthFakeProjectId的call方法就如同WSGI标准调用一样。
eg : app_iter = NoauthFakeProjectId._call_ 就相当于app_iter = NoauthFakeProjectId(environ,start_respone)
二. Neutron框架分析
主要分为Neutron Server、Neutron API、Neutron Plugin(core plugin和service plugin)、Message Queue、Agent
- Neutron Server
neutron只有一个主要的服务进程,即Neutron Server。它运行在网络控制节点。提供的RESTful API作为访Neutron的入口。Neutron Server接收到用户的HTTP请求后,由计算节点和网络节点中的各个agent来完成。
主要代码:/neutron/server
- Neutron API
Neutron将基于各种虚拟网络资源得到的API资源分为了Core API和Extension API两种。Core API只对应L2层的network、subnet、port、subnetpool四种抽象资源,其余各层的抽象都属于Extension API的范围
主要代码:/neutron/api
- Neutron Plugin
基于neutron的插件主要分为Core Plugin和services Plugin
- core plugin提供二层网络虚拟网络支持,只有ML2 plugin。ML2 plugin实现了network、subnet、port、subnetpool四种核心资源,包括port binding等在内的部分扩展资源。还实现了网络拓扑类型(FLAT、VLAN、VxLAN、GRE)以及底层虚拟网络(Linux Bridge、OpenvSwitch)分离的机制,通过Driver的形式进行扩展。不同的网络拓扑类型对应着不同的type driver,由type manager管理。不同的网络实现机制对应着不同的Mechanism Driver,由Mechanism Manager管理
主要代码:/neutron/plugins
- service Plugin实现了除core plugin四种plugins以外的资源。如FWaas、LBaas、VPNaas等服务
主要代码:/neutron/services
- Message Queue
使用Message Queue的一个模块oslo.Messaging,Oslo.Messaging支持的MQ组件有RabbitMQ、ZeroMQ和Qpid。常用的是RabbitMQ。
- Agent
负责执行各种具体的任务和操作。
三. Neutron服务启动分析
entry point用来标记各个插件和扩展的进入点。新版本中,entry point被写在文件setup.cfg中,同时用于分配url处理对象的api-paste.ini文件路径也写在setup.cfg中。
服务的启动入口在/cmd/eventlet/server/__init__.py文件中,主要是启动wsgi服务、rpc服务和api服务。
以wsgi服务启动为例:init中的代码如下:
def main():
server.boot_server(wsgi_eventlet.eventlet_wsgi_server)
代码的关键是调用了eventlet_wsgi_server方法,追踪该方法的实现:
def eventlet_wsgi_server():
neutron_api = service.serve_wsgi(service.NeutronApiService)
start_api_and_rpc_workers(neutron_api)
主要做了两件事:1. 初始化neutronapi对象; 2. 启动neutron_api服务和rpc服务。
初始化api对象会调用NeutronApiService类的creat和start方法,该类的creat继承自父类WsgiService的init。
start会执行WsgiService的_run_wsgi方法,该方法代码如下:
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
if not app:
LOG.error('No known API applications configured.')
return
return run_wsgi_app(app)
代码中,load_paste_app会通过api-paste.ini解析的结果使用load_app来加载wsgi_app列表,最后执行run_wsgi_app方法执行wsgi_app。