PS:本篇是关于neutron server启动的
neutron-server的启动命令如下:
42435 519598 0.0 0.0 371240 137840 ? S Oct17 4:01 /var/lib/kolla/venv/bin/python /var/lib/kolla/venv/bin/neutron-server --config-file /etc/neutron/neutron.conf --config-file /etc/neutro
n/plugins/ml2/ml2_conf.ini --config-file /etc/neutron/neutron_lbaas.conf --config-file /etc/neutron/neutron_aas.conf --config-file /etc/neutron/fwaas_driver.ini
开始分析整个代码流程
只是做了一件事情,引用了cmd.eventlet.server的main方法,再调用
from neutron.cmd.eventlet.server import main
main方法中只是调用了boot_server函数
def main():
server.boot_server(wsgi_eventlet.eventlet_wsgi_server)
boot_server函数主要是加载配置文件,配置日志,最终调用server_func() ,也就是 wsgi_eventlet.eventlet_wsgi_server
def _init_configuration():
# the configuration will be read into the cfg.CONF global data structure
conf_files = _get_config_files()
config.init(sys.argv[1:], default_config_files=conf_files)
config.setup_logging()
config.set_config_defaults()
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!"))
def boot_server(server_func):
_init_configuration()
try:
server_func()
except KeyboardInterrupt:
pass
except RuntimeError as e:
sys.exit(_("ERROR: %s") % e)
从上面可以看出,neutron加载了配置开启日之后最终直接通过eventlet启动wsgi服务, 启动了api和rpc服务。serve_wsgi 函数中传入neutronApiService,
def eventlet_wsgi_server():
neutron_api = service.serve_wsgi(service.NeutronApiService)
start_api_and_rpc_workers(neutron_api)
def start_api_and_rpc_workers(neutron_api):
try:
worker_launcher = service.start_all_workers()
pool = eventlet.GreenPool()
api_thread = pool.spawn(neutron_api.wait)
plugin_workers_thread = pool.spawn(worker_launcher.wait)
# api and other workers should die together. When one dies,
# kill the other.
api_thread.link(lambda gt: plugin_workers_thread.kill())
plugin_workers_thread.link(lambda gt: api_thread.kill())
pool.waitall()
except NotImplementedError:
LOG.info("RPC was already started in parent process by "
"plugin.")
neutron_api.wait()
neutron/service.py
serve_wsgi 传入cls,然后直接调用对于cls的create函数并start启动,这里代指NeutronApiService class的create和start
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.')
registry.publish(resources.PROCESS, events.BEFORE_SPAWN, service)
return service
NeutronApiService继承了WsgiService,本质上是一个wsgi 服务,实现了create和start等功能
class WsgiService(object):
"""Base class for WSGI based services.
For each api you define, you must also define these flags:
:_listen: The address on which to listen
:_listen_port: The port on which to listen
"""
def __init__(self, app_name):
self.app_name = app_name
self.wsgi_app = None
def start(self):
self.wsgi_app = _run_wsgi(self.app_name)
def wait(self):
self.wsgi_app.wait()
class NeutronApiService(WsgiService):
"""Class for neutron-api service."""
def __init__(self, app_name):
profiler.setup('neutron-server', cfg.CONF.host)
super(NeutronApiService, self).__init__(app_name)
@classmethod
def create(cls, app_name='neutron'):
# Setup logging early
config.setup_logging()
service = cls(app_name)
return service
start 服务时, 调用了_run_wsgi, 通过paster.deploy 创建了neutron的app, 最终调用 run_wsgi_app ,
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
if not app:
LOG.error('No known API applications configured.')
return
return run_wsgi_app(app)
run_wsgi_app() 函数最终构造了一个wsgi Server实例,名字为Neutron,start函数中传入监听地址和端口号以及worker数量
def run_wsgi_app(app):
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=_get_api_workers(), desc="api worker")
LOG.info("Neutron service started, listening on %(host)s:%(port)s",
{'host': cfg.CONF.bind_host, 'port': cfg.CONF.bind_port})
return server
start 函数中调用 _get_socket 通过eventlet listen了相关端口。最后调用launch ,worker数量肯定大于1,else里面先初始化了数据库连接,并fork子进程
def start(self, application, port, host='0.0.0.0', workers=0, desc=None):
"""Run a WSGI server with the given application."""
self._host = host
self._port = port
backlog = CONF.backlog
self._socket = self._get_socket(self._host,
self._port,
backlog=backlog)
self._launch(application, workers)
def _launch(self, application, workers=0, desc=None):
set_proctitle = "off" if desc is None else CONF.setproctitle
service = WorkerService(self, application, set_proctitle,
self.disable_ssl, workers)
if workers < 1:
# The API service should run in the current process.
self._server = service
# Dump the initial option values
cfg.CONF.log_opt_values(LOG, logging.DEBUG)
service.start(desc=desc)
systemd.notify_once()
else:
# dispose the whole pool before os.fork, otherwise there will
# be shared DB connections in child processes which may cause
# DB errors.
db_api.get_context_manager().dispose_pool()
# The API service runs in a number of child processes.
# Minimize the cost of checking for child exit by extending the
# wait interval past the default of 0.01s.
self._server = common_service.ProcessLauncher(
cfg.CONF, wait_interval=1.0, restart_method='mutate')
self._server.launch_service(service,
workers=service.worker_process_count)
至此neutron server启动完成