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:APIRouter.factory针对network、subnet、port三个资源注册了 index、create等2个collection action以及show、update、delete等3个memver action,这些action最终记录在APIRouter._plugin_handlers中:
{‘create‘: ‘create_subnet‘, ‘delete‘: ‘delete_subnet‘, ‘list‘: ‘get_subnets‘, ‘update‘: ‘update_subnet‘, ‘show‘: ‘get_subnet‘} {‘create‘: ‘create_network‘, ‘delete‘: ‘delete_network‘, ‘list‘: ‘get_networks‘, ‘update‘: ‘update_network‘, ‘show‘: ‘get_network‘} {‘create‘: ‘create_port‘, ‘delete‘: ‘delete_port‘, ‘list‘: ‘get_ports‘, ‘update‘: ‘update_port‘, ‘show‘: ‘get_port‘}
在请求进入APIRouter之前,会先经过RequestIdMiddleware(请求header中添加 openstack.request_id)、CatchErrorsMiddleware(错误处理)、keystone权限验证以及 plugin_aware_extension_middleware_factory等几个filter的处理,前三个filter比较直 观,plugin_aware_extension_middleware_factory创建了映射到plugin的处理函数:
{‘create‘: ‘create_router‘, ‘delete‘: ‘delete_router‘, ‘list‘: ‘get_routers‘, ‘update‘: ‘update_router‘, ‘show‘: ‘get_router‘}
{‘create‘: ‘create_floatingip‘, ‘delete‘: ‘delete_floatingip‘, ‘list‘: ‘get_floatingips‘, ‘update‘: ‘update_floatingip‘, ‘show‘: ‘get_floatingip‘}
{‘create‘: ‘create_agent‘, ‘delete‘: ‘delete_agent‘, ‘list‘: ‘get_agents‘, ‘update‘: ‘update_agent‘, ‘show‘: ‘get_agent‘}
参考资料
- Neutron网络简介 http://blog.ustack.com/blog/neutron_intro/
Neutron分析(2)——neutron-server启动过程分析
时间: 2024-11-07 18:38:36