分享

OpenStack J版 Neutron-server服务加载与启动源码分析(二)

pig2 发表于 2014-11-10 20:19:17 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 1 31076
问题导读
1.本文主要分析什么内容?
2.文中两个函数的作用是什么?







本文是在学习Openstack的过程中整理和总结,由于时间和个人能力有限,错误之处在所难免,欢迎指正!
在上一篇博客Neutron-server服务加载与启动源码分析(一)通过对api-paste.ini中配置信息的解析,最终就调用了WSGIApplicationapiv2的实现,具体就是neutron.api.v2.router:APIRouter.factory,这个WSGI
Application的具体功能就是实现模块功能的扩展和加载过程。现在就深入了解该模块是如何实现模块功能的扩展和加载。
首先来看下neutron.api.v2.router.py
classAPIRouter(wsgi.Router):

    @classmethod
    deffactory(cls, global_config,**local_config):
        return cls(**local_config)

def__init__(self,**local_config):
       #路由映射
        mapper = routes_mapper.Mapper()
       #获取插件
        plugin = manager.NeutronManager.get_plugin()
        ext_mgr =extensions.PluginAwareExtensionManager.get_instance()                                  #(1)
        ext_mgr.extend_resources("2.0", attributes.RESOURCE_ATTRIBUTE_MAP)

        col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,
                         member_actions=MEMBER_ACTIONS)

        def_map_resource(collection, resource, params, parent=None):                                    #(2)
            allow_bulk = cfg.CONF.allow_bulk
            allow_pagination = cfg.CONF.allow_pagination
            allow_sorting = cfg.CONF.allow_sorting
            controller = base.create_resource(
                collection, resource, plugin, params, allow_bulk=allow_bulk,
                parent=parent, allow_pagination=allow_pagination,
                allow_sorting=allow_sorting)
            path_prefix =None
            if parent:
                path_prefix ="/%s/{%s_id}/%s"%(parent['collection_name'],
                                                 parent['member_name'],
                                                  collection)
            mapper_kwargs = dict(controller=controller,
                                requirements=REQUIREMENTS,
                                path_prefix=path_prefix,
                                 **col_kwargs)
            return mapper.collection(collection, resource,
                                    **mapper_kwargs)

        mapper.connect('index','/', controller=Index(RESOURCES))
        #遍历建立对应资源的Controller
        for resource in RESOURCES:
            _map_resource(RESOURCES[resource], resource,
                         attributes.RESOURCE_ATTRIBUTE_MAP.get(
                             RESOURCES[resource], dict()))

        for resource in SUB_RESOURCES:
            _map_resource(SUB_RESOURCES[resource]['collection_name'], resource,
                         attributes.RESOURCE_ATTRIBUTE_MAP.get(
                             SUB_RESOURCES[resource]['collection_name'],
                              dict()),
                          SUB_RESOURCES[resource]['parent'])

        super(APIRouter, self).__init__(mapper)


这里面有两个重要的函数(1)和(2)
首先来看(1)函数:ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
最先执行的是PluginAwareExtensionManager的初始化中
  1. classPluginAwareExtensionManager(ExtensionManager):
  2.     _instance =None
  3.     def__init__(self, path, plugins):
  4.         self.plugins = plugins
  5.         super(PluginAwareExtensionManager, self).__init__(path)
  6.         self.check_if_plugin_extensions_loaded()
复制代码


调用父类的初始化,这边的path为/usr/lib/python2.7/dist-packages/neutron/extensions,根据注释可知是配置的extension路径。
  1. classExtensionManager(object):
  2.     def__init__(self, path):
  3.         LOG.info(_('Initializing extension manager.'))
  4.         self.path = path
  5.         self.extensions ={}
  6.         self._load_all_extensions()
  7.         policy.reset()
复制代码


在_load_all_extensions()中
  1. for path in self.path.split(':'):
  2.             if os.path.exists(path):
  3.                 self._load_all_extensions_from_path(path)
  4.             else:
  5.                 LOG.error(_("Extension path '%s' doesn't exist!"), path)
复制代码


