3 # Copyright 2016-2017 RIFT.IO Inc
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
24 gi
.require_version('RwNsdYang', '1.0')
25 gi
.require_version('RwProjectNsdYang', '1.0')
26 gi
.require_version('RwVnfdYang', '1.0')
27 gi
.require_version('RwProjectVnfdYang', '1.0')
28 gi
.require_version('RwYang', '1.0')
29 from gi
.repository
import (
41 from rift
.mano
.utils
.project
import NS_PROJECT
42 from rift
.rwlib
.translation
.json2xml
import InvalidSchemaException
44 class UnknownExtensionError(Exception):
48 class SerializationError(Exception):
52 def decode(desc_data
):
53 if isinstance(desc_data
, bytes
):
54 desc_data
= desc_data
.decode()
59 class ProtoMessageSerializer(object):
60 """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
63 def __init__(self
, yang_ns
, yang_pb_cls
,
64 yang_ns_project
, yang_pb_project_cls
):
65 """ Create a serializer for a specific protobuf message """
66 self
._yang
_ns
= yang_ns
67 self
._yang
_pb
_cls
= yang_pb_cls
68 self
._yang
_ns
_project
= yang_ns_project
69 self
._yang
_pb
_project
_cls
= yang_pb_project_cls
71 self
._log
= logging
.getLogger('rw-maon-log')
74 def _deserialize_extension_method_map(cls
):
76 ".xml": cls
._from
_xml
_file
_hdl
,
77 ".yml": cls
._from
_yaml
_file
_hdl
,
78 ".yaml": cls
._from
_yaml
_file
_hdl
,
79 ".json": cls
._from
_json
_file
_hdl
,
83 def _serialize_extension_method_map(cls
):
85 ".xml": cls
.to_xml_string
,
86 ".yml": cls
.to_yaml_string
,
87 ".yaml": cls
.to_yaml_string
,
88 ".json": cls
.to_json_string
,
92 def is_supported_file(cls
, filename
):
93 """Returns whether a file has a supported file extension
96 filename - A descriptor file
99 True if file extension is supported, False otherwise
102 _
, extension
= os
.path
.splitext(filename
)
103 extension_lc
= extension
.lower()
105 return extension_lc
in cls
._deserialize
_extension
_method
_map
()
108 def yang_namespace(self
):
109 """ The Protobuf's GI namespace class (e.g. RwVnfdYang) """
113 def yang_class(self
):
114 """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
115 return self
._yang
_pb
_cls
118 def yang_ns_project(self
):
119 """ The Protobuf's GI namespace class (e.g. RwProjectVnfdYang) """
120 return self
._yang
_ns
_project
123 def yang_class_project(self
):
124 """ The Protobuf's GI class (e.g. RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd) """
125 return self
._yang
_pb
_project
_cls
131 # Cache the libyang model for the serializer class
132 if cls
.libyang_model
is None:
133 cls
.libyang_model
= RwYang
.model_create_libyang()
134 cls
.libyang_model
.load_schema_ypbc(self
.yang_namespace
.get_schema())
135 cls
.libyang_model
.load_schema_ypbc(self
.yang_ns_project
.get_schema())
137 return cls
.libyang_model
139 def _from_xml_file_hdl(self
, file_hdl
, project
=None):
140 xml
= file_hdl
.read()
142 return self
.yang_class
.from_xml_v2(self
.model
, decode(xml
), strict
=False) \
143 if not project
else self
._yang
_pb
_project
_cls
.from_xml_v2(self
.model
, decode(xml
), strict
=False)
145 def _from_json_file_hdl(self
, file_hdl
, project
=None):
146 jstr
= file_hdl
.read()
147 self
._log
.debug("Convert from json file: {}".format(jstr
))
151 desc_msg
= self
.yang_class
.from_json(self
.model
, decode(jstr
), strict
=False)
153 desc_msg
= self
._yang
_pb
_project
_cls
.from_json(self
.model
, decode(jstr
), strict
=False)
155 self
._log
.debug("desc_msg: {}".format(desc_msg
.as_dict()))
156 return self
.yang_class_project
.from_dict(desc_msg
.as_dict())
157 except Exception as e
:
158 self
._log
.exception(e
)
161 def _from_yaml_file_hdl(self
, file_hdl
, project
=None):
162 yml
= file_hdl
.read()
165 desc_msg
= self
.yang_class
.from_yaml(self
.model
, decode(yml
), strict
=True)
166 except InvalidSchemaException
as invalid_scheme_exception
:
167 self
._log
.error("Exception raised during schema translation, %s. Launchpad will" \
168 "continue to process the remaining elements ", str(invalid_scheme_exception
))
169 desc_msg
= self
.yang_class
.from_yaml(self
.model
, decode(yml
), strict
=False)
170 except Exception as e
:
171 self
._log
.exception(e
)
174 return self
.yang_class_project
.from_dict(desc_msg
.as_dict())
176 def to_desc_msg(self
, pb_msg
, project_rooted
=True):
177 """Convert to and from project rooted pb msg descriptor to catalog
179 project_rooted: if pb_msg is project rooted or not
182 if isinstance(pb_msg
, self
._yang
_pb
_project
_cls
):
183 return self
._yang
_pb
_cls
.from_dict(pb_msg
.as_dict())
184 elif isinstance(pb_msg
, self
._yang
_pb
_cls
):
188 if isinstance(pb_msg
, self
._yang
_pb
_cls
):
189 return self
._yang
_pb
_project
_cls
.from_dict(pb_msg
.as_dict())
190 elif isinstance(pb_msg
, self
._yang
_pb
_project
_cls
):
193 raise TypeError("Invalid protobuf message type provided: {}".format(type(pb_msg
)))
196 def to_json_string(self
, pb_msg
, project_ns
=False):
197 """ Serialize a protobuf message into JSON
200 pb_msg - A GI-protobuf object of type provided into constructor
201 project_ns - Need the desc in project namespace, required for
202 posting to Restconf as part of onboarding
205 A JSON string representing the protobuf message
208 SerializationError - Message could not be serialized
209 TypeError - Incorrect protobuf type provided
211 self
._log
.debug("Convert desc to json (ns:{}): {}".format(project_ns
, pb_msg
.as_dict()))
213 # json_str = pb_msg.to_json(self.model)
215 desc_msg
= self
.to_desc_msg(pb_msg
, not project_ns
)
216 json_str
= desc_msg
.to_json(self
.model
)
218 # Remove rw-project:project top level element
219 dic
= json
.loads(json_str
)
220 jstr
= json
.dumps(dic
[NS_PROJECT
][0])
224 except Exception as e
:
225 raise SerializationError(e
)
227 self
._log
.debug("Convert desc to json: {}".format(jstr
))
230 def to_yaml_string(self
, pb_msg
, project_ns
=False):
231 """ Serialize a protobuf message into YAML
234 pb_msg - A GI-protobuf object of type provided into constructor
235 project_ns - Need the desc in project namespace, required for
236 posting to Restconf as part of onboarding
239 A YAML string representing the protobuf message
242 SerializationError - Message could not be serialized
243 TypeError - Incorrect protobuf type provided
245 self
._log
.debug("Convert desc to yaml (ns:{}): {}".format(project_ns
, pb_msg
.as_dict()))
247 desc_msg
= self
.to_desc_msg(pb_msg
, not project_ns
)
248 yaml_str
= desc_msg
.to_yaml(self
.model
)
250 # Remove rw-project:project top level element
251 dic
= yaml
.loads(yaml_str
)
252 ystr
= yaml
.dump(dic
[NS_PROJECT
][0])
257 except Exception as e
:
258 self
._log
.exception("Exception converting to yaml: {}".format(e
))
259 raise SerializationError(e
)
263 def to_xml_string(self
, pb_msg
):
264 """ Serialize a protobuf message into XML
267 pb_msg - A GI-protobuf object of type provided into constructor
270 A XML string representing the protobuf message
273 SerializationError - Message could not be serialized
274 TypeError - Incorrect protobuf type provided
277 desc_msg
= self
.to_desc_msg(pb_msg
)
278 xml_str
= desc_msg
.to_xml_v2(self
.model
)
280 except Exception as e
:
281 self
._log
.exception("Exception converting to xml: {}".format(e
))
282 raise SerializationError(e
)
286 def from_file_hdl(self
, file_hdl
, extension
, project
=None):
287 """ Returns the deserialized protobuf message from file contents
289 This function determines the serialization format based on file extension
292 file_hdl - The file hdl to deserialize (set at pos 0)
293 extension - Extension of the file format (second item of os.path.splitext())
296 A GI-Proto message of type that was provided into the constructor
299 UnknownExtensionError - File extension is not of a known serialization format
300 SerializationError - File failed to be deserialized into the protobuf message
303 extension_lc
= extension
.lower()
304 extension_map
= self
._deserialize
_extension
_method
_map
()
306 if extension_lc
not in extension_map
:
307 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc
)
310 self
._log
.debug("Converting from json..project = {}".format(project
))
311 msg
= extension_map
[extension_lc
](self
, file_hdl
, project
)
312 except Exception as e
:
313 raise SerializationError(e
)
317 def to_string(self
, pb_msg
, extension
):
318 """ Returns the serialized protobuf message for a particular file extension
320 This function determines the serialization format based on file extension
323 pb_msg - A GI-protobuf object of type provided into constructor
324 extension - Extension of the file format (second item of os.path.splitext())
327 A GI-Proto message of type that was provided into the constructor
330 UnknownExtensionError - File extension is not of a known serialization format
331 SerializationError - File failed to be deserialized into the protobuf message
334 extension_lc
= extension
.lower()
335 extension_map
= self
._serialize
_extension
_method
_map
()
337 if extension_lc
not in extension_map
:
338 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc
)
341 msg
= extension_map
[extension_lc
](self
, pb_msg
)
342 except Exception as e
:
343 raise SerializationError(e
)
348 class VnfdSerializer(ProtoMessageSerializer
):
349 """ Creates a serializer for the VNFD descriptor"""
351 super().__init
__(VnfdYang
, VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
,
352 ProjectVnfdYang
, ProjectVnfdYang
.YangData_RwProject_Project_VnfdCatalog_Vnfd
)
355 class NsdSerializer(ProtoMessageSerializer
):
356 """ Creates a serializer for the NSD descriptor"""
358 super().__init
__(NsdYang
, NsdYang
.YangData_Nsd_NsdCatalog_Nsd
,
359 ProjectNsdYang
, ProjectNsdYang
.YangData_RwProject_Project_NsdCatalog_Nsd
)
362 class RwVnfdSerializer(ProtoMessageSerializer
):
363 """ Creates a serializer for the VNFD descriptor"""
365 super().__init
__(RwVnfdYang
, RwVnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
,
366 RwProjectVnfdYang
, RwProjectVnfdYang
.YangData_RwProject_Project_VnfdCatalog_Vnfd
)
369 class RwNsdSerializer(ProtoMessageSerializer
):
370 """ Creates a serializer for the NSD descriptor"""
372 super().__init
__(RwNsdYang
, RwNsdYang
.YangData_Nsd_NsdCatalog_Nsd
,
373 RwProjectNsdYang
, RwProjectNsdYang
.YangData_RwProject_Project_NsdCatalog_Nsd
)