分享

Openstack Cinder中建立volume过程的源码解析(3)

shihailong123 发表于 2014-11-22 13:29:15 [显示全部楼层] 回帖奖励 阅读模式 关闭右栏 0 14278
阅读导读:
1.get_serializer的作用?
2.isgeneratorfunction是用来做什么的?
3.什么是特殊的generator方法?
4.进行响应信息的序列化操作的步骤?
5.简述在cinder模块中实现客户端发送过来的请求信息操作的主要的步骤?



感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
3.请求中body部分的反序列化
我们来看语句:
  1. try:
  2.     if content_type:
  3.         #确定反序列化的方法,实现对body的反序列化操作;
  4.         #meth = <bound method VolumeController.create of <cinder.api.v1.volumes.VolumeController object at 0x29cdb50>>
  5.         #content_type = application/json
  6.         #body = {"volume": {"status": "creating", "availability_zone": null, "source_volid": null, "display_description": null, "snapshot_id": null, "user_id": null, "size": 1, "display_name": "shinian01",
  7. "imageRef": null, "attach_status": "detached", "volume_type": null, "project_id": null, "metadata": {}}}
  8.         contents = self.deserialize(meth, content_type, body)
  9.     else:
  10.         contents = {}
复制代码
这部分语句实现的功能是确定反序列化方法,并实现对body的反序列化操作。
我们来看方法deserialize的源码实现:
  1. def deserialize(self, meth, content_type, body):
  2.         """
  3.         #meth = >
  4.         #content_type = application/json
  5.         #body = {"volume": {"status": "creating", "availability_zone": null, "source_volid": null, "display_description": null, "snapshot_id": null, "user_id": null, "size": 1, "display_name": "shinian01", "imageRef": null, "attach_status": "detached", "volume_type": null, "project_id": null, "metadata": {}}}               
  6.         """
  7.         # 获取指定的反序列化方法;
  8.         meth_deserializers = getattr(meth, 'wsgi_deserializers', {})
  9.         #meth_deserializers = {'xml': }
  10.         
  11.         try:
  12.             #_MEDIA_TYPE_MAP = {
  13.             #'application/vnd.openstack.volume+json': 'json',
  14.             #'application/json': 'json',
  15.             #'application/vnd.openstack.volume+xml': 'xml',
  16.             #'application/xml': 'xml',
  17.             #'application/atom+xml': 'atom',
  18.             #}
  19.             #content_type = application/json
  20.             mtype = _MEDIA_TYPE_MAP.get(content_type, content_type)
  21.             #mtype = json
  22.             
  23.             if mtype in meth_deserializers:
  24.                 deserializer = meth_deserializers[mtype]
  25.             else:
  26.                 deserializer = self.default_deserializers[mtype]
  27.             #deserializer =  
  28.             #注:确定所使用的反序列化方法;
  29.             
  30.         except (KeyError, TypeError):
  31.             raise exception.InvalidContentType(content_type=content_type)
  32.         #deserializer().deserialize = >
  33.         #根据确定的反序列化方法对body进行反序列化的实现;
  34.         return deserializer().deserialize(body)
复制代码
这个方法的实现主要分为两个步骤,获取合适的反序列化方法和应用指定的反序列化方法对body进行反序列化操作。
本实例中得到的应用的反序列化方法为 cinder.api.openstack.wsgi.JSONDeserializer.deserialize,至于body具体的反序列化实现过程这里不再进行深入的分析了。
我们回到方法_process_stack中,来看body部分实现反序列化操作后的输出示例:
  1. #contents = {'body': {u'volume': {u'status': u'creating',
  2.                                   u'user_id': None,
  3.                                   u'imageRef': None,
  4.                                   u'availability_zone': None,
  5.                                   u'attach_status': u'detached',
  6.                                   u'display_description': None,
  7.                                   u'metadata': {},
  8.                                   u'source_volid': None,
  9.                                   u'snapshot_id': None,
  10.                                   u'display_name': u'shinian01',
  11.                                   u'project_id': None,
  12.                                   u'volume_type': None,
  13.                                   u'size': 1}}}
复制代码
4.所获取的action相关的扩展方法的执行
我们来关注语句:
  1. response, post = self.pre_process_extensions(extensions, request, action_args)
