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.
23 gi
.require_version('RwNsdYang', '1.0')
24 gi
.require_version('RwProjectNsdYang', '1.0')
25 gi
.require_version('RwVnfdYang', '1.0')
26 gi
.require_version('RwProjectVnfdYang', '1.0')
27 gi
.require_version('RwYang', '1.0')
28 from gi
.repository
import (
40 from rift
.mano
.utils
.project
import NS_PROJECT
43 class UnknownExtensionError(Exception):
47 class SerializationError(Exception):
51 def decode(desc_data
):
52 if isinstance(desc_data
, bytes
):
53 desc_data
= desc_data
.decode()
58 class ProtoMessageSerializer(object):
59 """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
62 def __init__(self
, yang_ns
, yang_pb_cls
,
63 yang_ns_project
, yang_pb_project_cls
):
64 """ Create a serializer for a specific protobuf message """
65 self
._yang
_ns
= yang_ns
66 self
._yang
_pb
_cls
= yang_pb_cls
67 self
._yang
_ns
_project
= yang_ns_project
68 self
._yang
_pb
_project
_cls
= yang_pb_project_cls
70 self
._log
= logging
.getLogger('rw-maon-log')
73 def _deserialize_extension_method_map(cls
):
75 ".xml": cls
._from
_xml
_file
_hdl
,
76 ".yml": cls
._from
_yaml
_file
_hdl
,
77 ".yaml": cls
._from
_yaml
_file
_hdl
,
78 ".json": cls
._from
_json
_file
_hdl
,
82 def _serialize_extension_method_map(cls
):
84 ".xml": cls
.to_xml_string
,
85 ".yml": cls
.to_yaml_string
,
86 ".yaml": cls
.to_yaml_string
,
87 ".json": cls
.to_json_string
,
91 def is_supported_file(cls
, filename
):
92 """Returns whether a file has a supported file extension
95 filename - A descriptor file
98 True if file extension is supported, False otherwise
101 _
, extension
= os
.path
.splitext(filename
)
102 extension_lc
= extension
.lower()
104 return extension_lc
in cls
._deserialize
_extension
_method
_map
()
107 def yang_namespace(self
):
108 """ The Protobuf's GI namespace class (e.g. RwVnfdYang) """
112 def yang_class(self
):
113 """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
114 return self
._yang
_pb
_cls
117 def yang_ns_project(self
):
118 """ The Protobuf's GI namespace class (e.g. RwProjectVnfdYang) """
119 return self
._yang
_ns
_project
122 def yang_class_project(self
):
123 """ The Protobuf's GI class (e.g. RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd) """
124 return self
._yang
_pb
_project
_cls
130 # Cache the libncx model for the serializer class
131 if cls
.libncx_model
is None:
132 cls
.libncx_model
= RwYang
.model_create_libncx()
133 cls
.libncx_model
.load_schema_ypbc(self
.yang_namespace
.get_schema())
134 cls
.libncx_model
.load_schema_ypbc(self
.yang_ns_project
.get_schema())
136 return cls
.libncx_model
138 def _from_xml_file_hdl(self
, file_hdl
):
139 xml
= file_hdl
.read()
141 return self
.yang_class
.from_xml_v2(self
.model
, decode(xml
), strict
=False)
143 def _from_json_file_hdl(self
, file_hdl
):
144 json
= file_hdl
.read()
146 return self
.yang_class
.from_json(self
.model
, decode(json
), strict
=False)
148 def _from_yaml_file_hdl(self
, file_hdl
):
149 yml
= file_hdl
.read()
151 # Need to prefix project on to the descriptor and then
153 # TODO: See if there is a better way to do this
154 # desc = {NS_PROJECT: []}
155 # desc[NS_PROJECT].append(yaml.load(decode(yml)))
156 # log = logging.getLogger('rw-mano-log')
157 # log.error("Desc from yaml: {}".format(desc))
158 # return self.yang_class.from_yaml(self.model, yaml.dump(desc), strict=False)
161 desc_msg
= self
.yang_class
.from_yaml(self
.model
, decode(yml
), strict
=False)
162 return self
.yang_class_project
.from_dict(desc_msg
.as_dict())
163 except Exception as e
:
164 self
._log
.exception(e
)
167 def to_desc_msg(self
, pb_msg
, project_rooted
=True):
168 """Convert to and from project rooted pb msg descriptor to catalog
172 if isinstance(pb_msg
, self
._yang
_pb
_project
_cls
):
173 return self
._yang
_pb
_cls
.from_dict(pb_msg
.as_dict())
174 elif isinstance(pb_msg
, self
._yang
_pb
_cls
):
178 if isinstance(pb_msg
, self
._yang
_pb
_cls
):
179 return self
._yang
_pb
_project
_cls
.from_dict(pb_msg
.as_dict())
180 elif isinstance(pb_msg
, self
._yang
_pb
_project
_cls
):
183 raise TypeError("Invalid protobuf message type provided: {}".format(type(pb_msg
)))
186 def to_json_string(self
, pb_msg
, project_ns
=False):
187 """ Serialize a protobuf message into JSON
190 pb_msg - A GI-protobuf object of type provided into constructor
191 project_ns - Need the desc in project namespace, required for
192 posting to Restconf as part of onboarding
195 A JSON string representing the protobuf message
198 SerializationError - Message could not be serialized
199 TypeError - Incorrect protobuf type provided
202 # json_str = pb_msg.to_json(self.model)
204 desc_msg
= self
.to_desc_msg(pb_msg
, not project_ns
)
205 json_str
= desc_msg
.to_json(self
.model
)
207 # Remove rw-project:project top level element
208 dic
= json
.loads(json_str
)
209 jstr
= json
.dumps(dic
[NS_PROJECT
][0])
211 except Exception as e
:
212 raise SerializationError(e
)
214 self
._log
.debug("Convert desc to json: {}".format(jstr
))
217 def to_yaml_string(self
, pb_msg
):
218 """ Serialize a protobuf message into YAML
221 pb_msg - A GI-protobuf object of type provided into constructor
224 A YAML string representing the protobuf message
227 SerializationError - Message could not be serialized
228 TypeError - Incorrect protobuf type provided
231 desc_msg
= self
.to_desc_msg(pb_msg
)
232 yaml_str
= desc_msg
.to_yaml(self
.model
)
234 except Exception as e
:
235 self
._log
.exception("Exception converting to yaml: {}".format(e
))
236 raise SerializationError(e
)
240 def to_xml_string(self
, pb_msg
):
241 """ Serialize a protobuf message into XML
244 pb_msg - A GI-protobuf object of type provided into constructor
247 A XML string representing the protobuf message
250 SerializationError - Message could not be serialized
251 TypeError - Incorrect protobuf type provided
254 desc_msg
= self
.to_desc_msg(pb_msg
)
255 xml_str
= desc_msg
.to_xml_v2(self
.model
)
257 except Exception as e
:
258 self
._log
.exception("Exception converting to xml: {}".format(e
))
259 raise SerializationError(e
)
263 def from_file_hdl(self
, file_hdl
, extension
):
264 """ Returns the deserialized protobuf message from file contents
266 This function determines the serialization format based on file extension
269 file_hdl - The file hdl to deserialize (set at pos 0)
270 extension - Extension of the file format (second item of os.path.splitext())
273 A GI-Proto message of type that was provided into the constructor
276 UnknownExtensionError - File extension is not of a known serialization format
277 SerializationError - File failed to be deserialized into the protobuf message
280 extension_lc
= extension
.lower()
281 extension_map
= self
._deserialize
_extension
_method
_map
()
283 if extension_lc
not in extension_map
:
284 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc
)
287 msg
= extension_map
[extension_lc
](self
, file_hdl
)
288 except Exception as e
:
289 raise SerializationError(e
)
293 def to_string(self
, pb_msg
, extension
):
294 """ Returns the serialized protobuf message for a particular file extension
296 This function determines the serialization format based on file extension
299 pb_msg - A GI-protobuf object of type provided into constructor
300 extension - Extension of the file format (second item of os.path.splitext())
303 A GI-Proto message of type that was provided into the constructor
306 UnknownExtensionError - File extension is not of a known serialization format
307 SerializationError - File failed to be deserialized into the protobuf message
310 extension_lc
= extension
.lower()
311 extension_map
= self
._serialize
_extension
_method
_map
()
313 if extension_lc
not in extension_map
:
314 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc
)
317 msg
= extension_map
[extension_lc
](self
, pb_msg
)
318 except Exception as e
:
319 raise SerializationError(e
)
324 class VnfdSerializer(ProtoMessageSerializer
):
325 """ Creates a serializer for the VNFD descriptor"""
327 super().__init
__(VnfdYang
, VnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
,
328 ProjectVnfdYang
, ProjectVnfdYang
.YangData_RwProject_Project_VnfdCatalog_Vnfd
)
331 class NsdSerializer(ProtoMessageSerializer
):
332 """ Creates a serializer for the NSD descriptor"""
334 super().__init
__(NsdYang
, NsdYang
.YangData_Nsd_NsdCatalog_Nsd
,
335 ProjectNsdYang
, ProjectNsdYang
.YangData_RwProject_Project_NsdCatalog_Nsd
)
338 class RwVnfdSerializer(ProtoMessageSerializer
):
339 """ Creates a serializer for the VNFD descriptor"""
341 super().__init
__(RwVnfdYang
, RwVnfdYang
.YangData_Vnfd_VnfdCatalog_Vnfd
,
342 RwProjectVnfdYang
, RwProjectVnfdYang
.YangData_RwProject_Project_VnfdCatalog_Vnfd
)
345 class RwNsdSerializer(ProtoMessageSerializer
):
346 """ Creates a serializer for the NSD descriptor"""
348 super().__init
__(RwNsdYang
, RwNsdYang
.YangData_Nsd_NsdCatalog_Nsd
,
349 RwProjectNsdYang
, RwProjectNsdYang
.YangData_RwProject_Project_NsdCatalog_Nsd
)