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.
21 from rift
.mano
.yang_translator
.common
.exception
import ValidationError
22 from rift
.mano
.yang_translator
.common
.utils
import _
23 from rift
.mano
.yang_translator
.rwmano
.syntax
.tosca_resource \
25 from rift
.mano
.yang_translator
.rwmano
.syntax
.tosca_template \
27 from rift
.mano
.yang_translator
.rwmano
.translate_descriptors \
28 import TranslateDescriptors
30 import rift
.package
.image
31 from rift
.package
.package
import TarPackageArchive
32 import rift
.package
.cloud_init
33 import rift
.package
.script
34 import rift
.package
.store
35 import rift
.package
.icon
37 class YangTranslator(object):
38 '''Invokes translation methods.'''
40 def __init__(self
, log
, yangs
=None, files
=None, packages
=[]):
41 super(YangTranslator
, self
).__init
__()
48 self
.tosca_template
= ToscaTemplate(log
)
49 self
.node_translator
= None
51 self
.output_files
= {}
52 self
.output_files
['nsd'] = []
53 self
.output_files
['vnfd'] = []
55 log
.info(_('Initialized parameters for translation.'))
61 if 'nsd' in self
.yangs
:
62 self
.output_files
['nsd'].append(self
.yangs
['nsd'][0]['short_name'].replace(' ','_'))
63 if 'vnfd' in self
.yangs
:
64 for yang_vnfd
in self
.yangs
['vnfd']:
65 self
.output_files
['vnfd'].append(yang_vnfd
['short_name'].replace(' ','_'))
67 self
.node_translator
= TranslateDescriptors(self
.log
,
70 self
.output_files
['vnfd'])
71 self
.tosca_template
.resources
= self
.node_translator
.translate()
74 return self
.tosca_template
.output_to_tosca()
77 '''Get the descriptors and convert to yang instances'''
78 for filename
in self
.files
:
79 self
.log
.debug(_("Load file {0}").format(filename
))
81 # Only one descriptor per file
82 if tarfile
.is_tarfile(filename
):
83 tar
= open(filename
, "r+b")
84 archive
= TarPackageArchive(self
.log
, tar
)
85 pkg
= archive
.create_package()
87 desc_type
= pkg
.descriptor_type
88 if desc_type
== TranslateDescriptors
.NSD
:
89 if TranslateDescriptors
.NSD
not in self
.yangs
:
90 self
.yangs
[TranslateDescriptors
.NSD
] = []
91 self
.yangs
[TranslateDescriptors
.NSD
]. \
92 append(pkg
.descriptor_msg
.as_dict())
93 if 'name' in pkg
.descriptor_msg
.as_dict() is not None:
94 self
.output_files
['nsd'].append(pkg
.descriptor_msg
.as_dict()['name'])
96 raise ValidationError(message
="NSD Descriptor name attribute is not populated ")
97 elif desc_type
== TranslateDescriptors
.VNFD
:
98 if TranslateDescriptors
.VNFD
not in self
.yangs
:
99 self
.yangs
[TranslateDescriptors
.VNFD
] = []
100 self
.yangs
[TranslateDescriptors
.VNFD
]. \
101 append(pkg
.descriptor_msg
.as_dict())
102 if 'name' in pkg
.descriptor_msg
.as_dict() is not None:
103 self
.output_files
['vnfd'].append(pkg
.descriptor_msg
.as_dict()['name'])
105 raise ValidationError(message
="VNFD Descriptor name attribute is not populated ")
107 raise ValidationError("Unknown descriptor type: {}".
110 def _create_csar_files(self
, output_dir
, tmpl_out
,
113 for tmpl in tmpl_out:
114 if ToscaTemplate.TOSCA not in tmpl:
115 self.log.error(_("Did not find TOSCA template for {0}").
119 # Create sub for each NS template
120 sub_folder_name
= None
122 if len(self
.output_files
['nsd']) > 0:
123 if len(self
.output_files
['nsd']) == 1:
124 sub_folder_name
= self
.output_files
['nsd'][0]
126 raise ValidationError(message
="Multiple NSD Descriptor uploaded ")
127 elif len(self
.output_files
['vnfd']) > 0:
128 if len(self
.output_files
['vnfd']) == 1:
129 sub_folder_name
= self
.output_files
['vnfd'][0]
131 raise ValidationError(message
="Multiple VNFDs Descriptors uploaded without NSD")
133 raise ValidationError(message
="No NSD or VNFD uploaded")
135 if 'nsd' in self
.yangs
:
136 sub_folder_name
= self
.yangs
['nsd'][0]['short_name'].replace(' ','_')
137 elif 'vnfd' in self
.yangs
:
138 sub_folder_name
= self
.yangs
['vnfd'][0]['short_name'].replace(' ','_')
141 subdir
= os
.path
.join(output_dir
, sub_folder_name
)
142 if os
.path
.exists(subdir
):
143 shutil
.rmtree(subdir
)
145 riftio_src_file
= "{0}{1}".format(os
.getenv('RIFT_INSTALL'), "/usr/rift/mano/common/riftiotypes.yaml")
146 # Create the definitions dir
147 def_dir
= os
.path
.join(subdir
, 'Definitions')
149 shutil
.copy2(riftio_src_file
, def_dir
+ "/riftiotypes.yaml")
150 tosca_meta_entry_file
= None
151 for tmpl_key
in tmpl_out
:
152 tmpl
= tmpl_out
[tmpl_key
]
153 file_name
= tmpl_key
.replace(' ','_')
154 entry_file
= os
.path
.join(def_dir
, file_name
+'.yaml')
155 if file_name
.endswith('nsd'):
156 tosca_meta_entry_file
= file_name
157 self
.log
.debug(_("Writing file {0}").
159 with
open(entry_file
, 'w+') as f
:
160 f
.write(tmpl
[ToscaTemplate
.TOSCA
])
162 if tosca_meta_entry_file
is None:
163 tosca_meta_entry_file
= sub_folder_name
164 # Create the Tosca meta
165 meta_dir
= os
.path
.join(subdir
, 'TOSCA-Metadata')
166 os
.makedirs(meta_dir
)
167 meta
= '''TOSCA-Meta-File-Version: 1.0
170 Entry-Definitions: Definitions/'''
171 meta_data
= "{}{}".format(meta
, tosca_meta_entry_file
+'.yaml')
172 meta_file
= os
.path
.join(meta_dir
, 'TOSCA.meta')
173 self
.log
.debug(_("Writing file {0}:\n{1}").
174 format(meta_file
, meta_data
))
175 with
open(meta_file
, 'w+') as f
:
178 # Copy other supporting files
181 if ToscaTemplate
.FILES
in tmpl
:
182 for f
in tmpl
[ToscaTemplate
.FILES
]:
183 self
.log
.debug(_("Copy supporting file {0}").format(f
))
185 # Search in source packages
187 for pkg
in self
.pkgs
:
188 # TODO(pjoseph): Need to add support for other file types
189 fname
= f
[ToscaResource
.NAME
]
190 dest_path
= os
.path
.join(subdir
, f
[ToscaResource
.DEST
])
191 ftype
= f
[ToscaResource
.TYPE
]
194 image_file_map
= rift
.package
.image
.get_package_image_files(pkg
)
196 if fname
in image_file_map
:
197 self
.log
.debug(_("Extracting image {0} to {1}").
198 format(fname
, dest_path
))
199 pkg
.extract_file(image_file_map
[fname
],
203 elif ftype
== 'script':
205 rift
.package
.script
.PackageScriptExtractor
.package_script_files(pkg
)
206 if fname
in script_file_map
:
207 self
.log
.debug(_("Extracting script {0} to {1}").
208 format(fname
, dest_path
))
209 pkg
.extract_file(script_file_map
[fname
],
213 elif ftype
== 'cloud_init':
215 rift
.package
.cloud_init
.PackageCloudInitExtractor
.package_script_files(pkg
)
216 if fname
in script_file_map
:
217 self
.log
.debug(_("Extracting script {0} to {1}").
218 format(fname
, dest_path
))
219 pkg
.extract_file(script_file_map
[fname
],
222 elif ftype
== 'icons':
224 rift
.package
.icon
.PackageIconExtractor
.package_icon_files(pkg
)
225 if fname
in icon_file_map
:
226 self
.log
.debug(_("Extracting script {0} to {1}").
227 format(fname
, dest_path
))
228 pkg
.extract_file(icon_file_map
[fname
],
233 self
.log
.warn(_("Unknown file type {0}: {1}").
236 #TODO(pjoseph): Search in other locations
238 # Create the ZIP archive
244 zip_file
= sub_folder_name
+ '.zip'
245 zip_path
= os
.path
.join(output_dir
, zip_file
)
246 self
.log
.debug(_("Creating zip file {0}").format(zip_path
))
247 zip_cmd
= "zip -r {}.partial ."
248 subprocess
.check_call(zip_cmd
.format(zip_path
),
250 stdout
=subprocess
.DEVNULL
)
251 mv_cmd
= "mv {0}.partial {0}"
252 subprocess
.check_call(mv_cmd
.format(zip_path
),
254 stdout
=subprocess
.DEVNULL
)
255 shutil
.rmtree(subdir
)
258 except subprocess
.CalledProcessError
as e
:
259 self
.log
.error(_("Creating CSAR archive failed: {0}").
262 except Exception as e
:
263 self
.log
.exception(e
)
268 def write_output(self
, output
,
273 #for key in output.keys():
275 zf
= self
._create
_csar
_files
(output_dir
,
280 print(_("There is an issue with TOSCA Template"))