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
- 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
- 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的对象。
- 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的使用方法
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
"""
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格式的数据序列化与反序列化操作。