導(dǎo)讀
- APIRouter類(lèi)實(shí)現(xiàn)
上一篇“Neutron-server的啟動(dòng)流程和工作方式(一)”里提到APIRouter類(lèi)實(shí)現(xiàn)了app功能的擴(kuò)展和加載過(guò)程休涤,本文進(jìn)一步展開(kāi)分析。
APIRouter類(lèi)
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)生成一個(gè)PluginAwareExtensionManager實(shí)例
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的映射關(guān)系
85 def _map_resource(collection, resource, params, parent=None):
86 allow_bulk = cfg.CONF.allow_bulk
#(3) 創(chuàng)建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)
#根據(jù)之前創(chuàng)建的Controller但绕、REQUIREMENTS和path_prefix建立字典
96 mapper_kwargs = dict(controller=controller,
97 requirements=REQUIREMENTS,
98 path_prefix=path_prefix,
99 **col_kwargs)
#最后根據(jù)字典,建立neutron api的頂級(jí)資源集合體
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)兩部分。先來(lái)看下(1)的實(shí)現(xiàn),首先生成PluginAwareExtensionManager類(lèi),再調(diào)用get_instance()方法獲取ext_mgr實(shí)例:
486 class PluginAwareExtensionManager(ExtensionManager):
487
488 _instance = None
489
490 def __init__(self, path, plugins):
491 self.plugins = plugins
#調(diào)用父類(lèi)ExtensionManager的構(gòu)造函數(shù)
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
#根據(jù)path下的文件名脂男,生成extension,并調(diào)用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"的文件進(jìn)行排序后分別加載种呐,獲取文件名為extension的名稱(chēng)宰翅,其中加載的模塊包括external_net,dns,dvr等等。
回到(1),類(lèi)初始化完成后爽室,就調(diào)用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
這個(gè)函數(shù)中堕油,獲取路徑下所有文件的path和服務(wù)的插件,并構(gòu)建cls返回肮之。
再來(lái)看(2),這個(gè)是內(nèi)置函數(shù)掉缺,在下面被遍歷調(diào)用.這個(gè)函數(shù)中比較重要的是(3):
# create_resource中主要是根據(jù)資源信息建立Controller,這個(gè)Controller就是用以之后api請(qǐng)求到來(lái)之后真正去處理這些請(qǐng)求
#這個(gè)Controller是在neutron.api.v2.base中
#之后wsgi_resource.Resource中根據(jù)collection戈擒、resource以及對(duì)應(yīng)的RESOURCE_ATTRIBUTE_MAP的信息
#創(chuàng)建一個(gè)xml和json的序列化和反序列化的對(duì)象
#序列化指:對(duì)xml或json語(yǔ)句進(jìn)行解析眶明,確定要引用的動(dòng)作
#反序列化指:進(jìn)行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)
通過(guò)(3)創(chuàng)建的controller,就是著名的MVC模式中C筐高,就是用來(lái)干臟活累活的主體了搜囱。_map_resource函數(shù)就是用來(lái)實(shí)現(xiàn)對(duì)資源的映射,具體可以理解為柑土,得到了URL蜀肘,通過(guò)這里的映射關(guān)系,匹配定位到具體要調(diào)用的方法上稽屏。
至此扮宠,app功能的擴(kuò)展和加載就搞定了。