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")
65 def add_image(self
, nsd_id
, image
, chksum
=None):
66 if image
.name
not in self
.images
:
67 self
.images
[image
.name
] = image
69 def add_vld(self
, nsd_id
, vld
, pkg
=None):
70 if not 'vlds' in self
.nsds
[nsd_id
]:
71 self
.nsds
[nsd_id
]['vlds'] = []
72 self
.nsds
[nsd_id
]['vlds'].append(vld
)
74 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
76 def add_vnfd(self
, nsd_id
, vnfd
, pkg
=None):
77 if not 'vnfds' in self
.nsds
[nsd_id
]:
78 self
.nsds
[nsd_id
]['vnfds'] = []
79 self
.nsds
[nsd_id
]['vnfds'].append(vnfd
)
81 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
83 def add_nsd(self
, nsd
, pkg
=None):
84 nsd_id
= str(uuid
.uuid4())
85 self
.nsds
[nsd_id
] = {'nsd': nsd
}
86 self
.nsds
[nsd_id
]['pkgs'] = []
88 self
.nsds
[nsd_id
]['pkgs'].append(pkg
)
91 def create_csar(self
, nsd_id
, dest
=None):
93 dest
= tempfile
.mkdtemp()
95 # Convert YANG to dict
98 for vnfd
in self
.nsds
[nsd_id
]['vnfds']:
99 yangs
['vnfd'].append(vnfd
.as_dict())
100 self
.log
.debug("Translate VNFD: {}".format(vnfd
.as_dict()))
102 yangs
['nsd'].append(self
.nsds
[nsd_id
]['nsd'].as_dict())
103 self
.log
.debug("Translate NSD : {}".format(yangs
['nsd']))
105 # Translate YANG model to TOSCA template
106 translator
= YangTranslator(self
.log
,
108 packages
=self
.nsds
[nsd_id
]['pkgs'])
109 output
= translator
.translate()
110 self
.csars
.extend(translator
.write_output(output
,
113 self
.log
.debug("Created CSAR archive {}".format(self
.csars
[-1]))
115 def create_archive(self
, archive_name
, dest
=None):
116 if not len(self
.nsds
):
117 self
.log
.error("Did not find any NSDs to export")
121 dest
= tempfile
.mkdtemp()
123 prevdir
= os
.getcwd()
125 if not os
.path
.exists(dest
):
129 # Convert each NSD to a TOSCA template
130 for nsd_id
in self
.nsds
:
131 # Not passing the dest dir to prevent clash in case
132 # multiple export of the same desc happens
133 self
.create_csar(nsd_id
)
135 except Exception as e
:
136 msg
= "Exception converting NSD {}: {}".format(nsd_id
, e
)
137 self
.log
.exception(e
)
138 raise YangTranslateNsdError(msg
)
143 if archive_name
.endswith(".zip"):
144 archive_name
= archive_name
[:-4]
146 archive_path
= os
.path
.join(dest
, archive_name
)
148 # Construct a zip of the csar archives
149 zip_name
= '{}.zip'.format(archive_path
)
151 if len(self
.csars
) == 1:
152 # Only 1 TOSCA template, just rename csar if required
153 if self
.csars
[0] != zip_name
:
154 mv_cmd
= "mv {} {}".format(self
.csars
[0], zip_name
)
155 subprocess
.check_call(mv_cmd
, shell
=True, stdout
=subprocess
.DEVNULL
)
156 # Remove the temporary directory created
157 shutil
.rmtree(os
.path
.dirname(self
.csars
[0]))
160 with zipfile
.ZipFile('{}.partial'.format(zip_name
), 'w') as zf
:
161 for csar
in self
.csars
:
162 # Move file to the current dest dir
163 if os
.path
.dirname(csar
) != dest
:
164 file_mv
= "mv {} {}".format(csar
, dest
)
165 subprocess
.check_call(file_mv
,
167 stdout
=subprocess
.DEVNULL
)
168 # Remove the temporary directory created
169 shutil
.rmtree(os
.path
.dirname(csar
))
171 csar_f
= os
.basename(csar
)
172 # Now add to the archive
174 # Remove the csar file
177 # Rename archive to final name
178 mv_cmd
= "mv {0}.partial {0}".format(zip_name
)
179 subprocess
.check_call(mv_cmd
, shell
=True, stdout
=subprocess
.DEVNULL
)
183 except Exception as e
:
184 msg
= "Creating CSAR archive failed: {0}".format(e
)
185 self
.log
.exception(e
)
186 raise YangTranslateError(msg
)
191 class ImportTosca(object):
193 def __init__(self
, log
, in_file
, out_dir
=None):
195 self
.log
= logging
.getLogger("rw-mano-log")
199 self
.in_file
= in_file
200 self
.out_dir
= out_dir
203 # Check if the input file is a zip file
204 if not zipfile
.is_zipfile(self
.in_file
):
205 err_msg
= "{} is not a zip file.".format(self
.in_file
)
206 self
.log
.error(err_msg
)
207 raise InvalidToscaPackageError(err_msg
)
210 # Store the current working directory
211 prevdir
= os
.getcwd()
213 # See if we need to create a output directory
214 out_dir
= self
.out_dir
216 out_dir
= tempfile
.mkdtemp()
218 # Call the TOSCA translator
219 self
.log
.debug("Calling tosca-translator for {}".
220 format(self
.in_file
))
221 return TranslatorShell(self
.log
).translate(self
.in_file
,
225 except Exception as e
:
226 self
.log
.exception(e
)
227 raise ToscaTranslateError("Error translating TOSCA package {}: {}".
228 format(self
.in_file
, e
))
234 def is_tosca_package(in_file
):
235 if zipfile
.is_zipfile(in_file
):