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

来源:互联网 发布:软件开发研究成果报告 编辑:程序博客网 时间:2024/05/07 04:39

感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn


3.请求中body部分的反序列化

我们来看语句:

try:

    if content_type:

        #确定反序列化的方法,实现对body的反序列化操作;

        #meth = <bound method VolumeController.create of <cinder.api.v1.volumes.VolumeController object at 0x29cdb50>>

        #content_type = application/json

        #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": {}}}

        contents = self.deserialize(meth, content_type, body)
    else:

        contents = {}

这部分语句实现的功能是确定反序列化方法,并实现对body的反序列化操作。

我们来看方法deserialize的源码实现:

def deserialize(self, meth, content_type, body):         """         #meth = <bound method VolumeController.create of <cinder.api.v1.volumes.VolumeController object at 0x29cdb50>>         #content_type = application/json         #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": {}}}                       """         # 获取指定的反序列化方法;         meth_deserializers = getattr(meth, 'wsgi_deserializers', {})         #meth_deserializers = {'xml': <class 'cinder.api.v1.volumes.CreateDeserializer'>}                 try:             #_MEDIA_TYPE_MAP = {             #'application/vnd.openstack.volume+json': 'json',             #'application/json': 'json',             #'application/vnd.openstack.volume+xml': 'xml',             #'application/xml': 'xml',             #'application/atom+xml': 'atom',             #}             #content_type = application/json             mtype = _MEDIA_TYPE_MAP.get(content_type, content_type)             #mtype = json                         if mtype in meth_deserializers:                 deserializer = meth_deserializers[mtype]             else:                 deserializer = self.default_deserializers[mtype]             #deserializer = <class 'cinder.api.openstack.wsgi.JSONDeserializer'>             #注:确定所使用的反序列化方法;                     except (KeyError, TypeError):             raise exception.InvalidContentType(content_type=content_type)         #deserializer().deserialize = <bound method JSONDeserializer.deserialize of <cinder.api.openstack.wsgi.JSONDeserializer object at 0x3d07b10>>         #根据确定的反序列化方法对body进行反序列化的实现;         return deserializer().deserialize(body)
这个方法的实现主要分为两个步骤,获取合适的反序列化方法和应用指定的反序列化方法对body进行反序列化操作。

本实例中得到的应用的反序列化方法为 cinder.api.openstack.wsgi.JSONDeserializer.deserialize,至于body具体的反序列化实现过程这里不再进行深入的分析了。

我们回到方法_process_stack中,来看body部分实现反序列化操作后的输出示例:

#contents = {'body': {u'volume': {u'status': u'creating', 
                                  u'user_id': None, 
                                  u'imageRef': None, 
                                  u'availability_zone': None, 
                                  u'attach_status': u'detached', 
                                  u'display_description': None, 
                                  u'metadata': {}, 
                                  u'source_volid': None, 
                                  u'snapshot_id': None, 
                                  u'display_name': u'shinian01', 
                                  u'project_id': None, 
                                  u'volume_type': None, 
                                  u'size': 1}}}

4.所获取的action相关的扩展方法的执行

我们来关注语句:

response, post = self.pre_process_extensions(extensions, request, action_args)

这条语句实现的功能就是执行之前获取的扩展方法,我们来看方法 pre_process_extensions的源码实现:

    def pre_process_extensions(self, extensions, request, action_args):         """         extensions = [<bound method SchedulerHintsController.create of <cinder.api.contrib.scheduler_hints.SchedulerHintsController object at 0x2985a90>>]         request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0                   ......         action_args = {'body': {u'volume': {u'status': u'creating',                                             u'user_id': None,                                             u'imageRef': None,                                             u'availability_zone': None,                                             'scheduler_hints': {},                                             u'attach_status': u'detached',                                             u'display_description': None,                                             u'metadata': {},                                             u'source_volid': None,                                             u'snapshot_id': None,                                             u'display_name': u'shinian01',                                             u'project_id': None,                                             u'volume_type': None,                                             u'size': 1}}}         """         # List of callables for post-processing extensions         post = []         for ext in extensions:                        # isgeneratorfunction:判断一个方法是否是特殊的generator方法;             if inspect.isgeneratorfunction(ext):                 response = None                 try:                     with ResourceExceptionHandler():                         # ext = [<bound method SchedulerHintsController.create of <cinder.api.contrib.scheduler_hints.SchedulerHintsController object at 0x2985a90>>]                         gen = ext(req=request, **action_args)                         """                         gen = <generator object create at 0x3c03230>                          def create(self, req, body):                             hints = self._extract_scheduler_hints(body)                             if 'volume' in body:                                 body['volume']['scheduler_hints'] = hints                                 yield                         """                         response = gen.next()                         #response = None                 except Fault as ex:                     response = ex                 # We had a response...                 #response = None                 if response:                     return response, []                 # No response, queue up generator for post-processing                 post.append(gen)                 #post = [<generator object create at 0x3c03230>]             else:                 # Regular functions only perform post-processing                 post.append(ext)         return None, reversed(post)

