New feature: Code changes for project support
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / package / convert.py
1
2 #
3 # Copyright 2016 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 import tempfile
22 import yaml
23
24 import gi
25 gi.require_version('RwNsdYang', '1.0')
26 gi.require_version('RwVnfdYang', '1.0')
27 gi.require_version('RwYang', '1.0')
28 from gi.repository import (
29 RwNsdYang,
30 RwVnfdYang,
31 NsdYang,
32 VnfdYang,
33 RwYang,
34 )
35
36 from rift.mano.utils.project import NS_PROJECT
37
38
39 class UnknownExtensionError(Exception):
40 pass
41
42
43 class SerializationError(Exception):
44 pass
45
46
47 def decode(desc_data):
48 if isinstance(desc_data, bytes):
49 desc_data = desc_data.decode()
50
51 return desc_data
52
53
54 class ProtoMessageSerializer(object):
55 """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
56 libncx_model = None
57
58 def __init__(self, yang_ns, yang_pb_cls):
59 """ Create a serializer for a specific protobuf message """
60 self._yang_ns = yang_ns
61 self._yang_pb_cls = yang_pb_cls
62
63 @classmethod
64 def _deserialize_extension_method_map(cls):
65 return {
66 ".xml": cls._from_xml_file_hdl,
67 ".yml": cls._from_yaml_file_hdl,
68 ".yaml": cls._from_yaml_file_hdl,
69 ".json": cls._from_json_file_hdl,
70 }
71
72 @classmethod
73 def _serialize_extension_method_map(cls):
74 return {
75 ".xml": cls.to_xml_string,
76 ".yml": cls.to_yaml_string,
77 ".yaml": cls.to_yaml_string,
78 ".json": cls.to_json_string,
79 }
80
81 @classmethod
82 def is_supported_file(cls, filename):
83 """Returns whether a file has a supported file extension
84
85 Arguments:
86 filename - A descriptor file
87
88 Returns:
89 True if file extension is supported, False otherwise
90
91 """
92 _, extension = os.path.splitext(filename)
93 extension_lc = extension.lower()
94
95 return extension_lc in cls._deserialize_extension_method_map()
96
97 @property
98 def yang_namespace(self):
99 """ The Protobuf's GI namespace class (e.g. RwVnfdYang) """
100 return self._yang_ns
101
102 @property
103 def yang_class(self):
104 """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd) """
105 return self._yang_pb_cls
106
107 @property
108 def model(self):
109 cls = self.__class__
110
111 # Cache the libncx model for the serializer class
112 if cls.libncx_model is None:
113 cls.libncx_model = RwYang.model_create_libncx()
114 cls.libncx_model.load_schema_ypbc(self.yang_namespace.get_schema())
115
116 return cls.libncx_model
117
118 def _from_xml_file_hdl(self, file_hdl):
119 xml = file_hdl.read()
120
121 return self.yang_class.from_xml_v2(self.model, decode(xml), strict=False)
122
123 def _from_json_file_hdl(self, file_hdl):
124 json = file_hdl.read()
125
126 return self.yang_class.from_json(self.model, decode(json), strict=False)
127
128 def _from_yaml_file_hdl(self, file_hdl):
129 yml = file_hdl.read()
130
131 # Need to prefix project on to the descriptor and then
132 # convert to yang pb
133 # TODO: See if there is a better way to do this
134 desc = {NS_PROJECT: []}
135 desc[NS_PROJECT].append(yaml.load(decode(yml)))
136 # log = logging.getLogger('rw-mano-log')
137 # log.error("Desc from yaml: {}".format(desc))
138 return self.yang_class.from_yaml(self.model, yaml.dump(desc), strict=False)
139
140 def to_json_string(self, pb_msg):
141 """ Serialize a protobuf message into JSON
142
143 Arguments:
144 pb_msg - A GI-protobuf object of type provided into constructor
145
146 Returns:
147 A JSON string representing the protobuf message
148
149 Raises:
150 SerializationError - Message could not be serialized
151 TypeError - Incorrect protobuf type provided
152 """
153 if not isinstance(pb_msg, self._yang_pb_cls):
154 raise TypeError("Invalid protobuf message type provided")
155
156 try:
157 json_str = pb_msg.to_json(self.model)
158
159 # Remove rw-project:project top level element
160 dic = json.loads(json_str)
161 jstr = json.dumps(dic[NS_PROJECT][0])
162 except Exception as e:
163 raise SerializationError(e)
164
165 log = logging.getLogger('rw-mano-log')
166 log.error("Desc to json: {}".format(jstr))
167 return jstr
168
169 def to_yaml_string(self, pb_msg):
170 """ Serialize a protobuf message into YAML
171
172 Arguments:
173 pb_msg - A GI-protobuf object of type provided into constructor
174
175 Returns:
176 A YAML string representing the protobuf message
177
178 Raises:
179 SerializationError - Message could not be serialized
180 TypeError - Incorrect protobuf type provided
181 """
182 if not isinstance(pb_msg, self._yang_pb_cls):
183 raise TypeError("Invalid protobuf message type provided")
184
185 try:
186 yaml_str = pb_msg.to_yaml(self.model)
187
188 except Exception as e:
189 raise SerializationError(e)
190
191 return yaml_str
192
193 def to_xml_string(self, pb_msg):
194 """ Serialize a protobuf message into XML
195
196 Arguments:
197 pb_msg - A GI-protobuf object of type provided into constructor
198
199 Returns:
200 A XML string representing the protobuf message
201
202 Raises:
203 SerializationError - Message could not be serialized
204 TypeError - Incorrect protobuf type provided
205 """
206 if not isinstance(pb_msg, self._yang_pb_cls):
207 raise TypeError("Invalid protobuf message type provided")
208
209 try:
210 xml_str = pb_msg.to_xml_v2(self.model)
211
212 except Exception as e:
213 raise SerializationError(e)
214
215 return xml_str
216
217 def from_file_hdl(self, file_hdl, extension):
218 """ Returns the deserialized protobuf message from file contents
219
220 This function determines the serialization format based on file extension
221
222 Arguments:
223 file_hdl - The file hdl to deserialize (set at pos 0)
224 extension - Extension of the file format (second item of os.path.splitext())
225
226 Returns:
227 A GI-Proto message of type that was provided into the constructor
228
229 Raises:
230 UnknownExtensionError - File extension is not of a known serialization format
231 SerializationError - File failed to be deserialized into the protobuf message
232 """
233
234 extension_lc = extension.lower()
235 extension_map = self._deserialize_extension_method_map()
236
237 if extension_lc not in extension_map:
238 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
239
240 try:
241 msg = extension_map[extension_lc](self, file_hdl)
242 except Exception as e:
243 raise SerializationError(e)
244
245 return msg
246
247 def to_string(self, pb_msg, extension):
248 """ Returns the serialized protobuf message for a particular file extension
249
250 This function determines the serialization format based on file extension
251
252 Arguments:
253 pb_msg - A GI-protobuf object of type provided into constructor
254 extension - Extension of the file format (second item of os.path.splitext())
255
256 Returns:
257 A GI-Proto message of type that was provided into the constructor
258
259 Raises:
260 UnknownExtensionError - File extension is not of a known serialization format
261 SerializationError - File failed to be deserialized into the protobuf message
262 """
263
264 extension_lc = extension.lower()
265 extension_map = self._serialize_extension_method_map()
266
267 if extension_lc not in extension_map:
268 raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
269
270 try:
271 msg = extension_map[extension_lc](self, pb_msg)
272 except Exception as e:
273 raise SerializationError(e)
274
275 return msg
276
277
278 class VnfdSerializer(ProtoMessageSerializer):
279 """ Creates a serializer for the VNFD descriptor"""
280 def __init__(self):
281 super().__init__(VnfdYang, VnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
282
283
284 class NsdSerializer(ProtoMessageSerializer):
285 """ Creates a serializer for the NSD descriptor"""
286 def __init__(self):
287 super().__init__(NsdYang, NsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)
288
289
290 class RwVnfdSerializer(ProtoMessageSerializer):
291 """ Creates a serializer for the VNFD descriptor"""
292 def __init__(self):
293 super().__init__(RwVnfdYang, RwVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
294
295
296 class RwNsdSerializer(ProtoMessageSerializer):
297 """ Creates a serializer for the NSD descriptor"""
298 def __init__(self):
299 super().__init__(RwNsdYang, RwNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)