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
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'])
63 if 'vnfd' in self
.yangs
:
64 for yang_vnfd
in self
.yangs
['vnfd']:
65 self
.output_files
['vnfd'].append(yang_vnfd
['short_name'])
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']
137 elif 'vnfd' in self
.yangs
:
138 sub_folder_name
= self
.yangs
['vnfd'][0]['short_name']
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 for tmpl_key
in tmpl_out
:
151 tmpl
= tmpl_out
[tmpl_key
]
152 entry_file
= os
.path
.join(def_dir
, tmpl_key
+'.yaml')
153 self
.log
.debug(_("Writing file {0}").
155 with
open(entry_file
, 'w+') as f
:
156 f
.write(tmpl
[ToscaTemplate
.TOSCA
])
158 # Create the Tosca meta
159 meta_dir
= os
.path
.join(subdir
, 'TOSCA-Metadata')
160 os
.makedirs(meta_dir
)
161 meta
= '''TOSCA-Meta-File-Version: 1.0
164 Entry-Definitions: Definitions/'''
165 meta_data
= "{}{}".format(meta
, sub_folder_name
+'.yaml')
166 meta_file
= os
.path
.join(meta_dir
, 'TOSCA.meta')
167 self
.log
.debug(_("Writing file {0}:\n{1}").
168 format(meta_file
, meta_data
))
169 with
open(meta_file
, 'w+') as f
:
172 # Copy other supporting files
175 if ToscaTemplate
.FILES
in tmpl
:
176 for f
in tmpl
[ToscaTemplate
.FILES
]:
177 self
.log
.debug(_("Copy supporting file {0}").format(f
))
179 # Search in source packages
181 for pkg
in self
.pkgs
:
182 # TODO(pjoseph): Need to add support for other file types
183 fname
= f
[ToscaResource
.NAME
]
184 dest_path
= os
.path
.join(subdir
, f
[ToscaResource
.DEST
])
185 ftype
= f
[ToscaResource
.TYPE
]
188 image_file_map
= rift
.package
.image
.get_package_image_files(pkg
)
190 if fname
in image_file_map
:
191 self
.log
.debug(_("Extracting image {0} to {1}").
192 format(fname
, dest_path
))
193 pkg
.extract_file(image_file_map
[fname
],
197 elif ftype
== 'script':
199 rift
.package
.script
.PackageScriptExtractor
.package_script_files(pkg
)
200 if fname
in script_file_map
:
201 self
.log
.debug(_("Extracting script {0} to {1}").
202 format(fname
, dest_path
))
203 pkg
.extract_file(script_file_map
[fname
],
207 elif ftype
== 'cloud_init':
209 rift
.package
.cloud_init
.PackageCloudInitExtractor
.package_script_files(pkg
)
210 if fname
in script_file_map
:
211 self
.log
.debug(_("Extracting script {0} to {1}").
212 format(fname
, dest_path
))
213 pkg
.extract_file(script_file_map
[fname
],
218 self
.log
.warn(_("Unknown file type {0}: {1}").
221 #TODO(pjoseph): Search in other locations
223 # Create the ZIP archive
229 zip_file
= key
+ '.zip'
230 zip_path
= os
.path
.join(output_dir
, zip_file
)
231 self
.log
.debug(_("Creating zip file {0}").format(zip_path
))
232 zip_cmd
= "zip -r {}.partial ."
233 subprocess
.check_call(zip_cmd
.format(zip_path
),
235 stdout
=subprocess
.DEVNULL
)
236 mv_cmd
= "mv {0}.partial {0}"
237 subprocess
.check_call(mv_cmd
.format(zip_path
),
239 stdout
=subprocess
.DEVNULL
)
240 shutil
.rmtree(subdir
)
243 except subprocess
.CalledProcessError
as e
:
244 self
.log
.error(_("Creating CSAR archive failed: {0}").
247 except Exception as e
:
248 self
.log
.exception(e
)
253 def write_output(self
, output
,
258 #for key in output.keys():
260 zf
= self
._create
_csar
_files
(output_dir
,
265 print(_("There is an issue with TOSCA Template"))