2019独角兽企业重金招聘Python工程师标准>>>
随手记录一下查看nova代码时的笔记
nova.api.openstack.wsgi.ActionDispatcher模块解析:
class ActionDispatcher(object): """ 通过action名将方法名映射到本地方法。 """ def dispatch(self, *args, **kwargs): """ 查找并调用local方法.""" action = kwargs.pop('action', 'default') action_method = getattr(self, str(action), self.default) return action_method(*args, **kwargs) def default(self, data):#子类必须实现的方法 raise NotImplementedError()
nova.api.openstack.wsgi.JSONDeserializer模块解析:
class JSONDeserializer(ActionDispatcher): def _from_json(self, datastring): """将json字符串转为json对象""" try: return jsonutils.loads(datastring) except ValueError: msg = _("cannot understand JSON") raise exception.MalformedRequestBody(reason=msg) def deserialize(self, datastring, action='default'): return self.dispatch(datastring, action=action) def default(self, datastring): return { 'body': self._from_json(datastring)}
nova.api.openstack.wsgi.JSONDictSerializer模块解析:
class JSONDictSerializer(ActionDispatcher): """ 将JSON请求body体序列化。 """ def serialize(self, data, action='default'): return self.dispatch(data, action=action) def default(self, data): return six.text_type(jsonutils.dumps(data))#调用six模块实现python2与3兼容处理
nova.api.openstack.wsgi.Resource模块解析:
class Resource(wsgi.Application): """ 处理(反)序列化和控制器分发的WSGI app. WSGI app读取RoutesMiddleware提供的路由信息,并在其控制器上调用请求的action方法。 所有控制器action方法都必须接受'req'参数,它是传入的wsgi.Request。 如果操作是PUT或POST,控制器方法还必须接受一个“body”参数(反序列化的请求体)。 可能会引发webob.exc异常或返回dict,, 它将被按请求的内容类型序列化。 从webob.exc.HTTPException继承的Exceptions 将自动包装在Fault() 中,以提供API友好的错误响应。 """ support_api_request_version = False def __init__(self, controller, inherits=None): """:param controller: routes库创建的对象 :param inherits: 另一种资源对象,该资源应该继承的扩展extensions. 应用于父资源的任何action extensions也将应用于此资源。 """ self.controller = controller self.default_serializers = dict(json=JSONDictSerializer) # 复制actions字典 self.wsgi_actions = {} if controller: self.register_actions(controller) # 保存插件(extensions)的映射 self.wsgi_extensions = {} self.wsgi_action_extensions = {} self.inherits = inherits def register_actions(self, controller): """ 使用此资源注册控制器actions。""" actions = getattr(controller, 'wsgi_actions', {}) for key, method_name in actions.items(): self.wsgi_actions[key] = getattr(controller, method_name) def register_extensions(self, controller): """ 使用此资源注册控制器extensions。 """ extensions = getattr(controller, 'wsgi_extensions', []) for method_name, action_name in extensions: # 查找extending方法 extension = getattr(controller, method_name) if action_name: # action_name还不存在时,初始化列表... if action_name not in self.wsgi_action_extensions: self.wsgi_action_extensions[action_name] = [] self.wsgi_action_extensions[action_name].append(extension) else: # method_name还不存在时,初始化列表 if method_name not in self.wsgi_extensions: self.wsgi_extensions[method_name] = [] self.wsgi_extensions[method_name].append(extension) def get_action_args(self, request_environment): """ 解析routes创建的字典 .""" # 检查控制器是否有重写get_action_args(),有就调用重写的方法 if hasattr(self.controller, 'get_action_args'): return self.controller.get_action_args(request_environment) try: args = request_environment['wsgiorg.routing_args'][1].copy() except (KeyError, IndexError, AttributeError): return {} try: del args['controller'] except KeyError: pass try: del args['format'] except KeyError: pass return args def get_body(self, request): content_type = request.get_content_type() return content_type, request.body def deserialize(self, body): return JSONDeserializer().deserialize(body) def process_extensions(self, extensions, resp_obj, request, action_args): """处理插件(extensions)""" for ext in extensions: response = None #常规函数可以得到post-processing... try: with ResourceExceptionHandler(): response = ext(req=request, resp_obj=resp_obj, **action_args) except exception.VersionNotFoundForAPIMethod: # 如果附加的方法扩展(@wsgi.extends)名没有版本匹配,则不认为是错误。 跳过代码执行。 continue except Fault as ex: response = ex # response存在返回它,提前退出。 这实际上是代表一种失败模式。 response为None代表成功。 if response: return response return None def _should_have_body(self, request): return request.method in _METHODS_WITH_BODY #POST和PUT应该包含body内容 @webob.dec.wsgify(RequestClass=Request) def __call__(self, request): """ 控制(反)序列化和方法分派的WSGI方法。 """ if self.support_api_request_version: # 根据报头设置请求的API版本 try: request.set_api_version_request() except exception.InvalidAPIVersionString as e: return Fault(webob.exc.HTTPBadRequest( explanation=e.format_message())) except exception.InvalidGlobalAPIVersion as e: return Fault(webob.exc.HTTPNotAcceptable( explanation=e.format_message())) # 标识action, 参数和请求的内容类型 action_args = self.get_action_args(request.environ) action = action_args.pop('action', None) # 过滤掉InvalidContentTypes try: content_type, body = self.get_body(request) accept = request.best_match_content_type() except exception.InvalidContentType: msg = _("Unsupported Content-Type") return Fault(webob.exc.HTTPUnsupportedMediaType(explanation=msg)) # 通过这种方式拆分函数,可以通过包装现有函数的外部工具进行审计。 # 由于@webob.dec.wsgify()装饰器的作用, 如果试图审计__call__(),可能会遇到报错 return self._process_stack(request, action, action_args, content_type, body, accept) def _process_stack(self, request, action, action_args, content_type, body, accept): """ 实现processing stack.""" # 获取实现方法 try: meth, extensions = self.get_method(request, action, content_type, body) except (AttributeError, TypeError): return Fault(webob.exc.HTTPNotFound()) except KeyError as ex: msg = _("There is no such action: %s") % ex.args[0] return Fault(webob.exc.HTTPBadRequest(explanation=msg)) except exception.MalformedRequestBody: msg = _("Malformed request body") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) if body: msg = _("Action: '%(action)s', calling method: %(meth)s, body: " "%(body)s") % { 'action': action, 'body': six.text_type(body, 'utf-8'), 'meth': str(meth)} LOG.debug(strutils.mask_password(msg)) else: LOG.debug("Calling method '%(meth)s'", { 'meth': str(meth)}) # 反序列化request body... try: contents = {} if self._should_have_body(request): # 允许请求方法为PUT和POST的body为空 if request.content_length == 0: contents = { 'body': None} else: contents = self.deserialize(body) except exception.MalformedRequestBody: msg = _("Malformed request body") return Fault(webob.exc.HTTPBadRequest(explanation=msg)) # 更新action参数 action_args.update(contents) #比对project_id project_id = action_args.pop("project_id", None) context = request.environ.get('nova.context') if (context and project_id and (project_id != context.project_id)): msg = _("Malformed request URL: URL's project_id '%(project_id)s'" " doesn't match Context's project_id" " '%(context_project_id)s'") % \ { 'project_id': project_id, 'context_project_id': context.project_id} return Fault(webob.exc.HTTPBadRequest(explanation=msg)) response = None try: with ResourceExceptionHandler(): action_result = self.dispatch(meth, request, action_args) except Fault as ex: response = ex if not response: # 无异常时; 将action_result转换ResponseObject resp_obj = None if type(action_result) is dict or action_result is None: resp_obj = ResponseObject(action_result) elif isinstance(action_result, ResponseObject): resp_obj = action_result else: response = action_result # 运行post-processing插件(extensions) if resp_obj: # 预序列化以设置response对象 if hasattr(meth, 'wsgi_code'): resp_obj._default_code = meth.wsgi_code # 调用process_extensions response = self.process_extensions(extensions, resp_obj, request, action_args) if resp_obj and not response: response = resp_obj.serialize(request, accept) if hasattr(response, 'headers'): for hdr, val in list(response.headers.items()): if six.PY2: # 在Py2.X Headers 必须是字节字符串 response.headers[hdr] = utils.utf8(val) else: # 在Py3.X Headers 必须是utf-8符串 response.headers[hdr] = encodeutils.safe_decode( utils.utf8(val)) if not request.api_version_request.is_null(): response.headers[API_VERSION_REQUEST_HEADER] = \ 'compute ' + request.api_version_request.get_string() response.headers[LEGACY_API_VERSION_REQUEST_HEADER] = \ request.api_version_request.get_string() response.headers.add('Vary', API_VERSION_REQUEST_HEADER) response.headers.add('Vary', LEGACY_API_VERSION_REQUEST_HEADER) return response def get_method(self, request, action, content_type, body): meth, extensions = self._get_method(request, action, content_type, body) if self.inherits: _meth, parent_ext = self.inherits.get_method(request, action, content_type, body) extensions.extend(parent_ext) return meth, extensions def _get_method(self, request, action, content_type, body): """ 查找action-specific的方法及其extensions。""" # 查找方法 try: if not self.controller: meth = getattr(self, action) else: meth = getattr(self.controller, action) except AttributeError: if (not self.wsgi_actions or action not in _ROUTES_METHODS + ['action']): # 找不到抛出error raise else: return meth, self.wsgi_extensions.get(action, []) if action == 'action': #此方法会从body中找出action_name,此时的body应该是只有一个key的已经被序列化后的json。 action_name = action_peek(body) else: action_name = action # 查找action方法 return (self.wsgi_actions[action_name], self.wsgi_action_extensions.get(action_name, [])) def dispatch(self, method, request, action_args): """分发一个call到action-specific方法.""" try: return method(req=request, **action_args) except exception.VersionNotFoundForAPIMethod: return Fault(webob.exc.HTTPNotFound())