Ocata Neutron代码分析(六)——APIRouter的初始化(3)顶级resource的map过程
在完成了plugins和extensions的加载后,进行四个顶级resource(分别是network、subnet、subnetpool和port)的map过程。map过程指的是,将各个resource的相关请求(例如创建network、删除subnet)映射到相应的处理函数的过程。APIRouter构造函数中相关代码如下:
RESOURCES = {'network': 'networks','subnet': 'subnets','subnetpool': 'subnetpools','port': 'ports'} SUB_RESOURCES = {} class APIRouter(base_wsgi.Router):......def __init__(self, **local_config):mapper = routes_mapper.Mapper()......mapper.connect('index', '/', controller=Index(RESOURCES))for resource in RESOURCES:_map_resource(RESOURCES[resource], resource,attributes.RESOURCE_ATTRIBUTE_MAP.get(RESOURCES[resource], dict()))resource_registry.register_resource_by_name(resource)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'])
class APIRouter(base_wsgi.Router):def __init__(self, **local_config):col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,member_actions=MEMBER_ACTIONS)def _map_resource(collection, resource, params, parent=None):allow_bulk = cfg.CONF.allow_bulkcontroller = base.create_resource( # 1collection, resource, plugin, params, allow_bulk=allow_bulk,parent=parent, allow_pagination=True,allow_sorting=True)path_prefix = Noneif parent:path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],parent['member_name'],collection)mapper_kwargs = dict(controller=controller, # 2requirements=REQUIREMENTS,path_prefix=path_prefix,**col_kwargs)return mapper.collection(collection, resource, # 3**mapper_kwargs)
- 调用/neutron/api/v2/base.py中的create_resource函数来构造请求的处理函数(即上面提到的controller);
- 构造传入mapper.collection函数的参数mapper_kwargs;
- 调用mapper.collection函数来实际进行map动作。
def create_resource(collection, resource, plugin, params, allow_bulk=False,member_actions=None, parent=None, allow_pagination=False,allow_sorting=False):controller = Controller(plugin, collection, resource, params, allow_bulk,member_actions=member_actions, parent=parent,allow_pagination=allow_pagination,allow_sorting=allow_sorting)return wsgi_resource.Resource(controller, FAULT_MAP)
class Controller(object):LIST = 'list'SHOW = 'show'CREATE = 'create'UPDATE = 'update'DELETE = 'delete'def __init__(self, plugin, collection, resource, attr_info,allow_bulk=False, member_actions=None, parent=None,allow_pagination=False, allow_sorting=False):if member_actions is None:member_actions = []self._plugin = pluginself._collection = collection.replace('-', '_')self._resource = resource.replace('-', '_')self._attr_info = attr_infoself._allow_bulk = allow_bulkself._allow_pagination = allow_paginationself._allow_sorting = allow_sortingself._native_bulk = self._is_native_bulk_supported()self._native_pagination = self._is_native_pagination_supported()self._native_sorting = self._is_native_sorting_supported()self._policy_attrs = self._init_policy_attrs()self._notifier = n_rpc.get_notifier('network')self._member_actions = member_actionsself._primary_key = self._get_primary_key()if self._allow_pagination and self._native_pagination:# Native pagination need native sorting supportif not self._native_sorting:raise exceptions.Invalid(_("Native pagination depend on native sorting"))if not self._allow_sorting:LOG.info(_LI("Allow sorting is enabled because native ""pagination requires native sorting"))self._allow_sorting = Trueself.parent = parentif parent:self._parent_id_name = '%s_id' % parent['member_name']parent_part = '_%s' % parent['member_name']else:self._parent_id_name = Noneparent_part = ''self._plugin_handlers = {self.LIST: 'get%s_%s' % (parent_part, self._collection),self.SHOW: 'get%s_%s' % (parent_part, self._resource)}for action in [self.CREATE, self.UPDATE, self.DELETE]:self._plugin_handlers[action] = '%s%s_%s' % (action, parent_part,self._resource)
def Resource(controller, faults=None, deserializers=None, serializers=None,action_status=None):"""Represents an API entity resource and the associated serialization anddeserialization logic"""default_deserializers = {'application/json': wsgi.JSONDeserializer()}default_serializers = {'application/json': wsgi.JSONDictSerializer()}format_types = {'json': 'application/json'}action_status = action_status or dict(create=201, delete=204)default_deserializers.update(deserializers or {})default_serializers.update(serializers or {})deserializers = default_deserializersserializers = default_serializersfaults = faults or {}@webob.dec.wsgify(RequestClass=Request)def resource(request):......# NOTE(blogan): this is something that is needed for the transition to# pecan. This will allow the pecan code to have a handle on the controller# for an extension so it can reuse the code instead of forcing every# extension to rewrite the code for use with pecan.setattr(resource, 'controller', controller)setattr(resource, 'action_status', action_status)return resource
可以看到,Resource函数只是在其中的resource函数外多加了一层壳,这层壳主要是进行序列化和反序列化组件(serializers和deserializers)的配置。其中的resource函数经过webob.dec.wsgify修饰,所以各个resource的request均是交给这里的resource函数来处理。下面分析这个resource函数:
@webob.dec.wsgify(RequestClass=Request)def resource(request): # 处理Request的函数route_args = request.environ.get('wsgiorg.routing_args')if route_args:args = route_args[1].copy()else:args = {}# NOTE(jkoelker) by now the controller is already found, remove# it from the args if it is in the matchdictargs.pop('controller', None)fmt = args.pop('format', None)action = args.pop('action', None) # 获取请求中的format和action,移除controller。content_type = format_types.get(fmt,request.best_match_content_type())language = request.best_match_language()deserializer = deserializers.get(content_type) # 从deserializers中获取Content_type对应的deserializer。serializer = serializers.get(content_type) # 序列化同理。try:if request.body:args['body'] = deserializer.deserialize(request.body)['body'] # 将request中的body反序列化,e.g.str -> json。# Routes library is dumb and cuts off everything after last dot (.)# as format. At the same time, it doesn't enforce format suffix,# which combined makes it impossible to pass a 'id' with dots# included (the last section after the last dot is lost). This is# important for some API extensions like tags where the id is# really a tag name that can contain special characters.# # To work around the Routes behaviour, we will attach the suffix# back to id if it's not one of supported formats (atm json only).# This of course won't work for the corner case of a tag name that# actually ends with '.json', but there seems to be no better way# to tackle it without breaking API backwards compatibility.if fmt is not None and fmt not in format_types:args['id'] = '.'.join([args['id'], fmt])method = getattr(controller, action) # 从controller获取执行action的函数。result = method(request=request, **args) # 执行action,相关参数经反序列化后通过args参数传入controller。except Exception as e:mapped_exc = api_common.convert_exception_to_http_exc(e, faults,language)if hasattr(mapped_exc, 'code') and 400 <= mapped_exc.code < 500:LOG.info(_LI('%(action)s failed (client error): %(exc)s'),{'action': action, 'exc': mapped_exc})else:LOG.exception(_LE('%(action)s failed: %(details)s'),{'action': action,'details': utils.extract_exc_details(e),})raise mapped_excstatus = action_status.get(action, 200)body = serializer.serialize(result) # 将result序列化,e.g.json -> str。# NOTE(jkoelker) Comply with RFC2616 section 9.7if status == 204:content_type = ''body = Nonereturn webob.Response(request=request, status=status, # 构造Response进行返回。content_type=content_type,body=body)
- 从租户提交的请求中获取相关参数(formate、action等);
- 根据action的类型从controller中获取相应处理函数;
- 调用获取到的处理函数得到结果;
- 最后返回response;
- 此外,还进行了序列化和反序列化的工作。
class APIRouter(base_wsgi.Router):def __init__(self, **local_config):col_kwargs = dict(collection_actions=COLLECTION_ACTIONS,member_actions=MEMBER_ACTIONS)def _map_resource(collection, resource, params, parent=None):allow_bulk = cfg.CONF.allow_bulkcontroller = base.create_resource( # 1collection, resource, plugin, params, allow_bulk=allow_bulk,parent=parent, allow_pagination=True,allow_sorting=True)path_prefix = Noneif parent:path_prefix = "/%s/{%s_id}/%s" % (parent['collection_name'],parent['member_name'],collection)mapper_kwargs = dict(controller=controller, # 2requirements=REQUIREMENTS,path_prefix=path_prefix,**col_kwargs)return mapper.collection(collection, resource, # 3**mapper_kwargs)
create_resource返回的(即这里的controller变量)是经过webob.dec.wsgify修饰后的resource函数。然后,在2中,构造传入mapper.collection函数的参数,其中最关键的就是controller变量。最后,在3中,调用mapper.collection完成该resource的各个action的map动作。
转载于:https://www.cnblogs.com/Luka-Modric/p/8258385.html
Ocata Neutron代码分析(六)——APIRouter的初始化(3)顶级resource的map过程相关推荐
- Ocata Neutron代码分析(六)——APIRouter的初始化(1)加载core plugin和service plugin...
在分析api-paste.ini时,曾分析到wsgi app neutronapiapp_v2_0是直接调用/neutron/api/v2/router.py中APIRouter的factory方法: ...
- Ocata Neutron代码分析(六)——APIRouter的初始化(2)PluginAwareExtensionManager的初始化...
上篇分析了core plugin和service plugin的加载过程.APIRouter的构造函数下一步将进行PluginAwareExtensionManager的初始化: ext_mgr = ...
- Ocata Neutron代码分析(一)——Neutron API启动过程分析
首先,Neutron Server作为一种服务(neutron-server.service),可以到Neutron项目目录中的setup.cfg配置文件中找到对应的代码入口. [entry_poin ...
- Linux 网桥代码分析 六 网桥数据转发函数分析
对于数据包转发函数,主要是分为两大类:数据转发到指定端口.数据扩散到所有端口. 下面就从这两方面进行分析: 一 数据转发到指定端口 对于数据转发到指定端口的功能,也可以分为两个方面:对入口流量进行的 ...
- DSS 代码分析【启动、初始化流程】
DSS加载module及和module交互的流程,如下: (1).DSS在fork子进程后调用StartServer启动服务 调用OS.OSThread.Socket.SocketUtils.QTSS ...
- linux内存映射起始地址,内存初始化代码分析(三):创建系统内存地址映射
内存初始化代码分析(三):创建系统内存地址映射 作者:linuxer 发布于:2016-11-24 12:08 分类:内存管理 一.前言 经过内存初始化代码分析(一)和内存初始化代码分析(二)的过渡, ...
- Android4.0图库Gallery2代码分析(二) 数据管理和数据加载
Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Androi ...
- lighttpd1.4.18代码分析
lighttpd1.4.18代码分析(八)--状态机(2)CON_STATE_READ状态 posted @ 2008-09-24 10:50 那谁 阅读(2225) | 评论 (1) 编辑 lig ...
- 嵌入式Linux内核移植相关代码分析(转)
本文通过整理之前研发的一个项目(ARM7TDMI +uCLinux),分析内核启动过程及需要修改的文件,以供内核移植者参考.整理过程中也同时参考了众多网友的帖子,在此谢过.由于整理过程匆忙,难免 错误 ...
最新文章
- mongodb不等于某个值_MongoDb进阶实践之四 MongoDB查询命令详述
- 中文预训练模型ZEN开源,效果领域内最佳,创新工场港科大出品
- Android7.1修改系统默认多媒体音量大小
- 别再双塔了!谷歌提出DSI索引,检索效果吊打双塔,零样本超BM25!
- ddr4 lpddr4区别_i3 10100F和i5 9400F哪个好?区别有多大?两者性能对比评测_硬件评测...
- micropython教程nucleo-f767zi开发板_教你做CMSIS-DAP仿真器(基于Nucleo-F767ZI)
- VBA中msgbox的用法小结
- 法国PSA集团宣布,2018年就推出自动驾驶技术
- Windows7 的激活命令小结
- ps,ae,ui,ai,pr,cad,3DMAX,c4d,cdr,摄影后期
- Sublime Text编辑器设置中文
- 微软,招 Java 了!
- 电脑公司特别版5.0的驱动集成方法
- VTK:交互与拾取——点拾取
- a标签在微信iOS版本的解析没有问题,但是在安卓版就解析不出来
- [POJ1637]SightseeingTour
- java获取环境变量路径/java获取环境变量和系统属性
- [前端基础] JavaScript 进阶篇
- iOS 9公测开启 智能预测/省电模式亮相
- Android集成银联支付
热门文章
- formate在python_python的format方法
- 商品属性与商品产品之间的表设计结构,供参考!
- 完全掌握Python: 在一门课程中使用 Python 编程所需的一切 | Complete Python Mastery
- 三步必杀【洛谷P4231】
- markdown的基本使用方法 1
- “飞天”就是一个操作系统,最重要的功能就是资源管理;这套系统简单说就是把所有资源抽象成一台计算机,并通过互联网提供计算服务。...
- ps图层锁定后如何解锁
- 【学习笔记之java报错】Description The server encountered an unexpected condition that prevented it from fulf
- Set? set和Set set的区别?
- 元宇宙办公穿越时空奥秘探索无限可能