api-paste.ini

定义了WSGI应用和路由信息。利用Paste来实例化Neutron的APIRouter类,将资源(端口、网络、子网)映射到URL上,以及各个资源的控制器。
在neutron-server启动的时候,一般会指定参数—config-file neutron.conf —config-file xxx.ini。看neutron/server/init.py的代码: main()主程序中会调用config.parse(sys.argv[1:])来读取这些配置文件中的信息。而api-paste.ini信息中定义了neutron、neutronapi_v2_0、若干filter和两个app。

  1. [composite:neutron]
  2. use = egg:Paste#urlmap
  3. /: neutronversions
  4. /v2.0: neutronapi_v2_0
  5. [composite:neutronapi_v2_0]
  6. use = call:neutron.auth:pipeline_factory
  7. noauth = request_id catch_errors extensions neutronapiapp_v2_0
  8. keystone = request_id catch_errors authtoken keystonecontext extensions neutronapiapp_v2_0
  9. [filter:request_id]
  10. paste.filter_factory = oslo.middleware:RequestId.factory
  11. [filter:catch_errors]
  12. paste.filter_factory = oslo.middleware:CatchErrors.factory
  13. [filter:keystonecontext]
  14. paste.filter_factory = neutron.auth:NeutronKeystoneContext.factory
  15. [filter:authtoken]
  16. paste.filter_factory = keystonemiddleware.auth_token:filter_factory
  17. [filter:extensions]
  18. paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
  19. [app:neutronversions]
  20. paste.app_factory = neutron.api.versions:Versions.factory
  21. [app:neutronapiapp_v2_0]
  22. paste.app_factory = neutron.api.v2.router:APIRouter.factory

neutron-server在读取完配置信息后,会执行neutron/common/config.py:load_paste_app(“neutron”),即将neutron应用load进来。从api-paste.ini中可以看到,neutron实际上是一个composite,分别将URL“/”和“/v2.0”映射到neutronversions应用和neutronapi_v2_0(也是一个composite)。

前者实际上调用了 neutron.api.versions 模块中的 Versions.factory 来处理传入的请求。

后者则要复杂一些,首先调用 neutron.auth 模块中的pipeline_factory 处理。如果是 noauth,则传入参数为 request_id,catch_errors,extensions 这些 filter和 neutronapiapp_v2_0 应用;如果是 keystone,则多传入一个 authtoken filter,最后一个参数仍然是 neutronapiapp_v2_0 应用。来看 neutron.auth 模块中的 pipeline_factory 处理代码。

  1. def pipeline_factory(loader, global_conf, **local_conf):
  2. """Create a paste pipeline based on the 'auth_strategy' config option."""
  3. pipeline = local_conf[cfg.CONF.auth_strategy]
  4. pipeline = pipeline.split()
  5. filters = [loader.get_filter(n) for n in pipeline[:-1]]
  6. app = loader.get_app(pipeline[-1])
  7. filters.reverse()
  8. for filter in filters:
  9. app = filter(app)
  10. return app

最终的代码入口是neutron.api.v2.router:APIRouter.factory。该方法主要代码为

  1. class APIRouter(wsgi.Router):
  2. @classmethod
  3. def factory(cls, global_config, **local_config):
  4. return cls(**local_config)
  5. def __init__(self, **local_config):
  6. mapper = routes_mapper.Mapper()
  7. plugin = manager.NeutronManager.get_plugin()
  8. ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
  9. ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)
  10. col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
  11. member_actions=MEMBER_ACTIONS)
  12. def _map_resource(collection, resource, params, parent=None):
  13. allow_bulk = cfg.CONF.allow_bulk
  14. allow_pagination = cfg.CONF.allow_pagination
  15. allow_sorting = cfg.CONF.allow_sorting
  16. controller = base.create_resource(
  17. collection, resource, plugin, params, allow_bulk=allow_bulk,
  18. parent=parent, allow_pagination=allow_pagination,
  19. allow_sorting=allow_sorting)
  20. path_prefix = None
  21. if parent:
  22. path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
  23. parent['member_name'],
  24. collection)
  25. mapper_kwargs = dict(controller=controller,
  26. requirements=REQUIREMENTS,
  27. path_prefix=path_prefix,
  28. **col_kwargs)
  29. return mapper.collection(collection, resource,
  30. **mapper_kwargs)
  31. mapper.connect('index', '/', controller=Index(RESOURCES))
  32. for resource in RESOURCES:
  33. _map_resource(RESOURCES[resource], resource,
  34. attributes.RESOURCE_ATTRIBUTE_MAP.get(
  35. RESOURCES[resource], dict()))
  36. for resource in SUB_RESOURCES:
  37. _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
  38. attributes.RESOURCE_ATTRIBUTE_MAP.get(
  39. SUB_RESOURCES[resource]['collection_name'],
  40. dict()),
  41. SUB_RESOURCES[resource]['parent'])

neutron server启动后,根据配置文件动态加载对应的core plugin 和 service plugin。neturon server 中会对收到的 rest api 请求进行解析,并最终转换成对该 plugin(core or service) 中相应方法的调用。