在_load_all_extensions_from_path(path)中将/usr/lib/python2.7/dist-packages/neutron/extensions路径下的所有为“.py“的文件按照sorted排序顺序分别加载
  1. def_load_all_extensions_from_path(self, path):
  2.         # 对文件进行排序取出并加载
  3.         for f in sorted(os.listdir(path)):
  4.             try:
  5.                 LOG.debug(_('Loading extension file: %s'), f)
  6.                 mod_name, file_ext = os.path.splitext(os.path.split(f)[-1])
  7.                 ext_path = os.path.join(path, f)
  8.                 if file_ext.lower()=='.py'andnot mod_name.startswith('_'):
  9.                     mod = imp.load_source(mod_name, ext_path)
  10.                     ext_name = mod_name[0].upper()+ mod_name[1:]
  11.                     new_ext_class = getattr(mod, ext_name,None)
  12.                     ifnot new_ext_class:
  13.                         LOG.warn(_('Did not find expected name '
  14.                                    '"%(ext_name)s" in %(file)s'),
  15.                                  {'ext_name': ext_name,
  16.                                   'file': ext_path})
  17.                         continue
  18.                     new_ext = new_ext_class()
  19.                     self.add_extension(new_ext)
  20.             except Exception as exception:
  21.                 LOG.warn(_("Extension file %(f)s wasn't loaded due to "
  22.                            "%(exception)s"),{'f': f,'exception': exception})
复制代码


其中加载的文件包括external_net.py,agent.py等文件
回到(1)函数,初始化完成,就调用
  1. defget_instance(cls):
  2.         if cls._instance isNone:
  3.             cls._instance = cls(get_extensions_path(),
  4.                                manager.NeutronManager.get_service_plugins())
  5.         returncls._instance
复制代码


get_instance(cls)函数,在这个函数中,获取路径下的所有文件的paths和服务的插件,来构建cls并且返回。
再来看第二个重要的(2)函数:def_map_resource(collection, resource, params, parent=None):这个函数是函数中内置的函数,下面被遍历调用。
  1. def _map_resource(collection, resource, params, parent=None):
  2.             #读取配置文件中关于分块、分页、排序的设置
  3.             allow_bulk = cfg.CONF.allow_bulk
  4.             allow_pagination = cfg.CONF.allow_pagination
  5.             allow_sorting = cfg.CONF.allow_sorting
  6.             # create_resource中主要是根据资源信息建立Controller,这个Controller就是用以之后api请求到来之后真正去处理这些请求
  7.             #这个Controller是在neutron.api.v2.base中
  8.             #之后wsgi_resource.Resource中根据collection、resource以及对应的RESOURCE_ATTRIBUTE_MAP的信息
  9.             #创建一个xml和json的序列化和反序列化的对象
  10.             #序列化指:对xml或json语句进行解析,确定要引用的动作
  11.             #反序列化指:进行xml或json的封装
  12.             controller = base.create_resource(
  13.                 collection, resource, plugin, params, allow_bulk=allow_bulk,
  14.                 parent=parent, allow_pagination=allow_pagination,
  15.                 allow_sorting=allow_sorting)
  16.             path_prefix = None
  17.             if parent:
  18.                 path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],
  19.                                                   parent['member_name'],
  20.                                                   collection)
  21.             #根据之前创建的controller、REQUIREMENTS和path_prefix建立字典
  22.             mapper_kwargs = dict(controller=controller,
  23.                                  requirements=REQUIREMENTS,
  24.                                  path_prefix=path_prefix,
  25.                                  **col_kwargs)
  26.             #最后根据字典,建立neutron api的顶级资源集合体
  27.             return mapper.collection(collection, resource,
  28.                                      **mapper_kwargs)
复制代码


_map_resource函数从字面的意思我们就可以看出他是对资源进行映射,这边的资源是什么?他对应的就是得到的URL,所以这个函数可以简单的理解为,得到了URL,通过这里实现的映射关系,进行格式匹配,具体定位到所要调用的方法上。这边就将URL的请求信息对应地放置在顶级资源集合体之中,为调用做好准备。
至此,模块功能的扩展和加载就搞定了。

作者:林凯
团队:华为杭州OpenStack团队

已有(1)人评论

跳转到指定楼层
sheldon 发表于 2015-1-23 16:45:42
请教楼主一个问题,我在windows下,在eclipse下,导入了neutron工程,怎么能够做debug调试呢?
我有个fuel安装的环境是juno版本,在我的windows平台下,可以远程debug我那个环境吗?
debug代码会理解的更好一些。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条