OpenStack公共组件oslo之十一——oslo.serialization

        oslo.serialization为OpenStack其他组件提供序列化支持,其可以将对象封装为易于传输和保存的数据格式,如Base64、JSON和MassagePack等。本文首先详细介绍oslo.serialization对Base64、JSON和MassagePack数据格式的支持;然后,结合例子具体分析其使用方式。

1 Base64

      Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法。Base64编码可用于在HTTP环境下传递较长的标识信息。oslo.serialization提供了Base64转码和解码的支持,保存在oslo_serialization.base64模块下。该模块定义了四个Base64转码和解码的方法:

  • encode_as_bytes(s, encoding='utf-8'):使用Base64转码,如果s为text字符串类型,则首先将该text类型的字符串转为encoding编码的字符数组,然后再进行Base64编码。
  • encode_as_text(s, encoding='utf-8'):使用Base64转码,首先通过encode_as_bytes(s, encoding='utf-8')进行转码,然后将其通过ASCII码解码。
  • decode_as_bytes(encoded):使用Base64解码,如果encoded为bytes字符数组,则首先将其通过ASCII码解码,然后在进行Base64解码。
  • decode_as_text(encoded, encoding='utf-8'):使用Base64解码,首先通过decode_as_bytes(encoded)进行解码,然后将其通过指定的encoding解码。

