美文网首页虚拟化技术openstackOpenStack
Neutron-server的启动流程和工作方式(二)

Neutron-server的启动流程和工作方式(二)

作者: 分享放大价值 | 来源:发表于2017-05-02 18:00 被阅读59次

    导读

    • APIRouter类实现

    上一篇“Neutron-server的启动流程和工作方式(一)”里提到APIRouter类实现了app功能的扩展和加载过程,本文进一步展开分析。

    APIRouter类

     69 class APIRouter(base_wsgi.Router):
     70      
     71     @classmethod 
     72     def factory(cls, global_config, **local_config):
     73         return cls(**local_config) 
     74    
     75     def __init__(self, **local_config):
     76         mapper = routes_mapper.Mapper() 
     77         manager.init()  
     78         plugin = directory.get_plugin() 
                #(1)生成一个PluginAwareExtensionManager实例
     79         ext_mgr = extensions.PluginAwareExtensionManager.get_instance() 
     80         ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)   
     81                                                                
     82         col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,  
     83                           member_actions=MEMBER_ACTIONS)     
     84         #(2)建立resource到URL的映射关系                                               
     85         def _map_resource(collection, resource, params, parent=None): 
     86             allow_bulk = cfg.CONF.allow_bulk
                    #(3) 创建resource
     87             controller = base.create_resource(
     88                 collection, resource, plugin, params, allow_bulk=allow_bulk, 
     89                 parent=parent, allow_pagination=True,   
     90                 allow_sorting=True)
     91             path_prefix = None
     92             if parent:
     93                 path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
     94                                                   parent['member_name'],
     95                                                   collection)
                    #根据之前创建的Controller、REQUIREMENTS和path_prefix建立字典
     96             mapper_kwargs = dict(controller=controller, 
     97                                  requirements=REQUIREMENTS,
     98                                  path_prefix=path_prefix,
     99                                  **col_kwargs)
                    #最后根据字典,建立neutron api的顶级资源集合体
    100             return mapper.collection(collection, resource,
    101                                      **mapper_kwargs)
    102 
    103         mapper.connect('index', '/', controller=Index(RESOURCES))
    104         for resource in RESOURCES:
    105             _map_resource(RESOURCES[resource], resource,
    106                           attributes.RESOURCE_ATTRIBUTE_MAP.get(
    107                               RESOURCES[resource], dict()))
    108             resource_registry.register_resource_by_name(resource)
    109 
    110         for resource in SUB_RESOURCES:
    111             _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
    112                           attributes.RESOURCE_ATTRIBUTE_MAP.get(
    113                               SUB_RESOURCES[resource]['collection_name'],
    114                               dict()),
    115                           SUB_RESOURCES[resource]['parent'])
    116 
    117         # Certain policy checks require that the extensions are loaded
    118         # and the RESOURCE_ATTRIBUTE_MAP populated before they can be
    119         # properly initialized. This can only be claimed with certainty
    120         # once this point in the code has been reached. In the event
    121         # that the policies have been initialized before this point,
    122         # calling reset will cause the next policy check to
    123         # re-initialize with all of the required data in place.
    124         policy.reset()
    125         super(APIRouter, self).__init__(mapper) 
    
    

    上面的代码中比较重要就是(1)和(2)两部分。先来看下(1)的实现,首先生成PluginAwareExtensionManager类,再调用get_instance()方法获取ext_mgr实例:

    486 class PluginAwareExtensionManager(ExtensionManager):
    487 
    488     _instance = None
    489 
    490     def __init__(self, path, plugins):
    491         self.plugins = plugins
                #调用父类ExtensionManager的构造函数
    492         super(PluginAwareExtensionManager, self).__init__(path)
    493         self.check_if_plugin_extensions_loaded()
    
    305 class ExtensionManager(object):
    306     """Load extensions from the configured extension path.
    307 
    308     See tests/unit/extensions/foxinsocks.py for an
    309     example extension implementation.
    310     """
    311 
    312     def __init__(self, path):
    313         LOG.info(_LI('Initializing extension manager.'))
    314         self.path = path
    315         self.extensions = {}
    316         self._load_all_extensions()
    
    430     def _load_all_extensions(self):
    431         """Load extensions from the configured path.
    432 
    433         The extension name is constructed from the module_name. If your
    434         extension module is named widgets.py, the extension class within that
    435         module should be 'Widgets'.
    436 
    437         See tests/unit/extensions/foxinsocks.py for an example extension
    438         implementation.
    439         """
    440 
    441         for path in self.path.split(':'):
    442             if os.path.exists(path):
    443                 self._load_all_extensions_from_path(path)
    444             else:
    445                 LOG.error(_LE("Extension path '%s' doesn't exist!"), path)
    
    447     def _load_all_extensions_from_path(self, path):
    448         # Sorting the extension list makes the order in which they
    449         # are loaded predictable across a cluster of load-balanced
    450         # Neutron Servers
    451         for f in sorted(os.listdir(path)):
    452             try:
    453                 LOG.debug('Loading extension file: %s', f)
    454                 mod_name, file_ext = os.path.splitext(os.path.split(f)[-1])
    455                 ext_path = os.path.join(path, f)
    456                 if file_ext.lower() == '.py' and not mod_name.startswith('_'):
    457                     mod = imp.load_source(mod_name, ext_path)
    458                     ext_name = mod_name[0].upper() + mod_name[1:]
    459                     new_ext_class = getattr(mod, ext_name, None)
    460                     if not new_ext_class:
    461                         LOG.warning(_LW('Did not find expected name '
    462                                         '"%(ext_name)s" in %(file)s'),
    463                                     {'ext_name': ext_name,
    464                                      'file': ext_path})
    465                         continue
                            #根据path下的文件名,生成extension,并调用add_extension加入到self.extensions[]中
    466                     new_ext = new_ext_class()
    467                     self.add_extension(new_ext)
    468             except Exception as exception:
    469                 LOG.warning(_LW("Extension file %(f)s wasn't loaded due to "
    470                                 "%(exception)s"),
    471                             {'f': f, 'exception': exception})
    

    上述代码主要是将配置的extension路径下的所有"*.py"的文件进行排序后分别加载,获取文件名为extension的名称,其中加载的模块包括external_net,dns,dvr等等。
    回到(1),类初始化完成后,就调用get_instance():

    530     def get_instance(cls):                                                                          
    531         if cls._instance is None:
    532             service_plugins = directory.get_plugins()
    533             cls._instance = cls(get_extensions_path(service_plugins),
    534                                 service_plugins)
    535         return cls._instance
    

    这个函数中,获取路径下所有文件的path和服务的插件,并构建cls返回。

    再来看(2),这个是内置函数,在下面被遍历调用.这个函数中比较重要的是(3):

     # create_resource中主要是根据资源信息建立Controller,这个Controller就是用以之后api请求到来之后真正去处理这些请求
                #这个Controller是在neutron.api.v2.base中
                #之后wsgi_resource.Resource中根据collection、resource以及对应的RESOURCE_ATTRIBUTE_MAP的信息
                #创建一个xml和json的序列化和反序列化的对象
                #序列化指:对xml或json语句进行解析,确定要引用的动作
                #反序列化指:进行xml或json的封装
    750 def create_resource(collection, resource, plugin, params, allow_bulk=False,
    751                     member_actions=None, parent=None, allow_pagination=False,
    752                     allow_sorting=False):
    753     controller = Controller(plugin, collection, resource, params, allow_bulk,
    754                             member_actions=member_actions, parent=parent,
    755                             allow_pagination=allow_pagination,
    756                             allow_sorting=allow_sorting)
    757 
    758     return wsgi_resource.Resource(controller, FAULT_MAP)
    

    通过(3)创建的controller,就是著名的MVC模式中C,就是用来干脏活累活的主体了。_map_resource函数就是用来实现对资源的映射,具体可以理解为,得到了URL,通过这里的映射关系,匹配定位到具体要调用的方法上。
    至此,app功能的扩展和加载就搞定了。

    相关文章

      网友评论

        本文标题:Neutron-server的启动流程和工作方式(二)

        本文链接:https://www.haomeiwen.com/subject/qoqhtxtx.html