在这个方法中,核心的语句就是:

gen = ext(req=request, **action_args)

之前要判断一下这里调用的ext方法是否是一个生成器,在本实例中,这里ext=[<bound method SchedulerHintsController.create of <cinder.api.contrib.scheduler_hints.SchedulerHintsController object at 0x2985a90>>] ,即是之前我们获取的扩展方法,在这里进行具体的调用执行。至于方法cinder.api.contrib.scheduler_hints.SchedulerHintsController.create的具体执行过程这里不再进行具体的分析,我的理解是这些扩展方法所实现的功能就是为了其匹配的action方法进行某些功能方面的补充。

5.执行具体的action方法,如卷的建立方法create

我们回到方法_process_stack来看语句:

action_result = self.dispatch(meth, request, action_args)

这条语句实现的功能就是执行之前获取的action方法,获取并返回方法执行的结果,为后续形成方法执行的响应信息做准备。

我们来看方法dispatch的源码实现:

    def dispatch(self, method, request, action_args):         """         Dispatch a call to the action-specific method.               method = <bound method VolumeController.create of <cinder.api.v1.volumes.VolumeController object at 0x3cafa90>>         request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0                   ......                   {"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": {}}}         action_args = {'body': {u'volume': {u'status': u'creating',                                             u'user_id': None,                                             u'imageRef': None,                                             u'availability_zone': None,                                             'scheduler_hints': {},                                             u'attach_status': u'detached',                                             u'display_description': None,                                             u'metadata': {},                                             u'source_volid': None,                                             u'snapshot_id': None,                                             u'display_name': u'shinian01',                                             u'project_id': None,                                             u'volume_type': None,                                             u'size': 1}}}         """                 return method(req=request, **action_args)
我们可以看到这里终于调用了之前获取的action方法cinder.api.v1.volumes. VolumeController.create,并返回执行方法过后返回的结果信息。

我们回到方法dispatch中来看执行action方法过后返回的结果信息:

action_result = {'volume': {'status': 'creating', 

                            'display_name': u'shinian01', 
                            'attachments': [], 
                            'availability_zone': 'nova', 
                            'bootable': 'false', 
                            'created_at': datetime.datetime(2014, 3, 27, 7, 39, 42, 673944), 
                            'display_description': None, 
                            'volume_type': 'None', 
                            'snapshot_id': None, 
                            'source_volid': None, 
                            'metadata': {}, 
                            'id': 'e50e8f12-cc56-47eb-a488-64ae9f442464', 
                            'size': 1}}

至于方法create如何实现了volume的建立,我们会在下一篇博客中进行深入的分析,本篇博客这里先不进行解析。

6.响应信息的生成

准确来说,这部分实现的功能是基于之前获取的action方法执行结果,经过填充信息和格式处理,实现形成响应信息。

