neutron-server 启动流程
预备知识:
WSGI:一个可以在python web服务中可以广泛使用的API
PASTE:Paste Deployment用于发现和配置WSGI Application和Server,有了Paste Deployment,WSGI applications只需向其用户提供一个单独的入口loadapp函数,然后用户调用这个函数 就可以使用已经开发好的WSGI application,同时,由于只提供了一个入口,WSGI的开发者 也不再需要将App的具体实现暴露给用户,大大简化了整个开发过程。
Webob:提供了一系列的装饰器来将函数包装成WSGI应用。
架构功能划分
这张图片只是讲述了整体的框架
整体分析:
1)位于最上层的Neutron server负责接收来自外部服务的RESTful API请求
2)位于中间的Neutron plugin负责传达指令
3)位于下层的Neutron agent 负责执行具体任务和操作
组件图
图片来源于网络
框架分析
Neutron-server
Neutron只有一个主要的服务进程neutron-server,它运行在网络控制节点提供RESTfulAPI作为访问Neutron的入口。Neutron-server接收到的用户HTTP请求最终由遍布于计算节点和网络节点的各种agent来完成。
主要代码:/neutron/server
Neutron API
Neutron将基于各种虚拟网络资源得到的API资源分成核心资源(Core API)和扩展资源(Exten API)两种,Core API只对应于L2层的network、subnet、port、subnetpool四种抽象资源,其余的各层抽象都属于Exten API的范围。
代码目录:/neutron/api目录
Neutron Plugin
有core plugins 和service pulgins组成。
Core plugins:
提供基础二层网络虚拟网络支持,只要是ML2 plugin,
ML2 plugin不仅实现了network/subnet/port/subnetpool这四个核心资源和包括port binding等在内的部分扩展资源。还实现了网络拓扑类型(Flat、VLAN、VXLAN、GRE)和底层虚拟网络(Linux bridge、Open vSwitch)分离的机制。并分别通过Driver的形式扩展。其中,不同的网络拓扑类型对应着type dirver,由type manager 管理,不同的网络实现机制对应着Machansim Driver,有Mechanism Manager管理。
代码目录:neutron/plugins
Service plugin :
实现除network/subnet/port/subnetpool以外的资源。如FWaas、LBaas、VPNaas等高级服务。
代码目录:neutron/services
Message Queque
使用MessageQueque的一个模块Oslo.Messaging,Oslo.Messaging支持的MQ组件有RabbitMQ、ZeroMQ和Qpid。常用的是RabbitMQ。
Agent
执行各种具体任务和操作
服务启动分析:
stevedore 使用setupool的entry point 来定义并加载插件。
entry point目录:/neutro.egg-info目录下
文件如下图
Neutron-server
服务入口:\neutron\cmd\eventlet\server__init__.py:main()
实现代码:\neutron\services
代码分析
def _main_neutron_server():
if cfg.CONF.web_framework == 'legacy':
wsgi_eventlet.eventlet_wsgi_server()
else:
wsgi_pecan.pecan_wsgi_server()
web_framework的值是/etc/neutron/neutron.conf中的值
两个不同的wsgi_server框架,默认为evenlet模式,所以重点分析eventlet
def eventlet_wsgi_server():
neutron_api = service.serve_wsgi(service.NeutronApiService)
start_api_and_rpc_workers(neutron_api)
Service.server_wsgi主要创建一个服务并开始运行。
def serve_wsgi(cls):
try:
service = cls.create()
service.start()
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_LE('Unrecoverable error: please check log '
'for details.'))
registry.notify(resources.PROCESS, events.BEFORE_SPAWN, service)
return service
NeutronApiService继承与WsgiService,所以直接追踪WsgiService的start发现使用_run_wsgi来启动服务。
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
if not app:
LOG.error(_LE('No known API applications configured.'))
return
return run_wsgi_app(app)
def run_wsgi_app(app):
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=_get_api_workers())
LOG.info(_LI("Neutron service started, listening on %(host)s:%(port)s"),
{'host': cfg.CONF.bind_host, 'port': cfg.CONF.bind_port})
return server
## start server
def start(self, application, port, host='0.0.0.0', workers=0):
"""Run a WSGI server with the given application."""
self._host = host
self._port = port
backlog = CONF.backlog
self._socket = self._get_socket(self._host,
self._port,
backlog=backlog)
self._launch(application, workers)
下面就是到主要的_launch了
def _launch(self, application, workers=0):
service = WorkerService(self, application, self.disable_ssl, workers)
if workers < 1:
# The API service should run in the current process.
self._server = service
# Dump the initial option values
cfg.CONF.log_opt_values(LOG, logging.DEBUG)
service.start()
systemd.notify_once()
else:
# dispose the whole pool before os.fork, otherwise there will
# be shared DB connections in child processes which may cause
# DB errors.
api.context_manager.dispose_pool()
# The API service runs in a number of child processes.
# Minimize the cost of checking for child exit by extending the
# wait interval past the default of 0.01s.
self._server = common_service.ProcessLauncher(cfg.CONF,
wait_interval=1.0)
self._server.launch_service(service,
Load_paste_app从neutron.conf中得知api_paste.ini路径,并从api_paste.ini中加载WSGI app
上面只是对neutron-server的启动做了简单的分析
APIRouter
APIRouter,顾名思义,它是用来路由 API 请求的,把 API 请求真正发往那些实现功能的函数,在这里 Neutron 会加载 core plugin 和 plugin extension,扩展它的 Resource map,针对每一个资源集合(比如 networks、subnets、ports 等)建立 Controller,以后 API 将被路由到 Controller 去,Controller 再去调用对应的 create、get、update、delete 方法。同时在这里还可以做一些通用的检查,比如权限、数据有效性、自动转化数据格式等等。
代码目录:/neutron/api/v2/router.py
class APIRouter(base_wsgi.Router):
@classmethod
def factory(cls, global_config, **local_config):
return cls(**local_config)
def __init__(self, **local_config):
mapper = routes_mapper.Mapper()
manager.init()
plugin = directory.get_plugin()
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)
col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
member_actions=MEMBER_ACTIONS
)
这里简单的分析下这个APIRouter类做的事情,首先在调用时会先把core plugin启动然后就到server plugin的启动,启动完之后就会启动plugin相应的extension ,
启动完之后就会担任一个路由转发功能,将外面的HTTP请求访问的资源路由到对应的plugin下的那个extension处理。
这里对APIRouter只做一个简单的介绍,后面的文章会更加详细介绍,plugin的启动顺序,plugin和extension的创建,如何路由资源等