2 JSON

        JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式。它基于 ECMAScript (w3c制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。oslo.serialization在oslo_serialization.jsonutils模块下提供了JSON数据格式的封装。
        oslo_serialization.jsonutils模块首先提供了一个方便的方法to_primitive(value, convert_instances=False, convert_datetime=True, level=0, max_depth=3, encoding='utf-8', fallback=None),该方法可以将复杂的对象转化为基元,该方法是一个递归方法,所以我们可以使用循环嵌套的数据结构。通过该方法,我们可以很方便的使用JSON序列化。基于该方法,oslo_serialization.jsonutils模块提供了以下5个不同的序列化和反序列化方法:
  • dumps(obj, default=to_primitive, **kwargs):将一个对象obj序列化为JSON格式的字符串。
  • dump_as_bytes(obj, default=to_primitive, encoding='utf-8', **kwargs):将一个对象obj序列化为JSON格式的byte数组。
  • dump(obj, fp, *args, **kwargs):将一个对象obj序列化为JSON格式的流fp。
  • loads(s, encoding='utf-8', **kwargs):将JSON格式的字符串或字符数组s进行反序列化。
  • load(fp, encoding='utf-8', **kwargs):将JSON格式的流fp反序列化。

3 MessagePack

        MessagePack是一个高效的二进制序列化格式。它让你像JSON一样可以在各种语言之间交换数据。但是它比JSON更快、更小。小的整数会被编码成一个字节,短的字符串仅仅只需要比它的长度多一字节的大小。oslo.serialization在oslo_serialization.msgpackutils中对MessagePack序列化和反序列化进行了支持。
        oslo_serialization.msgpackutils模块首先定义了一系列用于MessagePack序列化的特殊数据处理类,这些类中都包含一个handles属性表示要处理的数据类型,还包含一个identity属性区分这些处理类;除此之外,这些类都定义了对handles监听的数据类型进行MessagePack序列化和反序列化的方法serialize()和deserialize()。这些类主要包括以下几种:
  • UUIDHandler:用于处理uuid.UUID类型的数据。
  • DateTimeHandler:用于处理datetime.datetime类型的数据。
  • CountHandler:用于处理itertools.count类型的数据。
  • NetAddrIPHandler:用于处理netaddr.IPAddress类型的数据。
  • SetHandler:用于处理set类型的数据。
  • FrozenSetHandler:用于处理frozenset类型的数据。
  • XMLRPCDateTimeHandler:用于处理xmlrpclib.DateTime类型的数据。
  • DateHandler:用于处理datetime.date类型的数据。

        为了对这些处理类进行统一管理,oslo_serilization.msgpackutils模块还定义了统一的处理器注册类HandlerRegistry。该类限制应用程序可以指定0~127来保存一个应用程序或库定义的类型处理类,即Handler类中identity的范围。其中,0~32通常为oslo.serialization保留,为oslo.serialization和它自己的附加扩展处理类使用,这些扩展处理类是为了普遍适用于所有的Python应用;33~127通常为应用程序保留,使应用程序可以构建自己的类型处理类,这个范围内定义的处理类会因为应用程序的不同而不同。这里面所使用的Interval类指定了一个小而简单的整型或浮点型的范围,这个范围包括指定的最大/最小边界。

        HandlerRegistry类定义了如下几个用于管理这些扩展处理器类的方法:

  • register(handler, reserved=False, override=False):向HandlerRegistry对象中注册一个用于处理指定类型数据的处理类Handler。
  • copy(unfreeze=False):深拷贝一个HandlerRegistry对象及其绑定的处理器类。
  • get(identity):根据指定的identity获取一个指定数据类型的处理类Handler的对象。
  • match(obj):根据指定对象的数据类型匹配一个与之对应的处理类Handler的对象。
        接着,oslo_serialization.msgpackutils模块定义了一个default_registry()方法,在进行序列化和反序列化之前,都会自动调用这个default_registry()方法初始化一个HandlerRegistry对象,并为其绑定上述处理类。最后,oslo_serialization.msgpackutils模块基于上述设计定义了MessagePack格式的数据序列化和反序列化方法,主要包括以下几个方法:
  • dumps(obj, registry=None):将对象obj序列化为MessagePack格式的字符串。
  • dump(obj, fp, registry=None):将对象obj序列化为MessagePack格式的流fp。
  • loads(s, registry=None):将MessagePack格式的字符串s反序列化为对象。
  • load(fp, registry=None):将MessagePack格式的流fp反序列化为对象。

4 oslo.serialization的使用方法

        上文详细讨论了oslo.serialization中Base64、JSON、MessagePack序列化和反序列化的实现,本文结合具体例子介绍oslo.serialization的使用方法。首先,直接使用base64、jsonutils、msgpackutils进行序列化非常简单,直接导入对应模块,然后使用模块中定义的序列化与反序列化方法即可。
from oslo_serialization import base64

data = 'Hello, World!'
personality.append({
    'path': '/helloworld.txt',
    'contents': base64.encode_as_bytes(data),
})

USER_DATA_STRING = (b"This is an encoded string")
ENCODE_USER_DATA_STRING = base64.encode_as_text(USER_DATA_STRING)

self.assertEqual(len(base64.decode_as_bytes(mddict["random_seed"])),
                 512)

self.assertEqual(base64.decode_as_text(i['contents']),
                 linux_client.exec_command(
                 'sudo cat %s' % i['path']))
        上述代码列举了nova中使用base64的使用方法,而jsonutils和msgpackutils的使用方法与之类似。
        除了直接使用模块中的方法之外,oslo.serialization还对JSON和MessagePack的序列化与反序列化方法进行了进一步的封装。首先,oslo.serialization在oslo_serialization.serializer目录中定义了一个抽象类BaseSerialization,其中定义了多个序列化和反序列化的方法。
import abc
import six

@six.add_metaclass(abc.ABCMeta)
class BaseSerializer(object):
    """Generic (de-)serialization definition abstract base class."""

    @abc.abstractmethod
    def dump(self, obj, fp):
        """Serialize ``obj`` as a stream to ``fp``.

        :param obj: python object to be serialized
        :param fp: ``.write()``-supporting file-like object
        """

    @abc.abstractmethod
    def dump_as_bytes(self, obj):
        """Serialize ``obj`` to a byte string.

        :param obj: python object to be serialized
        :returns: byte string
        """

    @abc.abstractmethod
    def load(self, fp):
        """Deserialize ``fp`` to a python object.

        :param fp: ``.read()``-supporting file-like object
        :returns: python object
        """

    @abc.abstractmethod
    def load_from_bytes(self, s):
        """Deserialize ``s`` to a python object.

        :param s: byte string to be deserialized
        :returns: python object
        """
        接着,分别为JSON和MessagePack的序列化实现了该抽象类。
from oslo_serialization import jsonutils
from oslo_serialization.serializer.base_serializer import BaseSerializer


class JSONSerializer(BaseSerializer):
    """JSON serializer based on the jsonutils module."""

    def __init__(self, default=jsonutils.to_primitive, encoding='utf-8'):
        self._default = default
        self._encoding = encoding

    def dump(self, obj, fp):
        return jsonutils.dump(obj, fp)

    def dump_as_bytes(self, obj):
        return jsonutils.dump_as_bytes(obj, default=self._default,
                                       encoding=self._encoding)

    def load(self, fp):
        return jsonutils.load(fp, encoding=self._encoding)

    def load_from_bytes(self, s):
        return jsonutils.loads(s, encoding=self._encoding)
from oslo_serialization import msgpackutils
from oslo_serialization.serializer.base_serializer import BaseSerializer


class MessagePackSerializer(BaseSerializer):
    """MessagePack serializer based on the msgpackutils module."""

    def __init__(self, registry=None):
        self._registry = registry

    def dump(self, obj, fp):
        return msgpackutils.dump(obj, fp, registry=self._registry)

    def dump_as_bytes(self, obj):
        return msgpackutils.dumps(obj, registry=self._registry)

    def load(self, fp):
        return msgpackutils.load(fp, registry=self._registry)

    def load_from_bytes(self, s):
        return msgpackutils.loads(s, registry=self._registry)
        所以,OpenStack其他项目在进行序列化与反序列化时,可以首先实例化一个相应的序列化对象,然后调用对象中的方法便可方便的实现JSON和MessagePack格式的数据序列化与反序列化操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值