blob: 7571c570e9000772942f02de265381e17b18b7f2 [file] [log] [blame]
#
# Copyright 2016 RIFT.IO Inc
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
import json
import os
import tempfile
import gi
gi.require_version('RwNsdYang', '1.0')
gi.require_version('RwVnfdYang', '1.0')
gi.require_version('RwYang', '1.0')
from gi.repository import (
RwNsdYang,
RwVnfdYang,
NsdYang,
VnfdYang,
RwYang,
)
class UnknownExtensionError(Exception):
pass
class SerializationError(Exception):
pass
def decode(desc_data):
if isinstance(desc_data, bytes):
desc_data = desc_data.decode()
return desc_data
class ProtoMessageSerializer(object):
"""(De)Serializer/deserializer fo a specific protobuf message into various formats"""
libncx_model = None
def __init__(self, yang_ns, yang_pb_cls):
""" Create a serializer for a specific protobuf message """
self._yang_ns = yang_ns
self._yang_pb_cls = yang_pb_cls
@classmethod
def _deserialize_extension_method_map(cls):
return {
".xml": cls._from_xml_file_hdl,
".yml": cls._from_yaml_file_hdl,
".yaml": cls._from_yaml_file_hdl,
".json": cls._from_json_file_hdl,
}
@classmethod
def _serialize_extension_method_map(cls):
return {
".xml": cls.to_xml_string,
".yml": cls.to_yaml_string,
".yaml": cls.to_yaml_string,
".json": cls.to_json_string,
}
@classmethod
def is_supported_file(cls, filename):
"""Returns whether a file has a supported file extension
Arguments:
filename - A descriptor file
Returns:
True if file extension is supported, False otherwise
"""
_, extension = os.path.splitext(filename)
extension_lc = extension.lower()
return extension_lc in cls._deserialize_extension_method_map()
@property
def yang_namespace(self):
""" The Protobuf's GI namespace class (e.g. RwVnfdYang) """
return self._yang_ns
@property
def yang_class(self):
""" The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
return self._yang_pb_cls
@property
def model(self):
cls = self.__class__
# Cache the libncx model for the serializer class
if cls.libncx_model is None:
cls.libncx_model = RwYang.model_create_libncx()
cls.libncx_model.load_schema_ypbc(self.yang_namespace.get_schema())
return cls.libncx_model
def _from_xml_file_hdl(self, file_hdl):
xml = file_hdl.read()
return self.yang_class.from_xml_v2(self.model, decode(xml), strict=False)
def _from_json_file_hdl(self, file_hdl):
json = file_hdl.read()
return self.yang_class.from_json(self.model, decode(json), strict=False)
def _from_yaml_file_hdl(self, file_hdl):
yaml = file_hdl.read()
return self.yang_class.from_yaml(self.model, decode(yaml), strict=False)
def to_json_string(self, pb_msg):
""" Serialize a protobuf message into JSON
Arguments:
pb_msg - A GI-protobuf object of type provided into constructor
Returns:
A JSON string representing the protobuf message
Raises:
SerializationError - Message could not be serialized
TypeError - Incorrect protobuf type provided
"""
if not isinstance(pb_msg, self._yang_pb_cls):
raise TypeError("Invalid protobuf message type provided")
try:
json_str = pb_msg.to_json(self.model)
except Exception as e:
raise SerializationError(e)
return json_str
def to_yaml_string(self, pb_msg):
""" Serialize a protobuf message into YAML
Arguments:
pb_msg - A GI-protobuf object of type provided into constructor
Returns:
A YAML string representing the protobuf message
Raises:
SerializationError - Message could not be serialized
TypeError - Incorrect protobuf type provided
"""
if not isinstance(pb_msg, self._yang_pb_cls):
raise TypeError("Invalid protobuf message type provided")
try:
yaml_str = pb_msg.to_yaml(self.model)
except Exception as e:
raise SerializationError(e)
return yaml_str
def to_xml_string(self, pb_msg):
""" Serialize a protobuf message into XML
Arguments:
pb_msg - A GI-protobuf object of type provided into constructor
Returns:
A XML string representing the protobuf message
Raises:
SerializationError - Message could not be serialized
TypeError - Incorrect protobuf type provided
"""
if not isinstance(pb_msg, self._yang_pb_cls):
raise TypeError("Invalid protobuf message type provided")
try:
xml_str = pb_msg.to_xml_v2(self.model)
except Exception as e:
raise SerializationError(e)
return xml_str
def from_file_hdl(self, file_hdl, extension):
""" Returns the deserialized protobuf message from file contents
This function determines the serialization format based on file extension
Arguments:
file_hdl - The file hdl to deserialize (set at pos 0)
extension - Extension of the file format (second item of os.path.splitext())
Returns:
A GI-Proto message of type that was provided into the constructor
Raises:
UnknownExtensionError - File extension is not of a known serialization format
SerializationError - File failed to be deserialized into the protobuf message
"""
extension_lc = extension.lower()
extension_map = self._deserialize_extension_method_map()
if extension_lc not in extension_map:
raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
try:
msg = extension_map[extension_lc](self, file_hdl)
except Exception as e:
raise SerializationError(e)
return msg
def to_string(self, pb_msg, extension):
""" Returns the serialized protobuf message for a particular file extension
This function determines the serialization format based on file extension
Arguments:
pb_msg - A GI-protobuf object of type provided into constructor
extension - Extension of the file format (second item of os.path.splitext())
Returns:
A GI-Proto message of type that was provided into the constructor
Raises:
UnknownExtensionError - File extension is not of a known serialization format
SerializationError - File failed to be deserialized into the protobuf message
"""
extension_lc = extension.lower()
extension_map = self._serialize_extension_method_map()
if extension_lc not in extension_map:
raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
try:
msg = extension_map[extension_lc](self, pb_msg)
except Exception as e:
raise SerializationError(e)
return msg
class VnfdSerializer(ProtoMessageSerializer):
""" Creates a serializer for the VNFD descriptor"""
def __init__(self):
super().__init__(VnfdYang, VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd)
class NsdSerializer(ProtoMessageSerializer):
""" Creates a serializer for the NSD descriptor"""
def __init__(self):
super().__init__(NsdYang, NsdYang.YangData_Nsd_NsdCatalog_Nsd)
class RwVnfdSerializer(ProtoMessageSerializer):
""" Creates a serializer for the VNFD descriptor"""
def __init__(self):
super().__init__(RwVnfdYang, RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd)
class RwNsdSerializer(ProtoMessageSerializer):
""" Creates a serializer for the NSD descriptor"""
def __init__(self):
super().__init__(RwNsdYang, RwNsdYang.YangData_Nsd_NsdCatalog_Nsd)