neutron 启动流程祥解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LIUSHU427/article/details/84105249

 neutron-server作为Neutron看的唯一的服务进程,承担着接收用户restful api请求并分发处理的任务

 neutron-server的启动入口在neutron/server/__init__.py中,分别启动neutron-api和neutron-rpc两个服务,neutron-api负责处理其它模块或者用户的restful请求,neutron-rpc处理neutron-server与neutron agent 之间的通信

启动代码:

def main():
    eventlet.monkey_patch()

    # the configuration will be read into the cfg.CONF global data structure
    config.parse(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()

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

        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)

neutron_api 根据/etc/neutron/api-paste.ini文件设置加载application,如下配置Paste Deploy会在这个WSGI Server创建时参与进来,完成下面配置的所有composite filter app的配置,并将配置的类通过factory初始化

[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为了优化neutron并行处理能力,加入了worker的配置,如果配置为worker小于1直接启动,否则会通过 Processlauncher fork几个子进程来并行处理rest请求

        if workers < 1:
            # For the case where only one process is required.
            self._server = self.pool.spawn(self._run, application,
                                           self._socket)
        else:
            # Minimize the cost of checking for child exit by extending the
            # wait interval past the default of 0.01s.
            self._launcher = ProcessLauncher(wait_interval=1.0)
            self._server = WorkerService(self, application)
            self._launcher.launch_service(self._server, workers=workers)

所有的core api 和extension api 的加载与路由规则的创建都是通过APIRouter类完成的 ,server在初始化的时候会通过api-paste.ini的配置将APIRouter通过factory()初始化,初始化的流程如下代码,会将neutron里的core api以及extension api加到mapper中

class APIRouter(wsgi.Router):

    @classmethod
    def factory(cls, global_config, **local_config):
        return cls(**local_config)

    def __init__(self, **local_config):
        mapper = routes_mapper.Mapper()
        plugin = manager.NeutronManager.get_plugin()
        ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
        ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)

        col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
                          member_actions=MEMBER_ACTIONS)

        def _map_resource(collection, resource, params, parent=None):
            allow_bulk = cfg.CONF.allow_bulk
            allow_pagination = cfg.CONF.allow_pagination
            allow_sorting = cfg.CONF.allow_sorting
            controller = base.create_resource(
                collection, resource, plugin, params, allow_bulk=allow_bulk,
                parent=parent, allow_pagination=allow_pagination,
                allow_sorting=allow_sorting)
            path_prefix = None
            if parent:
                path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
                                                  parent['member_name'],
                                                  collection)
            mapper_kwargs = dict(controller=controller,
                                 requirements=REQUIREMENTS,
                                 path_prefix=path_prefix,
                                 **col_kwargs)
            return mapper.collection(collection, resource,
                                     **mapper_kwargs)

        mapper.connect('index', '/', controller=Index(RESOURCES))
        for resource in RESOURCES:
            _map_resource(RESOURCES[resource], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              RESOURCES[resource], dict()))

        for resource in SUB_RESOURCES:
            _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
                          attributes.RESOURCE_ATTRIBUTE_MAP.get(
                              SUB_RESOURCES[resource]['collection_name'],
                              dict()),
                          SUB_RESOURCES[resource]['parent'])

        # Certain policy checks require that the extensions are loaded
        # and the RESOURCE_ATTRIBUTE_MAP populated before they can be
        # properly initialized. This can only be claimed with certainty
        # once this point in the code has been reached. In the event
        # that the policies have been initialized before this point,
        # calling reset will cause the next policy check to
        # re-initialize with all of the required data in place.
        policy.reset()
        super(APIRouter, self).__init__(mapper)

core api对应L2层的network/subnet/port三种抽象,其余的各层抽象都涵盖在Extension API的范围

三个核心资源使用base.py文件中的类Controller去实现,只是在封装成WSGI Application的时候调用这个文件中的create_resource()函数根据不同参数动态创建对应的Controller对象

def create_resource(collection, resource, plugin, params, allow_bulk=False,
                    member_actions=None, parent=None, allow_pagination=False,
                    allow_sorting=False):
    controller = Controller(plugin, collection, resource, params, allow_bulk,
                            member_actions=member_actions, parent=parent,
                            allow_pagination=allow_pagination,
                            allow_sorting=allow_sorting)

    return wsgi_resource.Resource(controller, FAULT_MAP)

对于其余的扩展资源,Neutron仍然使用了传统的方式来实现,它们在neutron/extensions/目录下都分别有对应的实现和对应的Controller类位于neutron/api/目录下的extension.py文件只是一些基类和共用的代码 

猜你喜欢

转载自blog.csdn.net/LIUSHU427/article/details/84105249