1 # Copyright 2016 RIFT.io Inc
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
24 from rift
.mano
.tosca_translator
.shell
import TranslatorShell
25 from rift
.mano
.yang_translator
.rwmano
.yang_translator
import YangTranslator
28 class ToscaPackageError(Exception):
32 class ToscaPackageReadError(Exception):
36 class InvalidToscaPackageError(ToscaPackageError
):
40 class ToscaTranslateError(ToscaPackageError
):
44 class YangTranslateError(Exception):
48 class ToscaArchiveCreateError(YangTranslateError
):
52 class YangTranslateNsdError(YangTranslateError
):
56 class ExportTosca(object):
57 def __init__(self
, log
=None):
59 self
.log
= logging
.getLogger("rw-mano-log")
66 def add_image(self
, nsd_id
, image
, chksum
=None):
67 if image
.name
not in self
.images
:
68 self
.images
[image
.name
] = image
70 def add_vld(self
, nsd_id
, vld
, pkg
=None):
71 if not 'vlds' in self
.nsds
[nsd_id
]:
72 self
.nsds
[nsd_id
]['vlds'] = []
73 self
.nsds
[nsd_id
]['vlds'].append(vld
)
75 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
77 def add_single_vnfd(self
, vnfd_id
, vnfd
, pkg
=None):
79 self
.vnfds
['vnfds'] = []
80 self
.vnfds
['pkgs'] = []
81 self
.vnfds
['vnfds'].append(vnfd
)
83 self
.vnfds
['pkgs'].append(pkg
)
85 def add_vnfd(self
, nsd_id
, vnfd
, pkg
=None):
86 if not 'vnfds' in self
.nsds
[nsd_id
]:
87 self
.nsds
[nsd_id
]['vnfds'] = []
88 self
.nsds
[nsd_id
]['vnfds'].append(vnfd
)
90 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
92 def add_nsd(self
, nsd
, pkg
=None):
93 nsd_id
= str(uuid
.uuid4())
94 self
.nsds
[nsd_id
] = {'nsd': nsd
}
95 self
.nsds
[nsd_id
]['pkgs'] = []
97 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
100 def create_csar(self
, nsd_id
, dest
=None):
102 dest
= tempfile
.mkdtemp()
104 # Convert YANG to dict
107 for vnfd
in self
.nsds
[nsd_id
]['vnfds']:
108 yangs
['vnfd'].append(vnfd
.as_dict())
109 self
.log
.debug("Translate VNFD: {}".format(vnfd
.as_dict()))
111 yangs
['nsd'].append(self
.nsds
[nsd_id
]['nsd'].as_dict())
112 self
.log
.debug("Translate NSD : {}".format(yangs
['nsd']))
114 # Translate YANG model to TOSCA template
115 translator
= YangTranslator(self
.log
,
117 packages
=self
.nsds
[nsd_id
]['pkgs'])
118 output
= translator
.translate()
119 self
.csars
.extend(translator
.write_output(output
,
122 self
.log
.debug("Created CSAR archive {}".format(self
.csars
[-1]))
124 def create_vnfd_csar(self
, dest
=None):
126 dest
= tempfile
.mkdtemp()
129 for vnfd
in self
.vnfds
['vnfds']:
130 yangs
['vnfd'].append(vnfd
.as_dict())
131 translator
= YangTranslator(self
.log
,
133 packages
=self
.vnfds
['pkgs'])
134 output
= translator
.translate()
135 self
.csars
.extend(translator
.write_output(output
,
138 self
.log
.debug("Created CSAR archive {}".format(self
.csars
[-1]))
141 def create_archive(self
, archive_name
, dest
=None):
142 if not len(self
.nsds
) and len(self
.vnfds
) == 0:
143 self
.log
.error("Did not find any NSDs to export")
147 dest
= tempfile
.mkdtemp()
149 prevdir
= os
.getcwd()
151 if not os
.path
.exists(dest
):
155 # Convert each NSD to a TOSCA template
156 if len(self
.nsds
) > 0:
157 for nsd_id
in self
.nsds
:
158 # Not passing the dest dir to prevent clash in case
159 # multiple export of the same desc happens
160 self
.create_csar(nsd_id
)
161 elif len(self
.vnfds
) > 0:
162 self
.create_vnfd_csar()
164 except Exception as e
:
165 msg
= "Exception converting NSD/VNFD {}".format(e
)
166 self
.log
.exception(e
)
167 raise YangTranslateNsdError(msg
)
172 if archive_name
.endswith(".zip"):
173 archive_name
= archive_name
[:-4]
175 archive_path
= os
.path
.join(dest
, archive_name
)
177 # Construct a zip of the csar archives
178 zip_name
= '{}.zip'.format(archive_path
)
180 if len(self
.csars
) == 1:
181 # Only 1 TOSCA template, just rename csar if required
182 if self
.csars
[0] != zip_name
:
183 mv_cmd
= "mv {} {}".format(self
.csars
[0], zip_name
)
184 subprocess
.check_call(mv_cmd
, shell
=True, stdout
=subprocess
.DEVNULL
)
185 # Remove the temporary directory created
186 shutil
.rmtree(os
.path
.dirname(self
.csars
[0]))
189 with zipfile
.ZipFile('{}.partial'.format(zip_name
), 'w') as zf
:
190 for csar
in self
.csars
:
191 # Move file to the current dest dir
192 if os
.path
.dirname(csar
) != dest
:
193 file_mv
= "mv {} {}".format(csar
, dest
)
194 subprocess
.check_call(file_mv
,
196 stdout
=subprocess
.DEVNULL
)
197 # Remove the temporary directory created
198 shutil
.rmtree(os
.path
.dirname(csar
))
200 csar_f
= os
.basename(csar
)
201 # Now add to the archive
203 # Remove the csar file
206 # Rename archive to final name
207 mv_cmd
= "mv {0}.partial {0}".format(zip_name
)
208 subprocess
.check_call(mv_cmd
, shell
=True, stdout
=subprocess
.DEVNULL
)
212 except Exception as e
:
213 msg
= "Creating CSAR archive failed: {0}".format(e
)
214 self
.log
.exception(e
)
215 raise YangTranslateError(msg
)
220 class ImportTosca(object):
222 def __init__(self
, log
, in_file
, out_dir
=None):
224 self
.log
= logging
.getLogger("rw-mano-log")
228 self
.in_file
= in_file
229 self
.out_dir
= out_dir
232 # Check if the input file is a zip file
233 if not zipfile
.is_zipfile(self
.in_file
):
234 err_msg
= "{} is not a zip file.".format(self
.in_file
)
235 self
.log
.error(err_msg
)
236 raise InvalidToscaPackageError(err_msg
)
239 # Store the current working directory
240 prevdir
= os
.getcwd()
242 # See if we need to create a output directory
243 out_dir
= self
.out_dir
245 out_dir
= tempfile
.mkdtemp()
247 # Call the TOSCA translator
248 self
.log
.debug("Calling tosca-translator for {}".
249 format(self
.in_file
))
250 return TranslatorShell(self
.log
).translate(self
.in_file
,
254 except Exception as e
:
255 self
.log
.exception(e
)
256 raise ToscaTranslateError("Error translating TOSCA package {}: {}".
257 format(self
.in_file
, e
))
263 def is_tosca_package(in_file
):
264 if zipfile
.is_zipfile(in_file
):