在nova的paste配置文件中(事实上其他模块也会有这种情况,版本演进的过程中,新的概念会放在新的api version中,同时又兼容老的version,最大程度
的满足不同情况的用户使用):
/v1.1: openstack_compute_api_v2
/v2: openstack_compute_api_v2
/v2.1: openstack_compute_api_v21
/v3: openstack_compute_api_v3
/v1.1和/v2都对应的是nova.api.openstack.compute:APIRouter.factory,前面记录过一遍APIRouter的load情况,来看看/v2.1和/v3:
在nova.api.openstack.compute中APIRouterV3和APIRouterV21的区别很小,二者都是nova.api.openstack.APIRouterV21的子类,
APIRouterV3在__init__中传入了v3mode=True, 因此主要落在APIRouterV21上,我们来trace一下:
在nova.conf中的segment[osapi_v3]中,若定义为disable,则新版本的api不被支持直接返回
if not CONF.osapi_v3.enabled:
LOG.info(_LI("V3 API has been disabled by configuration"))
return
APIRouterV21中定义了blacklist和whitelist,从配置文件的注释中知道:
blacklist:will never load,不被载入
whitelist: If the list is not empty then a v3 API extension will only be loaded if it exists in this list,只载入的
因此代码中对blacklist和whitelist取交集,若交集不为空,则矛盾了, 实际loading extension时,若既在blacklist又在whitelist,不会被载入。
接下来主要有两部分:
part 1:
self.api_extension_manager = stevedore.enabled.EnabledExtensionManager(
namespace=self.API_EXTENSION_NAMESPACE,
check_func=_check_load_extension,
invoke_on_load=True,
invoke_kwds={"extension_info": self.loaded_extension_info})
通过stevedore读取entry_points中API_EXTENSION_NAMESPACE(nova.api.v3.extensions)中的entry_point得到extensions,是怎么做到的呢?
trace在stevedore/enabled.py中的EnabledExtensionManager(可自己查看注释找到参数的意义),其父类ExtensionManager在__init__()中:
extensions = self._load_plugins(invoke_on_load, invoke_args, invoke_kwds, verify_requirements)
调用子类EnabledExtensionManager的_load_plugins:
ext = super(EnabledExtensionManager, self)._load_one_plugin(
ep, invoke_on_load, invoke_args, invoke_kwds,
verify_requirements,
)
if ext and not self.check_func(ext): #check_func在这里发挥了作用,在python中函数也是对应,作为参数传入
LOG.debug('ignoring extension %r', ep.name)
return None
其中ext为父类方法中的_load_one_plugin得到,返回return Extension(ep.name, ep, plugin, obj),其中obj = plugin(*invoke_args, **invoke_kwds),
对stevedore有兴趣可看看pkg_resource的实现,invoke_kwds对应前面的 invoke_kwds={"extension_info": self.loaded_extension_info,作为load entry point
时的参数传递,参数名为extension_info。
nova/api/openstack/compute/plugins/v3下的plugin,都是extensions.V3APIExtensionBase的子类,而extensions.V3APIExtensionBase的初始化函数中:
def __init__(self, extension_info):
self.extension_info = extension_info #定位去处了
!!不错,这里的extension_info就是nova/api/openstack/compute中APIRouterV21定义的:plugins.LoadedExtensionInfo()
而使用stevedore load extension时候执行:_check_load_extension,会调用self._register_extension(ext),最终所有的extension(plugin)都会
在nova/api/opnestack/compute/plugins/__init__.py中LoadedExtensionInfo的self.extension={}中以:
self.extensions[alias] = ext
的形式注册。
part 2:
if list(self.api_extension_manager):
self.api_extension_manager.map(self._register_resources,
mapper=mapper)
self.api_extension_manager.map(self._register_controllers)
trace到stevedore的map方法,实际上是对每个由stevedore得到的前面得到的extension进行routes的mapper建立,controller的对应关系建立。