525eff52007a32b7532beba7279713532c248fe4
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / package / convert.py
1
2 #
3 # Copyright 2016-2017 RIFT.IO Inc
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16 #
17
18 import json
19 import logging
20 import os
21
22 import gi
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 (
29 RwNsdYang,
30 RwVnfdYang,
31 NsdYang,
32 VnfdYang,
33 RwProjectNsdYang,
34 RwProjectVnfdYang,
35 ProjectNsdYang,
36 ProjectVnfdYang,
37 RwYang,
38 )
39
40 from rift.mano.utils.project import NS_PROJECT
41
42
43 class UnknownExtensionError(Exception):
44 pass
45
46
47 class SerializationError(Exception):
48 pass
49
50
51 def decode(desc_data):
52 if isinstance(desc_data, bytes):
53 desc_data = desc_data.decode()
54
55 return desc_data
56
57
58 class ProtoMessageSerializer(object):
59 """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
60 libncx_model = None
61
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
69
70 self._log = logging.getLogger('rw-maon-log')
71
72 @classmethod
73 def _deserialize_extension_method_map(cls):
74 return {
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,
79 }
80
81 @classmethod
82 def _serialize_extension_method_map(cls):
83 return {
84 ".xml": cls.to_xml_string,
85 ".yml": cls.to_yaml_string,
86 ".yaml": cls.to_yaml_string,
87 ".json": cls.to_json_string,
88 }
89
90 @classmethod
91 def is_supported_file(cls, filename):
92 """Returns whether a file has a supported file extension
93
94 Arguments:
95 filename - A descriptor file
96
97 Returns:
98 True if file extension is supported, False otherwise
99
100 """
101 _, extension = os.path.splitext(filename)
102 extension_lc = extension.lower()
103
104 return extension_lc in cls._deserialize_extension_method_map()
105
106 @property
107 def yang_namespace(self):
108 """ The Protobuf's GI namespace class (e.g. RwVnfdYang) """
109 return self._yang_ns
110
111 @property
112 def yang_class(self):
113 """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
114 return self._yang_pb_cls
115
116 @property
117 def yang_ns_project(self):
118 """ The Protobuf's GI namespace class (e.g. RwProjectVnfdYang) """
119 return self._yang_ns_project
120
121 @property
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
125
126 @property
127 def model(self):
128 cls = self.__class__
129
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())
135
136 return cls.libncx_model
137
138 def _from_xml_file_hdl(self, file_hdl):
139 xml = file_hdl.read()
140
141 return self.yang_class.from_xml_v2(self.model, decode(xml), strict=False)
142
143 def _from_json_file_hdl(self, file_hdl):
144 json = file_hdl.read()
145
146 return self.yang_class.from_json(self.model, decode(json), strict=False)
147
148 def _from_yaml_file_hdl(self, file_hdl):
149 yml = file_hdl.read()
150
151 # Need to prefix project on to the descriptor and then
152 # convert to yang pb
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)
159
160 try:
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)
165 raise e
166
167 def to_desc_msg(self, pb_msg, project_rooted=True):
168 """Convert to and from project rooted pb msg descriptor to catalog
169 rooted pb msg
170 """
171 if project_rooted:
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):
175 return pb_msg
176
177 else:
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):
181 return pb_msg
182
183 raise TypeError("Invalid protobuf message type provided: {}".format(type(pb_msg)))
184
185
186 def to_json_string(self, pb_msg, project_ns=False):
187 """ Serialize a protobuf message into JSON
188
189 Arguments:
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
193
194 Returns:
195 A JSON string representing the protobuf message
196
197 Raises:
198 SerializationError - Message could not be serialized
199 TypeError - Incorrect protobuf type provided
200 """
201 try:
202 # json_str = pb_msg.to_json(self.model)
203
204 desc_msg = self.to_desc_msg(pb_msg, not project_ns)
205 json_str = desc_msg.to_json(self.model)
206 if project_ns:
207 # Remove rw-project:project top level element
208 dic = json.loads(json_str)
209 jstr = json.dumps(dic[NS_PROJECT][0])
210
211 except Exception as e:
212 raise SerializationError(e)
213
214 self._log.debug("Convert desc to json: {}".format(jstr))
215 return jstr
216
217 def to_yaml_string(self, pb_msg):
218 """ Serialize a protobuf message into YAML
219
220 Arguments:
221 pb_msg - A GI-protobuf object of type provided into constructor
222
223 Returns:
224 A YAML string representing the protobuf message
225
226 Raises:
227 SerializationError - Message could not be serialized
228 TypeError - Incorrect protobuf type provided
229 """
230 try:
231 desc_msg = self.to_desc_msg(pb_msg)
232 yaml_str = desc_msg.to_yaml(self.model)
233
234 except Exception as e:
235 self._log.exception("Exception converting to yaml: {}".format(e))
236 raise SerializationError(e)
237
238 return yaml_str
239
240 def to_xml_string(self, pb_msg):
241 """ Serialize a protobuf message into XML
242
243 Arguments:
244 pb_msg - A GI-protobuf object of type provided into constructor
245
246 Returns:
247 A XML string representing the protobuf message
248
249 Raises:
250 SerializationError - Message could not be serialized
251 TypeError - Incorrect protobuf type provided
252 """
253 try:
254 desc_msg = self.to_desc_msg(pb_msg)
255 xml_str = desc_msg.to_xml_v2(self.model)
256
257 except Exception as e:
258 self._log.exception("Exception converting to xml: {}".format(e))
259 raise SerializationError(e)
260
261 return xml_str
262
263 def from_file_hdl(self, file_hdl, extension):
264 """ Returns the deserialized protobuf message from file contents
265
266 This function determines the serialization format based on file extension
267
268 Arguments:
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())
271
272 Returns:
273 A GI-Proto message of type that was provided into the constructor
274
275 Raises:
276 UnknownExtensionError - File extension is not of a known serialization format
277 SerializationError - File failed to be deserialized into the protobuf message
278 """
279
280 extension_lc = extension.lower()
281 extension_map = self._deserialize_extension_method_map()
282
283 if extension_lc not in extension_map:
284 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
285
286 try:
287 msg = extension_map[extension_lc](self, file_hdl)
288 except Exception as e:
289 raise SerializationError(e)
290
291 return msg
292
293 def to_string(self, pb_msg, extension):
294 """ Returns the serialized protobuf message for a particular file extension
295
296 This function determines the serialization format based on file extension
297
298 Arguments:
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())
301
302 Returns:
303 A GI-Proto message of type that was provided into the constructor
304
305 Raises:
306 UnknownExtensionError - File extension is not of a known serialization format
307 SerializationError - File failed to be deserialized into the protobuf message
308 """
309
310 extension_lc = extension.lower()
311 extension_map = self._serialize_extension_method_map()
312
313 if extension_lc not in extension_map:
314 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
315
316 try:
317 msg = extension_map[extension_lc](self, pb_msg)
318 except Exception as e:
319 raise SerializationError(e)
320
321 return msg
322
323
324 class VnfdSerializer(ProtoMessageSerializer):
325 """ Creates a serializer for the VNFD descriptor"""
326 def __init__(self):
327 super().__init__(VnfdYang, VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd,
328 ProjectVnfdYang, ProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
329
330
331 class NsdSerializer(ProtoMessageSerializer):
332 """ Creates a serializer for the NSD descriptor"""
333 def __init__(self):
334 super().__init__(NsdYang, NsdYang.YangData_Nsd_NsdCatalog_Nsd,
335 ProjectNsdYang, ProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)
336
337
338 class RwVnfdSerializer(ProtoMessageSerializer):
339 """ Creates a serializer for the VNFD descriptor"""
340 def __init__(self):
341 super().__init__(RwVnfdYang, RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd,
342 RwProjectVnfdYang, RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
343
344
345 class RwNsdSerializer(ProtoMessageSerializer):
346 """ Creates a serializer for the NSD descriptor"""
347 def __init__(self):
348 super().__init__(RwNsdYang, RwNsdYang.YangData_Nsd_NsdCatalog_Nsd,
349 RwProjectNsdYang, RwProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)