| |
| # |
| # 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) |