2024-03-15 09:13:33 31阅读
1. Neutron 接收到 RESTful API 的请求后,交给 WSGI Application 进行初步处理
2. WSGI Application 通过 Python API 调用 Neutron 的 Plugin 模块
3. Plugin 通过 RPC 调用 Neutron 的 Agent
4. Agent 再通过某种协议对 VNF 进行配置
Neutron-Server 首先是一个 Web Server,对外提供的 RESTful 接口,对 Neutron 内部来说是资源的 CRUD 的外在体现。
Neutron 将 API 分为两大类,Core Service API 和 Extension Service API
Core Service API:network,subnet,port,subnetpool 等资源的 API
Extension Service API:router,lbaas,ippool,snat 等资源的 API
# neutron.egg-info/entry_points.txt
neutron-server = neutron.cmd.eventlet.server:main
# 加载 WSGI Application
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
return run_wsgi_app(app)
def run_wsgi_app(app):
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=_get_api_workers())
return server
1. Web Server 的 host 和 port 在配置文件中
2. 参数 app 为 WSGI Application,是真正处理请求的实体
3. 参数 wokers 的数量决定了 Web Server 是另外启动线程,还是在当前线程以协程的形式启动
_get_api_workers 返回的 api_workers 数量(neutron.conf 配置文件中),决定了采用 Web Server 的方式
api_workers <1:在当前进程启动 Web Server
api_workers >=1:在新进程启动 Web Server
etc/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
[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
[app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
api-paste.ini 的每个 section 都为一个 WSGI Application 的构造函数
最外层的 WSGI Application 是 composite:neutron,根据 url 分配后续处理的 WSGI Application
“/”:neutronversions_composite 处理,查询 Neutron API 版本信息
“/v2.0”:neutronapi_v2_0 处理,资源的 RESTFUL API
neutronapi_v2_0
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]
pipeline = pipeline.split()
filters = [loader.get_filter(n) for n in pipeline[:-1]]
app = loader.get_app(pipeline[-1])
filters.reverse()
for filter in filters:
app = filter(app)
return app
根据配置文件 neutron.conf 的 auth_strategy 选择是 noauth 还是 keystone,然后根据 section 名构建 pipline,处理请求。
pipline 构建过程:neutronapi_v2_0 外面一层一层加上 section 的构造工厂,构造工厂的 app 参数为 APIRouter,最终将 app_v2.0 外层一层一
层加上 filter,各个WSGI的关系如下:
在第三节的 neutronapiapp_v2_0 的 APIRouter 构造函数中,实现 plugin 的加载,包括 Core Plugin 和 Service Plugin:
# neutron/api/v2/router.py
def APIRouter(**local_config):
return pecan_app.v2_factory(None, **local_config)
def _factory(global_config, **local_config):
return pecan_app.v2_factory(global_config, **local_config)
setattr(APIRouter, 'factory', _factory)
# neutron/pecan_wsgi/app.py
def v2_factory(global_config, **local_config):
# ...
startup.initialize_all()
return app
# neutron/pecan_wsgi/startup.py
def initialize_all():
manager.init()
# neutron/manager.py
def init():
if not directory.is_loaded():
NeutronManager.get_instance()
其中,在 NeutronManager 的构造函数中,_load_service_plugins 调用 _get_plugin_instance 实现对 Service Plugin 的具体加载过程:
class NeutronManager(object):
# 核心插件加载
plugin_provider = cfg.CONF.core_plugin
plugin = self._get_plugin_instance(CORE_PLUGINS_NAMESPACE,
plugin_provider)
# directory 是单例
directory.add_plugin(lib_const.CORE, plugin)
msg = validate_post_plugin_load()
self._load_services_from_core_plugin(plugin)
# 服务插件加载
self._load_service_plugins()
由于调用的代码比较复杂,总结为以下几点:
1. 根据neutron.conf 中配置
上节提到了拓展资源,即 Extension Service 类(继承 ExtensionDescriptor),其 get_resources 方法,调用 build_resource_info 函数构建了
资源的 HTTP Request 与 Plugin 的函数映射关系 。此外,根据 register_quota 参数,决定了资源是否有配额 。
def build_resource_info(plural_mappings, resource_map, which_service,
action_map=None, register_quota=False,
translate_name=False, allow_bulk=False):
for collection_name in resource_map:
if register_quota:
resource_registry.register_resource_by_name(resource_name)
member_actions = action_map.get(resource_name, {})
controller = base.create_resource()
resource = extensions.ResourceExtension()
resources.append(resource)
return resources
1. API 请求最终到达 Plugin 之后,进行参数校验,再进行 Neutron 数据库操作
2. 调用 networking-odl 的driver,对控制器发起HTTP请求,同步数据
3. networking-odl 是作为 neutron 项目的插件,与控制器对接
2024-03-15 09:13:33 31阅读
1. Neutron 接收到 RESTful API 的请求后,交给 WSGI Application 进行初步处理
2. WSGI Application 通过 Python API 调用 Neutron 的 Plugin 模块
3. Plugin 通过 RPC 调用 Neutron 的 Agent
4. Agent 再通过某种协议对 VNF 进行配置
Neutron-Server 首先是一个 Web Server,对外提供的 RESTful 接口,对 Neutron 内部来说是资源的 CRUD 的外在体现。
Neutron 将 API 分为两大类,Core Service API 和 Extension Service API
Core Service API:network,subnet,port,subnetpool 等资源的 API
Extension Service API:router,lbaas,ippool,snat 等资源的 API
# neutron.egg-info/entry_points.txt
neutron-server = neutron.cmd.eventlet.server:main
# 加载 WSGI Application
def _run_wsgi(app_name):
app = config.load_paste_app(app_name)
return run_wsgi_app(app)
def run_wsgi_app(app):
server = wsgi.Server("Neutron")
server.start(app, cfg.CONF.bind_port, cfg.CONF.bind_host,
workers=_get_api_workers())
return server
1. Web Server 的 host 和 port 在配置文件中
2. 参数 app 为 WSGI Application,是真正处理请求的实体
3. 参数 wokers 的数量决定了 Web Server 是另外启动线程,还是在当前线程以协程的形式启动
_get_api_workers 返回的 api_workers 数量(neutron.conf 配置文件中),决定了采用 Web Server 的方式
api_workers <1:在当前进程启动 Web Server
api_workers >=1:在新进程启动 Web Server
etc/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
[filter:extensions]
paste.filter_factory = neutron.api.extensions:plugin_aware_extension_middleware_factory
[app:neutronapiapp_v2_0]
paste.app_factory = neutron.api.v2.router:APIRouter.factory
api-paste.ini 的每个 section 都为一个 WSGI Application 的构造函数
最外层的 WSGI Application 是 composite:neutron,根据 url 分配后续处理的 WSGI Application
“/”:neutronversions_composite 处理,查询 Neutron API 版本信息
“/v2.0”:neutronapi_v2_0 处理,资源的 RESTFUL API
neutronapi_v2_0
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]
pipeline = pipeline.split()
filters = [loader.get_filter(n) for n in pipeline[:-1]]
app = loader.get_app(pipeline[-1])
filters.reverse()
for filter in filters:
app = filter(app)
return app
根据配置文件 neutron.conf 的 auth_strategy 选择是 noauth 还是 keystone,然后根据 section 名构建 pipline,处理请求。
pipline 构建过程:neutronapi_v2_0 外面一层一层加上 section 的构造工厂,构造工厂的 app 参数为 APIRouter,最终将 app_v2.0 外层一层一
层加上 filter,各个WSGI的关系如下:
在第三节的 neutronapiapp_v2_0 的 APIRouter 构造函数中,实现 plugin 的加载,包括 Core Plugin 和 Service Plugin:
# neutron/api/v2/router.py
def APIRouter(**local_config):
return pecan_app.v2_factory(None, **local_config)
def _factory(global_config, **local_config):
return pecan_app.v2_factory(global_config, **local_config)
setattr(APIRouter, 'factory', _factory)
# neutron/pecan_wsgi/app.py
def v2_factory(global_config, **local_config):
# ...
startup.initialize_all()
return app
# neutron/pecan_wsgi/startup.py
def initialize_all():
manager.init()
# neutron/manager.py
def init():
if not directory.is_loaded():
NeutronManager.get_instance()
其中,在 NeutronManager 的构造函数中,_load_service_plugins 调用 _get_plugin_instance 实现对 Service Plugin 的具体加载过程:
class NeutronManager(object):
# 核心插件加载
plugin_provider = cfg.CONF.core_plugin
plugin = self._get_plugin_instance(CORE_PLUGINS_NAMESPACE,
plugin_provider)
# directory 是单例
directory.add_plugin(lib_const.CORE, plugin)
msg = validate_post_plugin_load()
self._load_services_from_core_plugin(plugin)
# 服务插件加载
self._load_service_plugins()
由于调用的代码比较复杂,总结为以下几点:
1. 根据neutron.conf 中配置
上节提到了拓展资源,即 Extension Service 类(继承 ExtensionDescriptor),其 get_resources 方法,调用 build_resource_info 函数构建了
资源的 HTTP Request 与 Plugin 的函数映射关系 。此外,根据 register_quota 参数,决定了资源是否有配额 。
def build_resource_info(plural_mappings, resource_map, which_service,
action_map=None, register_quota=False,
translate_name=False, allow_bulk=False):
for collection_name in resource_map:
if register_quota:
resource_registry.register_resource_by_name(resource_name)
member_actions = action_map.get(resource_name, {})
controller = base.create_resource()
resource = extensions.ResourceExtension()
resources.append(resource)
return resources
1. API 请求最终到达 Plugin 之后,进行参数校验,再进行 Neutron 数据库操作
2. 调用 networking-odl 的driver,对控制器发起HTTP请求,同步数据
3. networking-odl 是作为 neutron 项目的插件,与控制器对接
写的真好
写的真好