OpenStack J版 Neutron-server服务加载与启动源码分析(一)

声明:

本博客欢迎转载,但请保留原作者信息!

作者:林凯

团队:华为杭州OpenStack研发团队

 

本文是在学习Openstack的过程中整理和总结,由于时间和个人能力有限,错误之处在所难免,欢迎指正!

    之前对于服务的加载与启动一直没有找到真正的源头,这次就来分析neutron真正是从哪里开始,并加载服务并启动的,在这里首先看Neutron-server的服务加载和启动。

 

1)查看/usr/bin/neutron-server脚本中的内容

主要作用调用neutron.servermain(),启动相关线程之后退出。

from neutron.server import main
if __name__ == "__main__":
sys.exit(main())

 

(2)main函数主要的内容

def main():
    try:
        pool =eventlet.GreenPool()  #建立一个事件的绿池(绿色线程池)
              #创建NeutronApiService的wsgi服务,并从线程池中spawn一个线程来监听api请求
       neutron_api = service.serve_wsgi(service.NeutronApiService)
        api_thread= pool.spawn(neutron_api.wait)
 
        try:
           neutron_rpc = service.serve_rpc()
        exceptNotImplementedError:
           LOG.info(_("RPC was already started in parent process byplugin."))
        else:
           rpc_thread = pool.spawn(neutron_rpc.wait)
 
            # apiand rpc should die together.  When onedies, kill the other.
           rpc_thread.link(lambda gt: api_thread.kill())
           api_thread.link(lambda gt: rpc_thread.kill())
 
       pool.waitall() 

在这里我们仔细分析wsgi 服务是怎么样被加载并启动服务的。

def serve_wsgi(cls):
 
    try:
        service =cls.create()
       service.start()
    exceptException:
        withexcutils.save_and_reraise_exception():
           LOG.exception(_('Unrecoverable error: please check log '
                            'for details.'))
 
    return service


首先调用的是service.NeutronApiService的create函数

class NeutronApiService(WsgiService):
    @classmethod
    defcreate(cls, app_name='neutron'):
       config.setup_logging()
        # Dump the initial option values
       cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
        service =cls(app_name)
        return service

create 函数进行日志的安装和配置文件的映射。回到上面调用 service.start(),NeutronApiService中没有start()函数,所以他调用的是父类的start的函数,也就是WsgiService这个类中的start函数。

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

继续看下 _run_wsgi中的东西

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 alloption 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

首先来看第一个函数 load_paste_app(app_name)

def load_paste_app(app_name):

   """Builds and returns a WSGI app from a paste configfile.
 
    :paramapp_name: Name of the application to load
    :raisesConfigFilesNotFoundError when config file cannot be located
    :raisesRuntimeError when application cannot be loaded from config file
   """
 
    config_path =cfg.CONF.find_file(cfg.CONF.api_paste_config)
    if notconfig_path:
        raisecfg.ConfigFilesNotFoundError(
           config_files=[cfg.CONF.api_paste_config])
    config_path =os.path.abspath(config_path)
   LOG.info(_("Config paste file: %s"), config_path)
 
    try:
        app =deploy.loadapp("config:%s" % config_path, name=app_name)
    except(LookupError, ImportError):
        msg =(_("Unable to load %(app_name)s from "
                "configuration file %(config_path)s.") %
              {'app_name': app_name,
               'config_path': config_path})
       LOG.exception(msg)
        raiseRuntimeError(msg)
    return app

 

调试可以看到config_path指向/etc/neutron/api-paste.ini,neutron通过解析api-paste.ini中的配置信息来进行指定WSGI Application的实现。这里可以看到,在方法load_app中,调用了模块库deploy来实现对api-paste.ini中配置信息的解析和指定WSGI Application的实现。

【注】:

       PasteDeployment是一种机制或者说是一种设计模式,它用于在应用WSGI Application和Server提供一个联系的桥梁,并且为用户提供一个接口,当配置好PasteDeployment之后,用户只需调用loadapp方法就可以使用现有的WSGI Application,而保持了WSGI Application对用户的透明性。

我们可以看到neutron/ 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 extensionsneutronapiapp_v2_0
keystone= request_id catch_errors authtokenkeystonecontext extensionsneutronapiapp_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

通过对 api-paste.ini中配置信息的解析,最终就调用了WSGIApplicationapiv2的实现,具体就是neutron.api.v2.router:APIRouter.factory,这个WSGI Application的具体功能就是实现模块功能的扩展和加载过程。之后我们将深入了解该模块是如何实现模块功能的扩展和加载。

 

 

你可能感兴趣的:(网络,云计算,openstack,neutron)