907a4a0e59f82296969b956dc47fff57091ae4ed
[osm/SO.git] / common / python / rift / mano / yang_translator / rwmano / yang_translator.py
1 # Copyright 2016 RIFT.io Inc
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15
16 import os
17 import shutil
18 import subprocess
19 import tarfile
20
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 \
24 import ToscaResource
25 from rift.mano.yang_translator.rwmano.syntax.tosca_template \
26 import ToscaTemplate
27 from rift.mano.yang_translator.rwmano.translate_descriptors \
28 import TranslateDescriptors
29
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
36
37 class YangTranslator(object):
38 '''Invokes translation methods.'''
39
40 def __init__(self, log, yangs=None, files=None, packages=[]):
41 super(YangTranslator, self).__init__()
42 self.log = log
43 self.yangs = {}
44 if yangs is not None:
45 self.yangs = yangs
46 self.files = files
47 self.archive = None
48 self.tosca_template = ToscaTemplate(log)
49 self.node_translator = None
50 self.pkgs = packages
51 log.info(_('Initialized parameters for translation.'))
52
53 def translate(self):
54 if self.files:
55 self.get_yangs()
56
57 self.node_translator = TranslateDescriptors(self.log,
58 self.yangs,
59 self.tosca_template)
60
61 self.tosca_template.resources = self.node_translator.translate()
62
63 return self.tosca_template.output_to_tosca()
64
65 def get_yangs(self):
66 '''Get the descriptors and convert to yang instances'''
67 for filename in self.files:
68 self.log.debug(_("Load file {0}").format(filename))
69 # Only one descriptor per file
70 if tarfile.is_tarfile(filename):
71 tar = open(filename, "r+b")
72 archive = TarPackageArchive(self.log, tar)
73 pkg = archive.create_package()
74 self.pkgs.append(pkg)
75 desc_type = pkg.descriptor_type
76 if desc_type == TranslateDescriptors.NSD:
77 if TranslateDescriptors.NSD not in self.yangs:
78 self.yangs[TranslateDescriptors.NSD] = []
79 self.yangs[TranslateDescriptors.NSD]. \
80 append(pkg.descriptor_msg.as_dict())
81 elif desc_type == TranslateDescriptors.VNFD:
82 if TranslateDescriptors.VNFD not in self.yangs:
83 self.yangs[TranslateDescriptors.VNFD] = []
84 self.yangs[TranslateDescriptors.VNFD]. \
85 append(pkg.descriptor_msg.as_dict())
86 else:
87 raise ValidationError("Unknown descriptor type: {}".
88 format(desc_type))
89
90 def _create_csar_files(self, output_dir, name, tmpl,
91 archive=False):
92 if ToscaTemplate.TOSCA not in tmpl:
93 self.log.error(_("Did not find TOSCA template for {0}").
94 format(name))
95 return
96
97 # Create sub for each NS template
98 subdir = os.path.join(output_dir, name)
99 if os.path.exists(subdir):
100 shutil.rmtree(subdir)
101 os.makedirs(subdir)
102
103 # Create the definitions dir
104 def_dir = os.path.join(subdir, 'Definitions')
105 os.makedirs(def_dir)
106 entry_file = os.path.join(def_dir, name+'.yaml')
107 self.log.debug(_("Writing file {0}").
108 format(entry_file))
109 with open(entry_file, 'w+') as f:
110 f.write(tmpl[ToscaTemplate.TOSCA])
111
112 # Create the Tosca meta
113 meta_dir = os.path.join(subdir, 'TOSCA-Metadata')
114 os.makedirs(meta_dir)
115 meta = '''TOSCA-Meta-File-Version: 1.0
116 CSAR-Version: 1.1
117 Created-By: RIFT.io
118 Entry-Definitions: Definitions/'''
119 meta_data = "{}{}".format(meta, name+'.yaml')
120 meta_file = os.path.join(meta_dir, 'TOSCA.meta')
121 self.log.debug(_("Writing file {0}:\n{1}").
122 format(meta_file, meta_data))
123 with open(meta_file, 'w+') as f:
124 f.write(meta_data)
125
126 # Copy other supporting files
127 if ToscaTemplate.FILES in tmpl:
128 for f in tmpl[ToscaTemplate.FILES]:
129 self.log.debug(_("Copy supporting file {0}").format(f))
130
131 # Search in source packages
132 if len(self.pkgs):
133 for pkg in self.pkgs:
134 # TODO(pjoseph): Need to add support for other file types
135 fname = f[ToscaResource.NAME]
136 dest_path = os.path.join(subdir, f[ToscaResource.DEST])
137 ftype = f[ToscaResource.TYPE]
138
139 if ftype == 'image':
140 image_file_map = rift.package.image.get_package_image_files(pkg)
141
142 if fname in image_file_map:
143 self.log.debug(_("Extracting image {0} to {1}").
144 format(fname, dest_path))
145 pkg.extract_file(image_file_map[fname],
146 dest_path)
147 break
148
149 elif ftype == 'script':
150 script_file_map = \
151 rift.package.script.PackageScriptExtractor.package_script_files(pkg)
152 if fname in script_file_map:
153 self.log.debug(_("Extracting script {0} to {1}").
154 format(fname, dest_path))
155 pkg.extract_file(script_file_map[fname],
156 dest_path)
157 break
158
159 elif ftype == 'cloud_init':
160 script_file_map = \
161 rift.package.cloud_init.PackageCloudInitExtractor.package_script_files(pkg)
162 if fname in script_file_map:
163 self.log.debug(_("Extracting script {0} to {1}").
164 format(fname, dest_path))
165 pkg.extract_file(script_file_map[fname],
166 dest_path)
167 break
168
169 else:
170 self.log.warn(_("Unknown file type {0}: {1}").
171 format(ftype, f))
172
173 #TODO(pjoseph): Search in other locations
174
175 # Create the ZIP archive
176 if archive:
177 prev_dir=os.getcwd()
178 os.chdir(subdir)
179
180 try:
181 zip_file = name + '.zip'
182 zip_path = os.path.join(output_dir, zip_file)
183 self.log.debug(_("Creating zip file {0}").format(zip_path))
184 zip_cmd = "zip -r {}.partial ."
185 subprocess.check_call(zip_cmd.format(zip_path),
186 shell=True,
187 stdout=subprocess.DEVNULL)
188 mv_cmd = "mv {0}.partial {0}"
189 subprocess.check_call(mv_cmd.format(zip_path),
190 shell=True,
191 stdout=subprocess.DEVNULL)
192 shutil.rmtree(subdir)
193 return zip_path
194
195 except subprocess.CalledProcessError as e:
196 self.log.error(_("Creating CSAR archive failed: {0}").
197 format(e))
198
199 except Exception as e:
200 self.log.exception(e)
201
202 finally:
203 os.chdir(prev_dir)
204
205 def write_output(self, output,
206 output_dir=None,
207 archive=False,):
208 if output:
209 zip_files = []
210 for key in output.keys():
211 if output_dir:
212 zf = self._create_csar_files(output_dir,
213 key,
214 output[key],
215 archive=archive,)
216 zip_files.append(zf)
217 else:
218 print(_("TOSCA Template {0}:\n{1}").
219 format(key, output[key]))
220 return zip_files