--- /dev/null
+
+#
+# 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)