首页 > 代码库 > Neutron分析(2)——neutron-server启动过程分析

Neutron分析(2)——neutron-server启动过程分析

neutron-server启动过程分析

1. /etc/init.d/neutron-server

DAEMON=/usr/bin/neutron-serverDAEMON_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 sysfrom neutron.server import mainif __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_factorynoauth = request_id catch_errors extensions neutronapiapp_v2_0keystone = 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/