我们来看方法dispatch中的这部分的源码:

       if not response:             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                         # 注:resp_obj应该是作为响应的头文件对象;             if resp_obj:                 # resp_obj = <cinder.api.openstack.wsgi.ResponseObject object at 0x2969d90>                 # request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0                 #           ......                 # _set_request_id_header:根据request的上下文信息,设置resp_obj的request_id值;                 _set_request_id_header(request, resp_obj)                 # 获取用于设置响应模板的类的实例化对象;                 serializers = getattr(meth, 'wsgi_serializers', {})                                 # serializers = {'xml': <class 'cinder.api.v1.volumes.VolumeTemplate'>}                 # _bind_method_serializers:这个方法是实现绑定指定的相应模板类serializers到响应对象resp_obj操作;                 resp_obj._bind_method_serializers(serializers)                                 # hasattr(meth, 'wsgi_code') = False                 if hasattr(meth, 'wsgi_code'):                     resp_obj._default_code = meth.wsgi_code                 # accept = application/json                 # self.default_serializers = {'xml': <class 'cinder.api.openstack.wsgi.XMLDictSerializer'>, 'json': <class 'cinder.api.openstack.wsgi.JSONDictSerializer'>}                 # preserialize:根据accept确定相应对象所要使用的序列化方法(类),并进行类的初始化操作;                    resp_obj.preserialize(accept, self.default_serializers)                 # Process post-processing extensions                 response = self.post_process_extensions(post, resp_obj, request, action_args)                         # resp_obj = <cinder.api.openstack.wsgi.ResponseObject object at 0x2969d90>             # response = None             if resp_obj and not response:                 # serialize:进行响应信息的序列化操作;                 # 1.获取用于序列化操作的方法;                 # 2.形成响应的头信息;                 # 3.通过序列化操作,形成响应的body信息;                 # 4.返回响应信息;                 response = resp_obj.serialize(request, accept, self.default_serializers)                 """                 accept = application/json                 self.default_serializers = {'xml': <class 'cinder.api.openstack.wsgi.XMLDictSerializer'>,                                             'json': <class 'cinder.api.openstack.wsgi.JSONDictSerializer'>}                 response = 200 OK                 x-compute-request-id: req-66a5680c-d160-493e-b333-7caacefc80f7                 Content-Type: application/json                 Content-Length: 344                 {"volume": {"status": "creating",                             "display_name": "shinian01",                             "attachments": [],                             "availability_zone": "nova",                             "bootable": "false",                             "created_at": "2014-03-27T07:39:42.673944",                             "display_description": null,                             "volume_type": "None",                             "snapshot_id": null,                             "source_volid": null,                             "metadata": {},                             "id": "e50e8f12-cc56-47eb-a488-64ae9f442464",                             "size": 1}}                 """         try:             msg_dict = dict(url=request.url, status=response.status_int)                     msg = _("%(url)s returned with HTTP %(status)d") % msg_dict         except AttributeError as e:             msg_dict = dict(url=request.url, e=e)             msg = _("%(url)s returned a fault: %(e)s") % msg_dict         LOG.info(msg)         """         response = 200 OK         x-compute-request-id: req-66a5680c-d160-493e-b333-7caacefc80f7         Content-Type: application/json         Content-Length: 344         {"volume": {"status": "creating",                     "display_name": "shinian01",                     "attachments": [],                     "availability_zone": "nova",                     "bootable": "false",                     "created_at": "2014-03-27T07:39:42.673944",                     "display_description": null,                     "volume_type": "None",                     "snapshot_id": null,                     "source_volid": null,                     "metadata": {},                     "id": "e50e8f12-cc56-47eb-a488-64ae9f442464",                     "size": 1}}         """         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的实现源码:

    def serialize(self, request, content_type, default_serializers=None):         """         Serializes the wrapped object.                 request = POST /v1/ecf0109bda814fa1a548af63f9ada370/volumes HTTP/1.0                   ......         accept = application/json         self.default_serializers = {'xml': <class 'cinder.api.openstack.wsgi.XMLDictSerializer'>,                                     'json': <class 'cinder.api.openstack.wsgi.JSONDictSerializer'>}         1.获取用于序列化操作的方法;         2.形成响应的头信息;         3.通过序列化操作,形成响应的body信息;         4.返回响应信息;         """         if self.serializer:             serializer = self.serializer         else:             # get_serializer:为封装对象的实现返回序列化方法;             _mtype, _serializer = self.get_serializer(content_type, default_serializers)                         # 获取序列化类的实例化对象;             serializer = _serializer()         response = webob.Response()         # code:获取响应状态;         response.status_int = self.code         """         response = 200 OK                    Content-Type: text/html; charset=UTF-8                    Content-Length: 0                 response.status_int = 200         """                 #self._headers = {'x-compute-request-id': 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f'}         for hdr, value in self._headers.items():             response.headers[hdr] = value             #response.headers['x-compute-request-id'] = req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f             #response.headers = ResponseHeaders([('Content-Type', 'text/html; charset=UTF-8'),             #                                    ('Content-Length', '0'),             #                                    ('x-compute-request-id', 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f            #                                     ')])                 # 形成了响应的头信息;         response.headers['Content-Type'] = content_type         #response.headers = ResponseHeaders([('Content-Length', '0'),         #                                    ('x-compute-request-id', 'req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f'),         #                                    ('Content-Type', 'application/json')])                 #self.obj = {'volume': {'status': 'creating',         #                       'display_name': u'shinian01',         #                       'attachments': [],         #                       'availability_zone': 'nova',         #                       'bootable': 'false',         #                       'created_at': datetime.datetime(2014, 3, 29, 12, 36, 23, 998481),         #                       'display_description': None,         #                       'volume_type': 'None',         #                       'snapshot_id': None,         #                       'source_volid': None,         #                       'metadata': {},         #                       'id': '3f0aa242-9dab-48db-b63d-92b6dd38cf20',         #                       'size': 1}}         if self.obj is not None:             # 对self.obj进行序列化操作,形成响应的body部分;             response.body = serializer.serialize(self.obj)             #serializer.serialize = <bound method JSONDictSerializer.serialize of <cinder.api.openstack.wsgi.JSONDictSerializer object at 0x4cd7190>>             #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}}         """         response = 200 OK                    x-compute-request-id: req-8cc99d4f-2b70-449c-b1a4-2b1cd10dca1f                    Content-Type: application/json                    Content-Length: 344                    {"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}}         """         return response

相关的代码解析请看源码中我的注释部分,具体来说,这部分代码实现的就是生成响应信息的头文件部分,以之前执行action方法所获取和返回的结果为主体,进行序列化操作,生成响应信息的body部分,从而形成完整的响应信息,并进行返回操作。

我们再回到方法_process_stack中,可见在方法的最后,返回了获取到的响应信息。


至此,在cinder模块中实现客户端发送过来的请求信息操作的主要的步骤已经全部解析完成。下一篇博客中,我将解析方法cinder.api.v1.volumes.VolumeController.create,来解析cinder是如何实现卷的建立的。

0 0
原创粉丝点击