nova-api代码分析(2)
2014-08-09 16:29
281 查看
上一篇完成了APIRouter类中,初始化ExtensionManager实例 ,ext_mgr = self.ExtensionManager()的功能分析,主要就是对于contrib目录下用户自定义的路由文件类加载进来。
接下来继续分析class APIRouter(base_wsgi.Router)类:
mapper = ProjectMapper() 初始化了routes模块里的Mapper类,包含了resource和connect两个路由加载方法。
ProjectMapper继承自APIMapper类。
APIRouter(base_wsgi.Router)继承自nova.api.openstack.compute下的
APIMapper(routes.Mapper)类
方法self._setup_routes(mapper, ext_mgr, init_only),加载openstack核心功能路由
继续看APIRouter的下一个方法self._setup_ext_routes(mapper, ext_mgr, init_only),此方法加载了所有contrib目录下一下加载进来的文件路由
重点看一下ExtensionManager类的内容:
_setup_ext_routes方法加载了contrib目录下所有的路由文件,下面举一个volumes.py文件的例子,看看具体内容:
以上内容基本分析完WSGIService的load_app方法,来加载路由信息的代码内容,下面继续分析,nova-api代码中启动WSGIService的代码
接下来继续分析class APIRouter(base_wsgi.Router)类:
mapper = ProjectMapper() 初始化了routes模块里的Mapper类,包含了resource和connect两个路由加载方法。
ProjectMapper继承自APIMapper类。
class ProjectMapper(APIMapper): def resource(self, member_name, collection_name, **kwargs): if 'parent_resource' not in kwargs: kwargs['path_prefix'] = '{project_id}/' else: parent_resource = kwargs['parent_resource'] p_collection = parent_resource['collection_name'] p_member = parent_resource['member_name'] kwargs['path_prefix'] = '{project_id}/%s/:%s_id' % (p_collection, p_member) routes.Mapper.resource(self, member_name, collection_name, **kwargs)
class APIMapper(routes.Mapper): def routematch(self, url=None, environ=None): if url == "": result = self._match("", environ) return result[0], result[1] return routes.Mapper.routematch(self, url, environ) def connect(self, *args, **kargs): # NOTE(vish): Default the format part of a route to only accept json # and xml so it doesn't eat all characters after a '.' # in the url. kargs.setdefault('requirements', {}) if not kargs['requirements'].get('format'): kargs['requirements']['format'] = 'json|xml' return routes.Mapper.connect(self, *args, **kargs)
APIRouter(base_wsgi.Router)继承自nova.api.openstack.compute下的
APIMapper(routes.Mapper)类
方法self._setup_routes(mapper, ext_mgr, init_only),加载openstack核心功能路由
class APIRouter(nova.api.openstack.APIRouter): """Routes requests on the OpenStack API to the appropriate controller and method. """ ExtensionManager = extensions.ExtensionManager #加载openstack的核心路由方法 def _setup_routes(self, mapper, ext_mgr, init_only): if init_only is None or 'versions' in init_only: #通过create_resource回调函数,返回wsgi.Resource(Controller(ext_mgr)),放入resources资源字典中 self.resources['versions'] = versions.create_resource() #mapper.connect方法,建立resources相应资源与REST请求的链接,具体connect的方法详见其他说明 mapper.connect("versions", "/", controller=self.resources['versions'], action='show', conditions={"method": ['GET']}) mapper.redirect("", "/") if init_only is None or 'consoles' in init_only: #通过create_resource回调函数,返回wsgi.Resource(Controller(ext_mgr)),放入resources资源字典中 self.resources['consoles'] = consoles.create_resource() #mapper.resource方法,建立resources相应资源与REST请求的链接,具体resource的方法详见其他说明 mapper.resource("console", "consoles", controller=self.resources['consoles'], parent_resource=dict(member_name='server', collection_name='servers')) if init_only is None or 'consoles' in init_only or \ 'servers' in init_only or 'ips' in init_only: self.resources['servers'] = servers.create_resource(ext_mgr) mapper.resource("server", "servers", controller=self.resources['servers'], collection={'detail': 'GET'}, member={'action': 'POST'}) if init_only is None or 'ips' in init_only: self.resources['ips'] = ips.create_resource() mapper.resource("ip", "ips", controller=self.resources['ips'], parent_resource=dict(member_name='server', collection_name='servers')) if init_only is None or 'images' in init_only: self.resources['images'] = images.create_resource() mapper.resource("image", "images", controller=self.resources['images'], collection={'detail': 'GET'}) if init_only is None or 'limits' in init_only: self.resources['limits'] = limits.create_resource() mapper.resource("limit", "limits", controller=self.resources['limits']) if init_only is None or 'flavors' in init_only: self.resources['flavors'] = flavors.create_resource() mapper.resource("flavor", "flavors", controller=self.resources['flavors'], collection={'detail': 'GET'}, member={'action': 'POST'}) if init_only is None or 'image_metadata' in init_only: self.resources['image_metadata'] = image_metadata.create_resource() image_metadata_controller = self.resources['image_metadata'] mapper.resource("image_meta", "metadata", controller=image_metadata_controller, parent_resource=dict(member_name='image', collection_name='images')) mapper.connect("metadata", "/{project_id}/images/{image_id}/metadata", controller=image_metadata_controller, action='update_all', conditions={"method": ['PUT']}) if init_only is None or 'server_metadata' in init_only: self.resources['server_metadata'] = \ server_metadata.create_resource() server_metadata_controller = self.resources['server_metadata'] mapper.resource("server_meta", "metadata", controller=server_metadata_controller, parent_resource=dict(member_name='server', collection_name='servers')) mapper.connect("metadata", "/{project_id}/servers/{server_id}/metadata", controller=server_metadata_controller, action='update_all', conditions={"method": ['PUT']})
继续看APIRouter的下一个方法self._setup_ext_routes(mapper, ext_mgr, init_only),此方法加载了所有contrib目录下一下加载进来的文件路由
重点看一下ExtensionManager类的内容:
class ExtensionManager(object): """Load extensions from the configured extension path. See nova/tests/api/openstack/compute/extensions/foxinsocks.py or an example extension implementation. """ def sorted_extensions(self): if self.sorted_ext_list is None: self.sorted_ext_list = sorted(self.extensions.iteritems()) for _alias, ext in self.sorted_ext_list: yield ext def is_loaded(self, alias): return alias in self.extensions def register(self, ext): # Do nothing if the extension doesn't check out if not self._check_extension(ext): return alias = e 4000 xt.alias LOG.audit(_('Loaded extension: %s'), alias) if alias in self.extensions: raise exception.NovaException("Found duplicate extension: %s" % alias) self.extensions[alias] = ext self.sorted_ext_list = None #获取resources方法 def get_resources(self): """Returns a list of ResourceExtension objects.""" resources = [] #向resources列表中添加extensions resources.append(ResourceExtension('extensions', ExtensionsController(self))) #sorted_extensions对ext_mgr进行排序后,通过迭代器返回ext实例 for ext in self.sorted_extensions(): try: #调用每一个路由文件里的get_resources()回调函数,返回路由信息的resources列表extend到resources resources.extend(ext.get_resources()) except AttributeError: # NOTE(dprince): Extension aren't required to have resource # extensions pass return resources def get_controller_extensions(self): """Returns a list of ControllerExtension objects.""" controller_exts = [] for ext in self.sorted_extensions(): try: get_ext_method = ext.get_controller_extensions except AttributeError: # NOTE(Vek): Extensions aren't required to have # controller extensions continue controller_exts.extend(get_ext_method()) return controller_exts def _check_extension(self, extension): """Checks for required methods in extension objects.""" try: LOG.debug('Ext name: %s', extension.name) LOG.debug('Ext alias: %s', extension.alias) LOG.debug('Ext description: %s', ' '.join(extension.__doc__.strip().split())) LOG.debug('Ext namespace: %s', extension.namespace) LOG.debug('Ext updated: %s', extension.updated) except AttributeError as ex: LOG.exception(_("Exception loading extension: %s"), unicode(ex)) return False return True def load_extension(self, ext_factory): """Execute an extension factory. Loads an extension. The 'ext_factory' is the name of a callable that will be imported and called with one argument--the extension manager. The factory callable is expected to call the register() method at least once. """ LOG.debug("Loading extension %s", ext_factory) if isinstance(ext_factory, six.string_types): # Load the factory factory = importutils.import_class(ext_factory) else: factory = ext_factory # Call it LOG.debug("Calling extension factory %s", ext_factory) factory(self) def _load_extensions(self): """Load extensions specified on the command line.""" extensions = list(self.cls_list) for ext_factory in extensions: try: self.load_extension(ext_factory) except Exception as exc: LOG.warn(_LW('Failed to load extension %(ext_factory)s: ' '%(exc)s'), {'ext_factory': ext_factory, 'exc': exc})
_setup_ext_routes方法加载了contrib目录下所有的路由文件,下面举一个volumes.py文件的例子,看看具体内容:
class Volumes(extensions.ExtensionDescriptor): """Volumes support.""" name = "Volumes" alias = "os-volumes" namespace = "http://docs.openstack.org/compute/ext/volumes/api/v1.1" updated = "2011-03-25T00:00:00Z" def get_resources(self): resources = [] # NOTE(justinsb): No way to provide singular name ('volume') # Does this matter? res = extensions.ResourceExtension('os-volumes', VolumeController(), collection_actions={'detail': 'GET'}) resources.append(res) attachment_controller = VolumeAttachmentController(self.ext_mgr) res = extensions.ResourceExtension('os-volume_attachments', attachment_controller, parent=dict( member_name='server', collection_name='servers')) resources.append(res) res = extensions.ResourceExtension('os-volumes_boot', inherits='servers') resources.append(res) res = extensions.ResourceExtension('os-snapshots', SnapshotController(), collection_actions={'detail': 'GET'}) resources.append(res) return resources
以上内容基本分析完WSGIService的load_app方法,来加载路由信息的代码内容,下面继续分析,nova-api代码中启动WSGIService的代码
相关文章推荐
- nova-api代码分析(1)
- nova-api代码分析(3)
- API Demo Snake代码分析一 FrameLayout新的认识
- API Demo SearchableDictionary代码分析二
- nova-api源码分析(APP中用到的开源库)
- Tripleo之nova-compute 和Ironic的代码深入分析(四)
- Tripleo之nova-compute 和Ironic的代码深入分析(一)
- Radmin的抓屏和显屏API代码部分分析
- novaclient代码解析之---通过nova show <server-id>命令解析Nova client与Nova API之间的调用关系
- JQuery data API实现代码分析
- JQuery html API支持解析执行Javascript脚本功能实现-代码分析
- openstack之nova-api服务流程分析
- openstack nova 源码分析2之nova-api,nova-compute
- openstack nova 源码分析2之nova-api,nova-compute
- nova-api源码分析(WSGI server的创建及启动)
- OpenStack 之 nova-api 的代码结构图
- API Demo Snake代码分析三 程序架构的分析
- DIOCP开源项目 API代码的封装和流程分析
- nova boot from volume代码分析
- Tripleo之nova-compute 和Ironic的代码深入分析(三)