Extension Service的加载

Extension Service从字面意义上来理解,就是可扩展的Service——谁都可以扩展的Service、谁都可以写自己的Service。既然谁都可以扩展,那么Neutron必须得知道你写的代码在哪个目录,否则它到哪里加载你的代码呢?
Neutron提供了两种告知Extension Service代码目录的方法。一种是在配置文件“neutron.conf”中,配置自己的Extension Service的代码目录:
#etc/neutron.py
api_extensions_path=*** # ***表示Extension Service的代码目录
另一种方式是把代码放在Neutron自己官方的extensions目录下,也就是目录neutron/extensions下。当前Neutron版本中,该目录下已经有很多代码,如下图:
需要强调的是,不是说把代码放在extensions目录(包括自己定义的目录和Neutron的官方目录“neutron/extensions”)下,Neutron就会认为这个代码就是可以加载的,就是属于Extension Service的代码。Neutron规定,文件名必须不能以“_”开头,否则Neutron不会加载该文件。
另外、即使代码的文件名合法了,Neutron也不会加载该文件中的所有内容。我们知道一个python文件里面也可以有很多python class,比如dns.py,里面就有很多class,如下图:
在这么多class中,Neutron只认为class name与file name相同的class才是Extension Service class,才会加载它。比如说dns.py这个文件里,Neutron只认为class Dns是一个Extension Service class,只会加载class Dns。
满足这两个条件后,Neutron还继续再做两个判断:1.是否继承自class ExtensionDescription;2.是否实现了get_name、get_alias、get_description、get_updated等接口。
在此,总结一下成为Neutron的Extension Service class的条件。
1 代码文件必须位于extensions目录下,extensions目录包括在配置文件neutron.conf自定义的目录和Neutron的官方目录“neutron/extensions”。
2 文件名必须不能以”_”开头。
3 class name必须与file name相同(不区分大小写)。
4 class 必须继承自class ExtensionDescriptor。
5 必须实现了get_name、get_alias、get_description、get_updated 4个接口。
当以上5个条件都通过以后,Neutron才会真正加载这个Extension Service。所谓加载,就是在Neutron代码启动时,创建这些Extension class的实例。
在此介绍一下相关代码的位置:
1 Extension Service代码所在的目录获取相关代码:
    def get_instance(cls):
        if cls._instance is None:
            service_plugins = directory.get_plugins()
            cls._instance = cls(get_extensions_path(service_plugins),
                                service_plugins)
        return cls._instance
2 Extension Service实例的加载:
   
 def _load_all_extensions_from_path(self, path):
        # Sorting the extension list makes the order in which they
        # are loaded predictable across a cluster of load-balanced
        # Neutron Servers
        for f in sorted(os.listdir(path)):
            try:
                LOG.debug('Loading extension file: %s', f)
                mod_name, file_ext = os.path.splitext(os.path.split(f)[-1])
                ext_path = os.path.join(path, f)
                if file_ext.lower() == '.py' and not mod_name.startswith('_'):
                    mod = imp.load_source(mod_name, ext_path)
                    ext_name = mod_name[0].upper() + mod_name[1:]
                    new_ext_class = getattr(mod, ext_name, None)
                    if not new_ext_class:
                        LOG.warning(_LW('Did not find expected name '
                                        '"%(ext_name)s" in %(file)s'),
                                    {'ext_name': ext_name,
                                     'file': ext_path})
                        continue
                    new_ext = new_ext_class()
                    self.add_extension(new_ext)
            except Exception as exception:
                LOG.warning(_LW("Extension file %(f)s wasn't loaded due to "
                                "%(exception)s"),
                            {'f': f, 'exception': exception})

猜你喜欢

转载自blog.csdn.net/chengqiuming/article/details/80696869