复制代码
这条语句实现的功能就是执行之前获取的扩展方法,我们来看方法 pre_process_extensions的源码实现
  1. def pre_process_extensions(self, extensions, request, action_args):
  2.         """
  3.         extensions = [>]
  4.         request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0
  5.                   ......
  6.         action_args = {'body': {u'volume': {u'status': u'creating',
  7.                                             u'user_id': None,
  8.                                             u'imageRef': None,
  9.                                             u'availability_zone': None,
  10.                                             'scheduler_hints': {},
  11.                                             u'attach_status': u'detached',
  12.                                             u'display_description': None,
  13.                                             u'metadata': {},
  14.                                             u'source_volid': None,
  15.                                             u'snapshot_id': None,
  16.                                             u'display_name': u'shinian01',
  17.                                             u'project_id': None,
  18.                                             u'volume_type': None,
  19.                                             u'size': 1}}}
  20.         """
  21.         # List of callables for post-processing extensions
  22.         post = []
  23.         for ext in extensions:            
  24.             # isgeneratorfunction:判断一个方法是否是特殊的generator方法;
  25.             if inspect.isgeneratorfunction(ext):
  26.                 response = None
  27.                 try:
  28.                     with ResourceExceptionHandler():
  29.                         # ext = [>]
  30.                         gen = ext(req=request, **action_args)
  31.                         """
  32.                         gen =  
  33.                         def create(self, req, body):
  34.                             hints = self._extract_scheduler_hints(body)
  35.                             if 'volume' in body:
  36.                                 body['volume']['scheduler_hints'] = hints
  37.                                 yield
  38.                         """
  39.                         response = gen.next()
  40.                         #response = None
  41.                 except Fault as ex:
  42.                     response = ex
  43.                 # We had a response...
  44.                 #response = None
  45.                 if response:
  46.                     return response, []
  47.                 # No response, queue up generator for post-processing
  48.                 post.append(gen)
  49.                 #post = []
  50.             else:
  51.                 # Regular functions only perform post-processing
  52.                 post.append(ext)
  53.         return None, reversed(post)
复制代码
在这个方法中,核心的语句就是:
  1. gen = ext(req=request, **action_args)
复制代码
之前要判断一下这里调用的ext方法是否是一个生成器,在本实例中,这里ext=[>] ,即是之前我们获取的扩展方法,在这里进行具体的调用执行。至于方法cinder.api.contrib.scheduler_hints.SchedulerHintsController.create的具体执行过程这里不再进行具体的分析,我的理解是这些扩展方法所实现的功能就是为了其匹配的action方法进行某些功能方面的补充。
5.执行具体的action方法,如卷的建立方法create
我们回到方法_process_stack来看语句:
  1. action_result = self.dispatch(meth, request, action_args)
复制代码
这条语句实现的功能就是执行之前获取的action方法,获取并返回方法执行的结果,为后续形成方法执行的响应信息做准备。
我们来看方法dispatch的源码实现:
  1. def dispatch(self, method, request, action_args):
  2.         """
  3.         Dispatch a call to the action-specific method.      
  4.         method = >
  5.         request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0
  6.                   ......
  7.                   {"volume": {"status": "creating",
  8.                               "availability_zone": null,
  9.                               "source_volid": null,
  10.                               "display_description": null,
  11.                               "snapshot_id": null,
  12.                               "user_id": null,
  13.                               "size": 1,
  14.                               "display_name": "shinian01",
  15.                               "imageRef": null,
  16.                               "attach_status": "detached",
  17.                               "volume_type": null,
  18.                               "project_id": null,
  19.                               "metadata": {}}}
  20.         action_args = {'body': {u'volume': {u'status': u'creating',
  21.                                             u'user_id': None,
  22.                                             u'imageRef': None,
  23.                                             u'availability_zone': None,
  24.                                             'scheduler_hints': {},
  25.                                             u'attach_status': u'detached',
  26.                                             u'display_description': None,
  27.                                             u'metadata': {},
  28.                                             u'source_volid': None,
  29.                                             u'snapshot_id': None,
  30.                                             u'display_name': u'shinian01',
  31.                                             u'project_id': None,
  32.                                             u'volume_type': None,
  33.                                             u'size': 1}}}
  34.         """         
  35.         return method(req=request, **action_args)
复制代码
我们可以看到这里终于调用了之前获取的action方法cinder.api.v1.volumes. VolumeController.create,并返回执行方法过后返回的结果信息。
我们回到方法dispatch中来看执行action方法过后返回的结果信息:
  1. action_result = {'volume': {'status': 'creating',
  2.                             'display_name': u'shinian01',
  3.                             'attachments': [],
  4.                             'availability_zone': 'nova',
  5.                             'bootable': 'false',
  6.                             'created_at': datetime.datetime(2014, 3, 27, 7, 39, 42, 673944),
  7.                             'display_description': None,
  8.                             'volume_type': 'None',
  9.                             'snapshot_id': None,
  10.                             'source_volid': None,
  11.                             'metadata': {},
  12.                             'id': 'e50e8f12-cc56-47eb-a488-64ae9f442464',
  13.                             'size': 1}}
