热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OcataNeutron代码分析(六)——APIRouter的初始化(3)顶级resource的map过程

在完成了plugins和extensions的加载后,进行四个顶级resource(分别是network、subnet、subnetpool和port&

在完成了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'])

map过程的关键就是调用Mapper类的函数来实现,这里首先实例化了Mapper类。
接着,调用其connect函数来进行map。这是一个最简单的map方式。这里匹配到的url为http://controller_ip:neutron_server_port/v2.0/,controller_ip和neutron_server_port在配置文件中指定,/v2.0为api-paste.ini中指定的匹配url。能与该url匹配的请求的controller是Index类的__call__函数,即能与该url匹配的request将交给Index类中的__call__函数来处理,这样的处理函数一般为一个经过webob.dec.wsgify修饰后的函数。
最后,依次调用_map_resource函数对RESOURCES中的各个顶级resource进行map,并注册各个顶级resource。向_map_resource传入的参数分别是collection(resource的集合的名称,string)、resource(resource的名称,string)和resource相关的属性(dict)。
下面重点分析_map_resource函数:

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)

_map_resource函数主要包含了三个步骤:
  1. 调用/neutron/api/v2/base.py中的create_resource函数来构造请求的处理函数(即上面提到的controller);
  2. 构造传入mapper.collection函数的参数mapper_kwargs;
  3. 调用mapper.collection函数来实际进行map动作。
先分析create_resource函数:

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)

该函数首先实例化Controller类赋给controller变量,然后将controller作为参数调用/neutron/api/v2/resource.py的Resource函数。
先看看Controller的构造函数:

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)

Controller的构造函数主要进行了参数的赋值、参数的合理性检查等。这里最重要的成员变量是self._plugin_handlers,它是一个对该resource采取的action名称与对应处理函数名称的字典。以network这一resource为例,其_plugin_handlers如下:
{'list': 'get_networks', 'show': 'get_network', 'create': 'create_network', 'update': 'update_network', 'delete': 'delete_network'}
分别表示:获取network列表,获取某个network,创建某个network,更新某个network和删除某个network。
后续流程会通过这个变量来获取相应处理函数的名称。
实例化后的controller变量传入/neutron/api/v2/resource.py的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&#39;s not one of supported formats (atm json only).# This of course won&#39;t work for the corner case of a tag name that# actually ends with &#39;.json&#39;, 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[&#39;id&#39;] &#61; &#39;.&#39;.join([args[&#39;id&#39;], fmt])method &#61; getattr(controller, action) # 从controller获取执行action的函数。result &#61; method(request&#61;request, **args) # 执行action&#xff0c;相关参数经反序列化后通过args参数传入controller。except Exception as e:mapped_exc &#61; api_common.convert_exception_to_http_exc(e, faults,language)if hasattr(mapped_exc, &#39;code&#39;) and 400 <&#61; mapped_exc.code <500:LOG.info(_LI(&#39;%(action)s failed (client error): %(exc)s&#39;),{&#39;action&#39;: action, &#39;exc&#39;: mapped_exc})else:LOG.exception(_LE(&#39;%(action)s failed: %(details)s&#39;),{&#39;action&#39;: action,&#39;details&#39;: utils.extract_exc_details(e),})raise mapped_excstatus &#61; action_status.get(action, 200)body &#61; serializer.serialize(result) # 将result序列化&#xff0c;e.g.json -> str。# NOTE(jkoelker) Comply with RFC2616 section 9.7if status &#61;&#61; 204:content_type &#61; &#39;&#39;body &#61; Nonereturn webob.Response(request&#61;request, status&#61;status, # 构造Response进行返回。content_type&#61;content_type,body&#61;body)

总而言之&#xff0c;resource函数主要完成以下几个工作&#xff1a;
  1. 从租户提交的请求中获取相关参数&#xff08;formate、action等&#xff09;&#xff1b;
  2. 根据action的类型从controller中获取相应处理函数&#xff1b;
  3. 调用获取到的处理函数得到结果&#xff1b;
  4. 最后返回response&#xff1b;
  5. 此外&#xff0c;还进行了序列化和反序列化的工作。
所以&#xff0c;先在create_resource函数中实例化的controller&#xff0c;包含了所有action类型&#xff08;包括index、show、create、update和delete&#xff09;的实现函数。针对某个resource的某个action经过resource函数&#xff0c;最终还是来到了controller中的相应action函数中进行处理。具体action函数的处理会在后续章节中分析。
下面回到_map_resource函数的分析中&#xff1a;

class APIRouter(base_wsgi.Router):def __init__(self, **local_config):col_kwargs &#61; dict(collection_actions&#61;COLLECTION_ACTIONS,member_actions&#61;MEMBER_ACTIONS)def _map_resource(collection, resource, params, parent&#61;None):allow_bulk &#61; cfg.CONF.allow_bulkcontroller &#61; base.create_resource( # 1collection, resource, plugin, params, allow_bulk&#61;allow_bulk,parent&#61;parent, allow_pagination&#61;True,allow_sorting&#61;True)path_prefix &#61; Noneif parent:path_prefix &#61; "/%s/{%s_id}/%s" % (parent[&#39;collection_name&#39;],parent[&#39;member_name&#39;],collection)mapper_kwargs &#61; dict(controller&#61;controller, # 2requirements&#61;REQUIREMENTS,path_prefix&#61;path_prefix,**col_kwargs)return mapper.collection(collection, resource, # 3**mapper_kwargs)

