Neutron分析(2)——neutron-server启动过程分析
neutron-server启动过程分析
1. /etc/init.d/neutron-server
DAEMON=/usr/bin/neutron-server
DAEMON_ARGS="--log-file=$LOGFILE"
DAEMON_DIR=/var/run
...
case $1 in
start)
test "$ENABLED" = "true" || exit 0
log_daemon_msg "Starting neutron server" "neutron-server"
start-stop-daemon -Sbmv --pidfile $PIDFILE --chdir $DAEMON_DIR --exec $DAEMON -- $DAEMON_ARGS
log_end_msg $?
;;
...
esac
2. /usr/bin/neutron-server
import sys
from neutron.server import main if __name__ == "__main__":
sys.exit(main())
3. neutron.server.main
ef main():
# the configuration will be read into the cfg.CONF global data structure
config.init(sys.argv[1:])
if not cfg.CONF.config_file:
sys.exit(_("ERROR: Unable to find configuration file via the default"
" search paths (~/.neutron/, ~/, /etc/neutron/, /etc/) and"
" the '--config-file' option!"))
try:
pool = eventlet.GreenPool() # 以协程方式启动Restful API
neutron_api = service.serve_wsgi(service.NeutronApiService)
api_thread = pool.spawn(neutron_api.wait) # 启动RPC API
try:
neutron_rpc = service.serve_rpc()
except NotImplementedError:
LOG.info(_("RPC was already started in parent process by plugin."))
else:
rpc_thread = pool.spawn(neutron_rpc.wait) # api and rpc should die together. When one dies, kill the other.
rpc_thread.link(lambda gt: api_thread.kill())
api_thread.link(lambda gt: rpc_thread.kill()) pool.waitall()
except KeyboardInterrupt:
pass
except RuntimeError as e:
sys.exit(_("ERROR: %s") % e)
4. 先看neutron.service.serve_rpc()
neutron.service.serve_rpc()最重要的工作就是启动各个插件的RpcWorker
plugin = manager.NeutronManager.get_plugin() try:
rpc = RpcWorker(plugin) if cfg.CONF.rpc_workers < 1:
rpc.start()
return rpc
else:
launcher = common_service.ProcessLauncher(wait_interval=1.0)
launcher.launch_service(rpc, workers=cfg.CONF.rpc_workers)
return launcher
而RpcWorker最重要的工作是调用plugin的start_rpc_listeners来监听消息队列:
def start(self):
# We may have just forked from parent process. A quick disposal of the
# existing sql connections avoids producing errors later when they are
# discovered to be broken.
session.get_engine().pool.dispose()
self._servers = self._plugin.start_rpc_listeners()
5. 再来看Rest API部分
service.serve_wsgi(service.NeutronApiService)
def serve_wsgi(cls):
try:
service = cls.create()
service.start()
except Exception:
with excutils.save_and_reraise_exception():
LOG.exception(_('Unrecoverable error: please check log '
'for details.'))
return service
service.start()即为self.wsgi_app = _run_wsgi(self.app_name),而该函数最重要的工作是从api-paste.ini中加载app并启动
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
if not app:
LOG.error(_('No known API applications configured.'))
return
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=cfg.CONF.api_workers)
# Dump all option values here after all options are parsed
cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
LOG.info(_("Neutron service started, listening on %(host)s:%(port)s"),
{'host': cfg.CONF.bind_host,
'port': cfg.CONF.bind_port})
return server
6. api-paste.ini
[composite:neutron]
use = egg:Paste#urlmap
/: neutronversions
/v2.0: neutronapi_v2_0 [composite:neutronapi_v2_0]
use = call:neutron.auth:pipeline_factory
noauth = request_id catch_errors extensions neutronapiapp_v2_0
keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0 [filter:request_id]
paste.filter_factory = neutron.openstack.common.middleware.request_id:RequestIdMiddleware.factory [filter:catch_errors]
paste.filter_factory = neutron.openstack.common.middleware.catch_errors:CatchErrorsMiddleware.factory [filter:keystonecontext]
paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory [filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory [filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory [app:neutronversions]
paste.app_factory = neutron.api.versions:Versions.factory [app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
实例化neutron/api/v2/router.py中的APIRouter
- class APIRouter(wsgi.Router):
- # 一个工厂类方法
- @classmethod
- def factory(cls, global_config, **local_config):
- return cls(**local_config)
- # 真正调用的实例化方法
- def __init__(self, **local_config):
- ...
- #获取NeutornManage的core_plugin,这个定义在/etc/neutron/neutron.conf,比如我的是
- #core_plugin = neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2
- plugin = manager.NeutronManager.get_plugin()
- #扫描特定路径下的extensions
- ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
- ...
- #定义的局部方法
- def _map_resource(collection, resource, params, parent=None):
- ...
- controller = base.create_resource(
- collection, resource, plugin, params, allow_bulk=allow_bulk,
- parent=parent, allow_pagination=allow_pagination,
- allow_sorting=allow_sorting)
- ...
- # 将这些resource加进router中
- return mapper.collection(collection, resource, **mapper_kwargs)
- # 遍历 {'network': 'networks', 'subnet': 'subnets','port': 'ports'}
- # 添加controller
- for resource in RESOURCES:
- _map_resource(RESOURCES[resource], resource,
- attributes.RESOURCE_ATTRIBUTE_MAP.get(
- RESOURCES[resource], dict()))
- for resource in SUB_RESOURCES:
- ...
- #其实操作和上面一个差不多,
由这个可以看出,添加的controller类型主要分为三类:(其实只要你在neutron目录下grep一下,看哪里调用了create_resource方法即可)
- OVSNeutronPluginV2
- extensions/*.py
- plugins/*.py
针对前两途径加载resource的类,下面慢慢进行描述。至于第三种,则是在各个不同的plugin内部额外实现的,不是必须的。
顺便简单的提一下,在neutron/api/extensions.py下的get_instance方法,这里其实也是和nova一样,是遍历目录下的py文件,来增加extension的
- ...
- @classmethod
- def get_instance(cls):
- if cls._instance is None:
- cls._instance = cls(get_extensions_path(),
- ... NeutronManager.get_service_plugins())
Resource:OVSNeutronPluginV2的实现
看了代码的你肯定知道,OVSNeutronPluginV2这个类,作为core_plugin继承了好多的的类
- class OVSNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2,
- external_net_db.External_net_db_mixin,
- extraroute_db.ExtraRoute_db_mixin,
- l3_gwmode_db.L3_NAT_db_mixin,
- sg_db_rpc.SecurityGroupServerRpcMixin,
- l3_agentschedulers_db.L3AgentSchedulerDbMixin,
- agentschedulers_db.DhcpAgentSchedulerDbMixin,
- portbindings_db.PortBindingMixin,
- extradhcpopt_db.ExtraDhcpOptMixin,
- addr_pair_db.AllowedAddressPairsMixin):
OVSNeutronPluginV2基本上没有什么自己的method,全靠它的"爹们"了。
随便抓两个来看下,比如NeutronDbPluginV2,他的method有get_port,create_network之类的,还有L3_NAT_db_mixin的create_router等。反正与db的操作,OVSNeutronPluginV2是不会管的,都在它的父类那边处理。
再看看OVSNeutronPluginV2继承的这些父类们:
- #NeutronDbPluginV2继承自NeutronPluginBaseV2
- class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,
- CommonDbMixin):
- class NeutronPluginBaseV2(...) :
- @abstractmethod
- def create_subnet(self, context, subnet):
- @abstractmethod
- def update_subnet(self, context, id, subnet):
- @abstractmethod
- def get_subnet(self, context, id, fields=None):
- @abstractmethod
- def get_subnets(self, context, filters=None, fields=None,
其类图如下:(仅展示部分) 
基本上可以说有一个接口类(如图中的NeutronPluginBaseV2),定义了抽象方法,然后一个具体的db类来实现(如NeutronDbPluginV2,这里是采用SQLAlchemy来完成db模型的)
plugin_aware_extension_middleware_factory
在请求进入APIRouter之前,会先经过RequestIdMiddleware(请求header中添加 openstack.request_id)、CatchErrorsMiddleware(错误处理)、keystone权限验证以及 plugin_aware_extension_middleware_factory等几个filter的处理,前三个filter比较直 观,plugin_aware_extension_middleware_factory初始化了Extension目录下的Resource:
class ExtensionMiddleware(wsgi.Middleware):
"""Extensions middleware for WSGI.""" def __init__(self, application,
ext_mgr=None):
self.ext_mgr = (ext_mgr
or ExtensionManager(get_extensions_path()))
mapper = routes.Mapper() # extended resources ext_mgr.get_resources()其实在内部会调用每个extensions目录下的extension类的get_resources方法
for resource in self.ext_mgr.get_resources():
path_prefix = resource.path_prefix
if resource.parent:
path_prefix = (resource.path_prefix +
"/%s/{%s_id}" %
(resource.parent["collection_name"],
resource.parent["member_name"])) LOG.debug(_('Extended resource: %s'),
resource.collection)
for action, method in resource.collection_actions.iteritems():
conditions = dict(method=[method])
path = "/%s/%s" % (resource.collection, action)
with mapper.submapper(controller=resource.controller,
action=action,
path_prefix=path_prefix,
conditions=conditions) as submap:
submap.connect(path)
submap.connect("%s.:(format)" % path) mapper.resource(resource.collection, resource.collection,
controller=resource.controller,
member=resource.member_actions,
parent_resource=resource.parent,
path_prefix=path_prefix) # extended actions
action_controllers = self._action_ext_controllers(application,
self.ext_mgr, mapper)
for action in self.ext_mgr.get_actions():
LOG.debug(_('Extended action: %s'), action.action_name)
controller = action_controllers[action.collection]
controller.add_action(action.action_name, action.handler) # extended requests
req_controllers = self._request_ext_controllers(application,
self.ext_mgr, mapper)
for request_ext in self.ext_mgr.get_request_extensions():
LOG.debug(_('Extended request: %s'), request_ext.key)
controller = req_controllers[request_ext.key]
controller.add_handler(request_ext.handler) self._router = routes.middleware.RoutesMiddleware(self._dispatch,
mapper)
super(ExtensionMiddleware, self).__init__(application)
比如在extensions下的securitygroup.py中的get_resources方法,看这个代码就知道其中可以处理security_group和security_group_rule两类请求了:
@classmethod
def get_resources(cls):
"""Returns Ext Resources."""
my_plurals = [(key, key[:-1]) for key in RESOURCE_ATTRIBUTE_MAP.keys()]
attr.PLURALS.update(dict(my_plurals))
exts = []
plugin = manager.NeutronManager.get_plugin()
for resource_name in ['security_group', 'security_group_rule']:
collection_name = resource_name.replace('_', '-') + "s"
params = RESOURCE_ATTRIBUTE_MAP.get(resource_name + "s", dict())
quota.QUOTAS.register_resource_by_name(resource_name)
controller = base.create_resource(collection_name,
resource_name,
plugin, params, allow_bulk=True,
allow_pagination=True,
allow_sorting=True) ex = extensions.ResourceExtension(collection_name,
controller,
attr_map=params)
exts.append(ex) return exts
如此,Neutron-Server就已经基本上启动了,无外乎就是加载配置,router各种resource,然后就等待请求了。其中router哪些resource完全是由配置文件来决定的。 当然,在启动的过程中也会初始化db,这也就是为何在安装neutron的时候无需像nova,glance等要执行db sync的原因了。
参考资料
- Neutron网络简介 http://blog.ustack.com/blog/neutron_intro/
- http://www.lnmpy.com/neutron-server-how-to-start/
Neutron分析(2)——neutron-server启动过程分析的更多相关文章
- Eureka Server启动过程分析
1.首先,SpringCloud充分利用了SpringBoot的自动装配特点 eureka-server的jar包,发现在META-INF下面的配置文件spring.factories,里面记录了Sp ...
- Neutron分析(3)—— neutron-l3-agent
一.Layer-3 Networking Extension neutron l3作为一种API扩展,向租户提供了路由和NAT功能. l3扩展包含两种资源: router:在不同内部子网中转发数据包: ...
- openstack Neutron分析(3)—— neutron-dhcp-agent源码分析
1.neutron dhcp3个主要部件分别为什么?2.dhcp模块包含哪些内容?3.Dnsmasq配置文件是如何创建和更新的?4.DHCP agent的信息存放在neutron数据库的哪个表中? 扩 ...
- ASP.Net Core MVC6 RC2 启动过程分析[偏源码分析]
入口程序 如果做过Web之外开发的人,应该记得这个是标准的Console或者Winform的入口.为什么会这样呢? .NET Web Development and Tools Blog ASP.NE ...
- 图解Android - Zygote, System Server 启动分析
Init 是所有Linux程序的起点,而Zygote于Android,正如它的英文意思,是所有java程序的'孵化池'(玩过星际虫族的兄弟都晓得的).用ps 输出可以看到 >adb shell ...
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6629298 在前面一篇文章浅谈Android系 ...
- Disconf源码分析之启动过程分析下(2)
接上文,下面是第二次扫描的XML配置. <bean id="disconfMgrBean2" class="com.baidu.disconf.client.Dis ...
- netty源码分析之一:server的启动
nio server启动的第一步,都是要创建一个serverSocketChannel,我截取一段启动代码,一步步分析: public void afterPropertiesSet() throws ...
- (3.4)mysql基础深入——mysql.server启动脚本源码阅读与分析
(3.4)mysql基础深入——mysql.server启动脚本源码阅读与分析 my.server主要分为3大部分 [1]变量初始化部分 [2]函数声明部分 [3]具体执行部分 #!/bin/sh # ...
随机推荐
- dedecms list 实现noflag
转自:http://blog.sina.com.cn/s/blog_7e53dd2b0101l3kq.html 替换include下arc.listview.class.php即可 经测试可行 但在更 ...
- 在VS2010下配置OpenCV 2.3
一.下载OpenCV 2.3: http://www.opencv.org.cn/download/OpenCV-2.3.0-win-superpack.exe 二.解压 将下载的Op ...
- 【转】SQL Server与Oracle的区别
转自:http://soft.chinabyte.com/database/255/12258255.shtml SQL Server与Oracle的区别 2012-02-10 00:00 中国IT实 ...
- SQL Server用户自定义函数
用户自定义函数不能用于执行一系列改变数据库状态的操作,但它可以像系统 函数一样在查询或存储过程等的程序段中使用,也可以像存储过程一样通过EXECUTE 命令来执行.在 SQL Server 中根据函数 ...
- JS版百度地图API
地图的构建非常简单,官方的API文档也写得很清晰,我只做一总结: 一起jquery,17jquery 一.引入JS :这个很容易理解,既然是调用JS版的百度地图,肯定得引用外部的JS文件了,而这个文件 ...
- poj3553 拓扑序+排序贪心
题意:有多个任务,每个任务有需要花费的时间和最后期限,任务之间也有一些先后关系,必须先完成某个才能开始某个,对于每个任务,如果没有越期,则超时为0,否则超时为结束时间-最后期限,求总超时时间最小的任务 ...
- 【BZOJ1007】【HNOI2008】水平可见直线
依旧看黄学长代码,不过这回是看完后自己写的 原题: 在xoy直角坐标平面上有n条直线L1,L2,...Ln,若在y值为正无穷大处往下看,能见到Li的某个子线段,则称Li为可见的,否则Li为被覆盖的.例 ...
- iPad 2升级iOS 9的过程记录
有一台老旧的iPad2,iOS版本还是5.1.1,现在好多软件都无法安装了. 决定升级到最新的操作系统,中间的过程,遇到的问题和解决办法如下: 据说升级到iOS 9以后就不好越狱了,不过我也就是用用一 ...
- 29个要点帮你完成java代码优化
通过java代码规范来优化程序,优化内存使用情况,防止内存泄露 可供程序利用的资源(内存.CPU时间.网络带宽等)是有限的,优化的目的就是让程序用尽可能少的资源完成预定的任务.优化通常包含两方面的内容 ...
- FreeSWITCH安装报错“You must install libyuv-dev to build mod_fsv”的解决方案
昨天下午安装FreeSWITCH时遇到该问题时,整了一个下午都没解决,也走了许多弯路.如果直接通过yum安装libyuv-devel时,会报错说找不到该安装包.后来又通过FreeSWITCH官网的网上 ...