复制代码
至于方法create如何实现了volume的建立,我们会在下一篇博客中进行深入的分析,本篇博客这里先不进行解析。
6.响应信息的生成
准确来说,这部分实现的功能是基于之前获取的action方法执行结果,经过填充信息和格式处理,实现形成响应信息。
我们来看方法dispatch中的这部分的源码:
  1. if not response:
  2.             resp_obj = None
  3.             if type(action_result) is dict or action_result is None:
  4.                 resp_obj = ResponseObject(action_result)
  5.                 #注:注意这里对响应信息类进行了初始化操作,即形成了响应信息中若干参数的赋值;
  6.                
  7.             elif isinstance(action_result, ResponseObject):
  8.                 resp_obj = action_result
  9.             else:
  10.                 response = action_result
  11.             
  12.             # 注:resp_obj应该是作为响应的头文件对象;
  13.             if resp_obj:
  14.                 # resp_obj =  
  15.                 # request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0
  16.                 #           ......
  17.                 # _set_request_id_header:根据request的上下文信息,设置resp_obj的request_id值;
  18.                 _set_request_id_header(request, resp_obj)
  19.                 # 获取用于设置响应模板的类的实例化对象;
  20.                 serializers = getattr(meth, 'wsgi_serializers', {})
  21.                
  22.                 # serializers = {'xml': }
  23.                 # _bind_method_serializers:这个方法是实现绑定指定的相应模板类serializers到响应对象resp_obj操作;
  24.                 resp_obj._bind_method_serializers(serializers)
  25.                
  26.                 # hasattr(meth, 'wsgi_code') = False
  27.                 if hasattr(meth, 'wsgi_code'):
  28.                     resp_obj._default_code = meth.wsgi_code
  29.                 # accept = application/json
  30.                 # self.default_serializers = {'xml': , 'json': }
  31.                 # preserialize:根据accept确定相应对象所要使用的序列化方法(类),并进行类的初始化操作;   
  32.                 resp_obj.preserialize(accept, self.default_serializers)
  33.                 # Process post-processing extensions
  34.                 response = self.post_process_extensions(post, resp_obj, request, action_args)
  35.             
  36.             # resp_obj =  
  37.             # response = None
  38.             if resp_obj and not response:
  39.                 # serialize:进行响应信息的序列化操作;
  40.                 # 1.获取用于序列化操作的方法;
  41.                 # 2.形成响应的头信息;
  42.                 # 3.通过序列化操作,形成响应的body信息;
  43.                 # 4.返回响应信息;
  44.                 response = resp_obj.serialize(request, accept, self.default_serializers)
  45.                 """
  46.                 accept = application/json
  47.                 self.default_serializers = {'xml': ,
  48.                                             'json': }
  49.                 response = 200 OK
  50.                 x-compute-request-id: req-66a5680c-d160-493e-b333-7caacefc80f7
  51.                 Content-Type: application/json
  52.                 Content-Length: 344
  53.                 {"volume": {"status": "creating",
  54.                             "display_name": "shinian01",
  55.                             "attachments": [],
  56.                             "availability_zone": "nova",
  57.                             "bootable": "false",
  58.                             "created_at": "2014-03-27T07:39:42.673944",
  59.                             "display_description": null,
  60.                             "volume_type": "None",
  61.                             "snapshot_id": null,
  62.                             "source_volid": null,
  63.                             "metadata": {},
  64.                             "id": "e50e8f12-cc56-47eb-a488-64ae9f442464",
  65.                             "size": 1}}
  66.                 """
  67.         try:
  68.             msg_dict = dict(url=request.url, status=response.status_int)         
  69.             msg = _("%(url)s returned with HTTP %(status)d") % msg_dict
  70.         except AttributeError as e:
  71.             msg_dict = dict(url=request.url, e=e)
  72.             msg = _("%(url)s returned a fault: %(e)s") % msg_dict
  73.         LOG.info(msg)
  74.         """
  75.         response = 200 OK
  76.         x-compute-request-id: req-66a5680c-d160-493e-b333-7caacefc80f7
  77.         Content-Type: application/json
  78.         Content-Length: 344
  79.         {"volume": {"status": "creating",
  80.                     "display_name": "shinian01",
  81.                     "attachments": [],
  82.                     "availability_zone": "nova",
  83.                     "bootable": "false",
  84.                     "created_at": "2014-03-27T07:39:42.673944",
  85.                     "display_description": null,
  86.                     "volume_type": "None",
  87.                     "snapshot_id": null,
  88.                     "source_volid": null,
  89.                     "metadata": {},
  90.                     "id": "e50e8f12-cc56-47eb-a488-64ae9f442464",
  91.                     "size": 1}}
  92.         """
  93.         return response
