在Neutron API启动过程分析中,曾分析到加载wsgi app是通过load_paste_app函数首先实例化oslo_service.wsgi.py中的Loader类,返回一个loader对象。然后再调用loader对象的load_app函数来实现的。
def load_paste_app(app_name): """Builds and returns a WSGI app from a paste config file. :param app_name: Name of the application to load """ loader = wsgi.Loader(cfg.CONF) app = loader.load_app(app_name) return app
class Loader(object): def load_app(self, name): """Return the paste URLMap wrapped WSGI application. :param name: Name of the application to load. :returns: Paste URLMap object wrapping the requested application. :raises: PasteAppNotFound """ try: LOG.debug("Loading app %(name)s from %(path)s", {‘name‘: name, ‘path‘: self.config_path}) return deploy.loadapp("config:%s" % self.config_path, name=name) # 调用第三方库paste.deploy的loadapp函数来加载wsgi_app并返回 except LookupError: LOG.exception("Couldn‘t lookup app: %s", name) raise PasteAppNotFound(name=name, path=self.config_path)
下面分析一下paste.deploy的配置文件(即self.config_path),该配置文件默认为api-paste.ini。
[composite:neutron] use = egg:Paste#urlmap /: neutronversions_composite /v2.0: neutronapi_v2_0 [composite:neutronapi_v2_0] use = call:neutron.auth:pipeline_factory noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0 keystone = cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0 [composite:neutronversions_composite] use = call:neutron.auth:pipeline_factory noauth = cors http_proxy_to_wsgi neutronversions keystone = cors http_proxy_to_wsgi neutronversions [filter:request_id] paste.filter_factory = oslo_middleware:RequestId.factory [filter:catch_errors] paste.filter_factory = oslo_middleware:CatchErrors.factory [filter:cors] paste.filter_factory = oslo_middleware.cors:filter_factory oslo_config_project = neutron [filter:http_proxy_to_wsgi] paste.filter_factory = oslo_middleware.http_proxy_to_wsgi:HTTPProxyToWSGI.factory [filter:keystonecontext] paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory [filter:authtoken] paste.filter_factory = keystonemiddleware.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 [filter:osprofiler] paste.filter_factory = osprofiler.web:WsgiMiddleware.factory
- url为‘/‘:由neutronversions_composite处理;
- url为‘/v2.0‘:由neutronapi_v2_0处理。
[composite:neutronapi_v2_0] use = call:neutron.auth:pipeline_factory noauth = cors http_proxy_to_wsgi request_id catch_errors extensions neutronapiapp_v2_0 keystone = cors http_proxy_to_wsgi request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
use指定要调用的函数为/neutron/auth.py的pipeline_factory。noauth和keystone作为参数local_conf(dict)传入该函数。
def pipeline_factory(loader, global_conf, **local_conf): """Create a paste pipeline based on the ‘auth_strategy‘ config option.""" pipeline = local_conf[cfg.CONF.auth_strategy] # 配置文件中auth_strategy设置是否需要验证token(口令) pipeline = pipeline.split() # pipeline:str -> list filters = [loader.get_filter(n) for n in pipeline[:-1]] # 获取所有的filters(排除最后一个neutronapiapp_v2_0,因为它是app),形成list app = loader.get_app(pipeline[-1]) # neutronapiapp_v2_0中调用的类(APIRouter)在这一步被初始化,下一节分析 filters.reverse() # 反向filters列表,最靠近APIRouter的filter最先执行,即第一个执行的是extensions filter for filter in filters: app = filter(app) # 将app作为参数依次传入每个filter return app
配置文件中的auth_strategy默认为keystone,即默认需要对token进行验证。下面重点分析一下app:neutronapiapp_v2_0和filter:extensions。
1.neutronapiapp_v2_0
[app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
直接调用/neutron/api/v2/router.py中APIRouter的factory方法:
class APIRouter(base_wsgi.Router): @classmethod def factory(cls, global_config, **local_config): return cls(**local_config) def __init__(self, **local_config): ......
APIRouter的factory方法是一个classmethod,直接调用APIRouter的构造函数,对APIRouter进行初始化,这部分下一节分析。
2.extensions
[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
extensions filter直接调用/neutron/api/extensions.py中的plugin_aware_extension_middleware_factory方法:
def plugin_aware_extension_middleware_factory(global_config, **local_config): """Paste factory.""" def _factory(app): ext_mgr = PluginAwareExtensionManager.get_instance() return ExtensionMiddleware(app, ext_mgr=ext_mgr) return _factory