Neutron分析(2)——neutron-server启动过程分析
2014-07-15 13:54
197 查看
neutron-server启动过程分析
基本上可以说有一个接口类(如图中的
http://www.lnmpy.com/neutron-server-how-to-start/
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()最重要的工作就是启动各个插件的RpcWorkerplugin = 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):# 一个工厂类方法@classmethoddef 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.OVSNeutronPluginV2plugin = manager.NeutronManager.get_plugin()#扫描特定路径下的extensionsext_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'}# 添加controllerfor 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方法即可)OVSNeutronPluginV2extensions/*.pyplugins/*.py针对前两途径加载resource的类,下面慢慢进行描述。至于第三种,则是在各个不同的plugin内部额外实现的,不是必须的。顺便简单的提一下,在
neutron/api/extensions.py下的
get_instance方法,这里其实也是和nova一样,是遍历目录下的py文件,来增加extension的...@classmethoddef 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继承自NeutronPluginBaseV2class NeutronDbPluginV2(neutron_plugin_base_v2.NeutronPluginBaseV2,CommonDbMixin):class NeutronPluginBaseV2(...) :@abstractmethoddef create_subnet(self, context, subnet):@abstractmethoddef update_subnet(self, context, id, subnet):@abstractmethoddef get_subnet(self, context, id, fields=None):@abstractmethoddef 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/
相关文章推荐
- OpenStack J版 Neutron-server服务加载与启动源码分析(二)
- Openstack本学习笔记——Neutron-server服务加载和启动源代码分析(三)
- OpenStack J版 Neutron-server服务加载与启动源码分析(一)
- Openstack学习笔记之——Neutron-server服务加载与启动源码分析(三)
- Openstack L版本的neutron server 启动流程分析(二)
- openstack L版本neutron server启动分析
- OpenRTMFP/Cumulus Primer(5)CumulusServer启动流程分析(续1)
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(3)
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(4)
- Tomcat启动分析server.xml[转]
- OpenRTMFP/Cumulus Primer(4)CumulusServer启动流程分析
- OpenRTMFP/Cumulus Primer(5)CumulusServer启动流程分析(续1)
- hostapd的radius/eap server代码分析(4)-在windows下启动hostapd的radius/eap server
- HRegionServer 启动分析
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析
- OpenRTMFP/Cumulus Primer(7)CumulusServer启动流程分析(续3)
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析(2)
- OpenRTMFP/Cumulus Primer(6)CumulusServer启动流程分析(续2)
- Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析