server

实现neutron-server的主进程。

init.py文件中包括一个main()函数,是WSGI服务器开始的模块,并且通过调用serve_wsgi来创建一个NeutronApiService的实例。然后通过eventlet的greenpool来运行WSGI的应用程序,响应来自客户端的请求。
主要过程为:

  1. eventlet.monkey_patch()

绿化各个模块为支持协程(通过打补丁的方式让本地导入的库都支持协程)。

  1. config.parse(sys.argv[1:])
  2. if not cfg.CONF.config_file:
  3. sys.exit(_("ERROR: Unable to find configuration file via the default"
  4. " search paths (~/.neutron/, ~/, /etc/neutron/, /etc/) and"
  5. " the '--config-file' option!"))

通过解析命令行传入的参数,获取配置文件所在。

  1. pool = eventlet.GreenPool()

创建基于协程的线程池。

  1. neutron_api = service.serve_wsgi(service.NeutronApiService)
  2. api_thread = pool.spawn(neutron_api.wait)

serve_wsgi方法创建NeutronApiService实例(作为一个WsgiService),并调用其的start()来启动socket服务器端。

  1. #neutron.service
  2. def serve_wsgi(cls):
  3. try:
  4. service = cls.create()
  5. service.start()
  6. except Exception:
  7. with excutils.save_and_reraise_exception():
  8. LOG.exception(_('Unrecoverable error: please check log '
  9. 'for details.'))
  10. return service

neutron.service.NeutronApiService类继承自neutron.service.WsgiService,其create方法返回一个appname默认为“neutron”的WsgiService对象;start方法则调用_run_wsgi方法。

  1. def start(self):
  2. self.wsgi_app = _run_wsgi(self.app_name)

_run_wsgi方法主要是从api-paste.ini文件中读取应用(最后是利用neutron.api.v2.router:APIRouter.factory来构造应用),然后为应用创建一个wsgi的服务端,并启动应用,主要代码为。

  1. def _run_wsgi(app_name):
  2. app = config.load_paste_app(app_name)
  3. if not app:
  4. LOG.error(_('No known API applications configured.'))
  5. return
  6. server = wsgi.Server("Neutron")
  7. server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
  8. workers=cfg.CONF.api_workers)
  9. # Dump all option values here after all options are parsed
  10. cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
  11. LOG.info(_("Neutron service started, listening on %(host)s:%(port)s"),
  12. {'host': cfg.CONF.bind_host,
  13. 'port': cfg.CONF.bind_port})
  14. return server

至此,neutron server启动完成,之后,需要创建rpc服务端。

  1. try:
  2. neutron_rpc = service.serve_rpc()
  3. except NotImplementedError:
  4. LOG.info(_("RPC was already started in parent process by plugin."))
  5. else:
  6. rpc_thread = pool.spawn(neutron_rpc.wait)
  7. rpc_thread.link(lambda gt: api_thread.kill())
  8. api_thread.link(lambda gt: rpc_thread.kill())

这些代码创建plugin的rpc服务端,并将api和rpc的生存绑定到一起,一个死掉,则另外一个也死掉。

  1. pool.waitall()

最后是后台不断等待。

下面的图表总结了neutron-server的核心启动过程。

neutron.server neutron.service#serve_wsgi() neutron.service.NeutronApiService neutron.service.WsgiService neutron.service#_run_wsgi()
neutron_api = service.serve_wsgi(service.NeutronApiService) service = cls.create(); service.start() service = cls(app_name=’neutron’) self.wsgi_app = _run_wsgi(self.app_name) app = config.load_paste_app(app_name); server = wsgi.Server(“Neutron”); server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host, workers=cfg.CONF.api_workers)