create_resource返回的&#xff08;即这里的controller变量&#xff09;是经过webob.dec.wsgify修饰后的resource函数。然后&#xff0c;在2中&#xff0c;构造传入mapper.collection函数的参数&#xff0c;其中最关键的就是controller变量。最后&#xff0c;在3中&#xff0c;调用mapper.collection完成该resource的各个action的map动作。


转:https://www.cnblogs.com/Luka-Modric/p/8258385.html



推荐阅读
  • 本文探讨了 Kafka 集群的高效部署与优化策略。首先介绍了 Kafka 的下载与安装步骤,包括从官方网站获取最新版本的压缩包并进行解压。随后详细讨论了集群配置的最佳实践,涵盖节点选择、网络优化和性能调优等方面,旨在提升系统的稳定性和处理能力。此外,还提供了常见的故障排查方法和监控方案,帮助运维人员更好地管理和维护 Kafka 集群。 ... [详细]
  • Squaretest:自动生成功能测试代码的高效插件
    本文将介绍一款名为Squaretest的高效插件,该工具能够自动生成功能测试代码。使用这款插件的主要原因是公司近期加强了代码质量的管控,对各项目进行了严格的单元测试评估。Squaretest不仅提高了测试代码的生成效率,还显著提升了代码的质量和可靠性。 ... [详细]
  • 在前文探讨了Spring如何为特定的bean选择合适的通知器后,本文将进一步深入分析Spring AOP框架中代理对象的生成机制。具体而言,我们将详细解析如何通过代理技术将通知器(Advisor)中包含的通知(Advice)应用到目标bean上,以实现切面编程的核心功能。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 本文详细介绍了一种利用 ESP8266 01S 模块构建 Web 服务器的成功实践方案。通过具体的代码示例和详细的步骤说明,帮助读者快速掌握该模块的使用方法。在疫情期间,作者重新审视并研究了这一未被充分利用的模块,最终成功实现了 Web 服务器的功能。本文不仅提供了完整的代码实现,还涵盖了调试过程中遇到的常见问题及其解决方法,为初学者提供了宝贵的参考。 ... [详细]
  • 在Java Web服务开发中,Apache CXF 和 Axis2 是两个广泛使用的框架。CXF 由于其与 Spring 框架的无缝集成能力,以及更简便的部署方式,成为了许多开发者的首选。本文将详细介绍如何使用 CXF 框架进行 Web 服务的开发,包括环境搭建、服务发布和客户端调用等关键步骤,为开发者提供一个全面的实践指南。 ... [详细]
  • 本文介绍了如何利用 Delphi 中的 IdTCPServer 和 IdTCPClient 控件实现高效的文件传输。这些控件在默认情况下采用阻塞模式,并且服务器端已经集成了多线程处理,能够支持任意大小的文件传输,无需担心数据包大小的限制。与传统的 ClientSocket 相比,Indy 控件提供了更为简洁和可靠的解决方案,特别适用于开发高性能的网络文件传输应用程序。 ... [详细]
  • 本文介绍了如何利用ObjectMapper实现JSON与JavaBean之间的高效转换。ObjectMapper是Jackson库的核心组件,能够便捷地将Java对象序列化为JSON格式,并支持从JSON、XML以及文件等多种数据源反序列化为Java对象。此外,还探讨了在实际应用中如何优化转换性能,以提升系统整体效率。 ... [详细]
  • 使用 Vuex 管理表单状态:当输入框失去焦点时自动恢复初始值 ... [详细]
  • Java中不同类型的常量池(字符串常量池、Class常量池和运行时常量池)的对比与关联分析
    在研究Java虚拟机的过程中,笔者发现存在多种类型的常量池,包括字符串常量池、Class常量池和运行时常量池。通过查阅CSDN、博客园等相关资料,对这些常量池的特性、用途及其相互关系进行了详细探讨。本文将深入分析这三种常量池的差异与联系,帮助读者更好地理解Java虚拟机的内部机制。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • Objective-C 中的委托模式详解与应用 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • 2018年9月21日,Destoon官方发布了安全更新,修复了一个由用户“索马里的海贼”报告的前端GETShell漏洞。该漏洞存在于20180827版本的某CMS中,攻击者可以通过构造特定的HTTP请求,利用该漏洞在服务器上执行任意代码,从而获得对系统的控制权。此次更新建议所有用户尽快升级至最新版本,以确保系统的安全性。 ... [详细]
  • 在腾讯云服务器上部署Nginx的详细指南中,首先需要确保安装必要的依赖包。如果这些依赖包已安装,可直接跳过此步骤。具体命令包括 `yum -y install gcc gcc-c++ wget net-tools pcre-devel zlib-devel`。接下来,本文将详细介绍如何下载、编译和配置Nginx,以确保其在腾讯云服务器上顺利运行。此外,还将提供一些优化建议,帮助用户提升Nginx的性能和安全性。 ... [详细]
author-avatar
蔚-然之林
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有