复制代码
首先来看语句resp_obj = ResponseObject(action_result),这条语句实现的功能就是对响应信息类ResponseObject进行了初始化操作,即形成了响应信息中若干参数的赋值;
再来看语句resp_obj.preserialize(accept, self.default_serializers),这条语句实现的功能就是根据accept确定相应对象所要使用的序列化方法(类),并进行类的初始化操作;
在这部分代码中,最重要的语句就是response = resp_obj.serialize(request, accept, self.default_serializers),这条语句实现的就是生成响应信息中的头文件部分,并且根据确定的序列化方法,对之前获取的执行action的返回结果action_result为主体的信息,进行序列化操作,从而形成响应信息中的body部分,从而形成了完整的响应信息。我们具体来看方法serialize的实现源码:

  1. def serialize(self, request, content_type, default_serializers=None):
  2. """
  3. Serializes the wrapped object.
  4. request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0
  5. ......
  6. accept = application/json
  7. self.default_serializers = {'xml': ,
  8. 'json': }
  9.         1.获取用于序列化操作的方法;
  10.         2.形成响应的头信息;
  11.         3.通过序列化操作,形成响应的body信息;
  12.         4.返回响应信息;
  13.         """
  14.         if self.serializer:
  15.             serializer = self.serializer
  16.         else:
  17.             # get_serializer:为封装对象的实现返回序列化方法;
  18.             _mtype, _serializer = self.get_serializer(content_type, default_serializers)
  19.             
  20.             # 获取序列化类的实例化对象;
  21.             serializer = _serializer()
  22.         response = webob.Response()
  23.         # code:获取响应状态;
  24.         response.status_int = self.code
  25.         """
  26.         response = 200 OK
  27.                    Content-Type: text/html; charset=UTF-8
  28.                    Content-Length: 0
  29.         
  30.         response.status_int = 200
  31.         """
  32.         
  33.         #self._headers = {'x-compute-request-id': 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f'}
  34.         for hdr, value in self._headers.items():
  35.             response.headers[hdr] = value
  36.             #response.headers['x-compute-request-id'] = req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f
  37.             #response.headers = ResponseHeaders([('Content-Type', 'text/html; charset=UTF-8'),
  38.             #                                    ('Content-Length', '0'),
  39.             #                                    ('x-compute-request-id', 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f            #                                     ')])
  40.         
  41.         # 形成了响应的头信息;
  42.         response.headers['Content-Type'] = content_type
  43.         #response.headers = ResponseHeaders([('Content-Length', '0'),
  44.         #                                    ('x-compute-request-id', 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f'),
  45.         #                                    ('Content-Type', 'application/json')])
  46.         
  47.         #self.obj = {'volume': {'status': 'creating',
  48.         #                       'display_name': u'shinian01',
  49.         #                       'attachments': [],
  50.         #                       'availability_zone': 'nova',
  51.         #                       'bootable': 'false',
  52.         #                       'created_at': datetime.datetime(2014, 3, 29, 12, 36, 23, 998481),
  53.         #                       'display_description': None,
  54.         #                       'volume_type': 'None',
  55.         #                       'snapshot_id': None,
  56.         #                       'source_volid': None,
  57.         #                       'metadata': {},
  58.         #                       'id': '3f0aa242-9dab-48db-b63d-92b6dd38cf20',
  59.         #                       'size': 1}}
  60.         if self.obj is not None:
  61.             # 对self.obj进行序列化操作,形成响应的body部分;
  62.             response.body = serializer.serialize(self.obj)
  63.             #serializer.serialize = >
  64.             #response.body = {"volume": {"status": "creating", "display_name": "shinian01", "attachments": [], "availability_zone": "nova", "bootable": "false", "created_at": "2014-03-29T12:36:23.998481", "display_description": null, "volume_type": "None", "snapshot_id": null, "source_volid": null, "metadata": {}, "id": "3f0aa242-9dab-48db-b63d-92b6dd38cf20", "size": 1}}
  65.         """
  66.         response = 200 OK
  67.                    x-compute-request-id: req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f
  68.                    Content-Type: application/json
  69.                    Content-Length: 344
  70.                    {"volume": {"status": "creating",
  71.                                "display_name": "shinian01",
  72.                                "attachments": [],
  73.                                "availability_zone": "nova",
  74.                                "bootable": "false",
  75.                                "created_at": "2014-03-29T12:36:23.998481",
  76.                                "display_description": null,
  77.                                "volume_type": "None",
  78.                                "snapshot_id": null,
  79.                                "source_volid": null,
  80.                                "metadata": {},
  81.                                "id": "3f0aa242-9dab-48db-b63d-92b6dd38cf20",
  82.                                "size": 1}}
  83.         """
  84.         return response
复制代码
相关的代码解析请看源码中我的注释部分,具体来说,这部分代码实现的就是生成响应信息的头文件部分,以之前执行action方法所获取和返回的结果为主体,进行序列化操作,生成响应信息的body部分,从而形成完整的响应信息,并进行返回操作。
我们再回到方法_process_stack中,可见在方法的最后,返回了获取到的响应信息。
至此,在cinder模块中实现客户端发送过来的请求信息操作的主要的步骤已经全部解析完成。下一篇博客中,我将解析方法cinder.api.v1.volumes.VolumeController.create,来解析cinder是如何实现卷的建立的。





相关文章:
Openstack Cinder中建立volume过程的源码解析(1)
http://www.aboutyun.com/thread-10217-1-1.html
1.cinder中卷的建立的过程中,客户端传递过来的request的执行过程是怎样的?
2.__call__方法都通过什么方法封装?
3.如何调用指定中间件的__call__方法?


Openstack Cinder中建立volume过程的源码解析(2)
http://www.aboutyun.com/thread-10216-1-1.html
1.如何获取要执行的action方法及其相关的扩展方法?
2.Resource类中的__call__(self,request)方法如何实现?
3.meth的作用?
4.如何从request.environ中获取要执行的action方法?
5.如何对body进行反序列化操作?



Openstack Cinder中建立volume过程的源码解析(4)----以及taskflow相关解析
http://www.aboutyun.com/thread-10214-1-1.html
1.简述cinder是如何实现卷的建立的?
2.简述taskflow库来实现卷的简历过程?
3.如何根据给定id来检索获取单个的卷的类型?
4.如何构建并返回用于建立卷的flow?
5.如何声明flow是否是真的?
6.简述建立卷的flow的步骤?


Openstack Cinder中建立volume过程的源码解析(5)----以及taskflow相关解析
http://www.aboutyun.com/thread-10213-1-1.html
1.如何实现Flow类的初始化的?
2.用于卷的建立的flow中都添加了哪些task?
3.ExtractVolumeRequestTask类的作用是什么?
4.如何完全或部分的重置flow的内部的状态?
5.如何从给定的卷中提取卷的id信息?
6.OnFailureChangeStatusTask类的作用?

Openstack Cinder中建立volume过程的源码解析(6)----以及taskflow相关解析
http://www.aboutyun.com/thread-10212-1-1.html
1.如何来运行已经构建好的flow?
2.run的源码如何实现及实现过程是什么?
3.resume_it的实现过程是什么?
4.类Runner的初始化方法是什么?
5.run_it的源码如何实现?

Openstack Cinder中建立volume过程的源码解析(7)----以及taskflow相关解析
http://www.aboutyun.com/thread-10211-1-1.html
1.关于flow中task执行的重要语句的实现基本解析完成,如何实现?
2.如果卷的建立出现异常,则如何执行相关的逆转回滚操作?

Openstack Cinder中建立volume过程的源码解析(8)
http://www.aboutyun.com/thread-10219-1-1.html
1.VolumeCastTask的源码如何实现?
2.远程调用建立新卷的操作,有哪几个步骤?
3.task类VolumeCastTask具体是如何来实现根据请求信息进行卷的建立的?


Openstack Cinder中建立volume过程的源码解析(9)
http://www.aboutyun.com/thread-10210-1-1.html
1.如何实现create_volume的源码?
2.Cast如何实现远程调create_volume?
3.如何实现调用方法self.volume_rpcapi.create_volume来实现在目标主机上新卷的建立?




如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn









没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

推荐上一条 /2 下一条