RIFT OSM R1 Initial Submission
[osm/SO.git] / common / python / rift / mano / yang_translator / rwmano / yang_translator.py
diff --git a/common/python/rift/mano/yang_translator/rwmano/yang_translator.py b/common/python/rift/mano/yang_translator/rwmano/yang_translator.py
new file mode 100644 (file)
index 0000000..907a4a0
--- /dev/null
@@ -0,0 +1,220 @@
+# Copyright 2016 RIFT.io Inc
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+import shutil
+import subprocess
+import tarfile
+
+from rift.mano.yang_translator.common.exception import ValidationError
+from rift.mano.yang_translator.common.utils import _
+from rift.mano.yang_translator.rwmano.syntax.tosca_resource \
+    import ToscaResource
+from rift.mano.yang_translator.rwmano.syntax.tosca_template \
+    import ToscaTemplate
+from rift.mano.yang_translator.rwmano.translate_descriptors \
+    import TranslateDescriptors
+
+import rift.package.image
+from rift.package.package import TarPackageArchive
+import rift.package.cloud_init
+import rift.package.script
+import rift.package.store
+
+
+class YangTranslator(object):
+    '''Invokes translation methods.'''
+
+    def __init__(self, log, yangs=None, files=None, packages=[]):
+        super(YangTranslator, self).__init__()
+        self.log = log
+        self.yangs = {}
+        if yangs is not None:
+            self.yangs = yangs
+        self.files = files
+        self.archive = None
+        self.tosca_template = ToscaTemplate(log)
+        self.node_translator = None
+        self.pkgs = packages
+        log.info(_('Initialized parameters for translation.'))
+
+    def translate(self):
+        if self.files:
+            self.get_yangs()
+
+        self.node_translator = TranslateDescriptors(self.log,
+                                                      self.yangs,
+                                                      self.tosca_template)
+
+        self.tosca_template.resources = self.node_translator.translate()
+
+        return self.tosca_template.output_to_tosca()
+
+    def get_yangs(self):
+        '''Get the descriptors and convert to yang instances'''
+        for filename in self.files:
+            self.log.debug(_("Load file {0}").format(filename))
+            # Only one descriptor per file
+            if tarfile.is_tarfile(filename):
+                tar = open(filename, "r+b")
+                archive = TarPackageArchive(self.log, tar)
+                pkg = archive.create_package()
+                self.pkgs.append(pkg)
+                desc_type = pkg.descriptor_type
+                if desc_type == TranslateDescriptors.NSD:
+                    if TranslateDescriptors.NSD not in self.yangs:
+                        self.yangs[TranslateDescriptors.NSD] = []
+                    self.yangs[TranslateDescriptors.NSD]. \
+                        append(pkg.descriptor_msg.as_dict())
+                elif desc_type == TranslateDescriptors.VNFD:
+                    if TranslateDescriptors.VNFD not in self.yangs:
+                        self.yangs[TranslateDescriptors.VNFD] = []
+                    self.yangs[TranslateDescriptors.VNFD]. \
+                        append(pkg.descriptor_msg.as_dict())
+                else:
+                    raise ValidationError("Unknown descriptor type: {}".
+                                          format(desc_type))
+
+    def _create_csar_files(self, output_dir, name, tmpl,
+                           archive=False):
+        if ToscaTemplate.TOSCA not in tmpl:
+            self.log.error(_("Did not find TOSCA template for {0}").
+                           format(name))
+            return
+
+        # Create sub for each NS template
+        subdir = os.path.join(output_dir, name)
+        if os.path.exists(subdir):
+            shutil.rmtree(subdir)
+        os.makedirs(subdir)
+
+        # Create the definitions dir
+        def_dir = os.path.join(subdir, 'Definitions')
+        os.makedirs(def_dir)
+        entry_file = os.path.join(def_dir, name+'.yaml')
+        self.log.debug(_("Writing file {0}").
+                       format(entry_file))
+        with open(entry_file, 'w+') as f:
+            f.write(tmpl[ToscaTemplate.TOSCA])
+
+        # Create the Tosca meta
+        meta_dir = os.path.join(subdir, 'TOSCA-Metadata')
+        os.makedirs(meta_dir)
+        meta = '''TOSCA-Meta-File-Version: 1.0
+CSAR-Version: 1.1
+Created-By: RIFT.io
+Entry-Definitions: Definitions/'''
+        meta_data = "{}{}".format(meta, name+'.yaml')
+        meta_file = os.path.join(meta_dir, 'TOSCA.meta')
+        self.log.debug(_("Writing file {0}:\n{1}").
+                       format(meta_file, meta_data))
+        with open(meta_file, 'w+') as f:
+            f.write(meta_data)
+
+        # Copy other supporting files
+        if ToscaTemplate.FILES in tmpl:
+            for f in tmpl[ToscaTemplate.FILES]:
+                self.log.debug(_("Copy supporting file {0}").format(f))
+
+                # Search in source packages
+                if len(self.pkgs):
+                    for pkg in self.pkgs:
+                        # TODO(pjoseph): Need to add support for other file types
+                        fname = f[ToscaResource.NAME]
+                        dest_path = os.path.join(subdir, f[ToscaResource.DEST])
+                        ftype = f[ToscaResource.TYPE]
+
+                        if ftype == 'image':
+                            image_file_map = rift.package.image.get_package_image_files(pkg)
+
+                            if fname in image_file_map:
+                                self.log.debug(_("Extracting image {0} to {1}").
+                                               format(fname, dest_path))
+                                pkg.extract_file(image_file_map[fname],
+                                                 dest_path)
+                                break
+
+                        elif ftype == 'script':
+                            script_file_map = \
+                                rift.package.script.PackageScriptExtractor.package_script_files(pkg)
+                            if fname in script_file_map:
+                                self.log.debug(_("Extracting script {0} to {1}").
+                                               format(fname, dest_path))
+                                pkg.extract_file(script_file_map[fname],
+                                                 dest_path)
+                                break
+
+                        elif ftype == 'cloud_init':
+                            script_file_map = \
+                                rift.package.cloud_init.PackageCloudInitExtractor.package_script_files(pkg)
+                            if fname in script_file_map:
+                                self.log.debug(_("Extracting script {0} to {1}").
+                                               format(fname, dest_path))
+                                pkg.extract_file(script_file_map[fname],
+                                                 dest_path)
+                                break
+
+                        else:
+                            self.log.warn(_("Unknown file type {0}: {1}").
+                                          format(ftype, f))
+
+                #TODO(pjoseph): Search in other locations
+
+        # Create the ZIP archive
+        if archive:
+            prev_dir=os.getcwd()
+            os.chdir(subdir)
+
+            try:
+                zip_file = name + '.zip'
+                zip_path = os.path.join(output_dir, zip_file)
+                self.log.debug(_("Creating zip file {0}").format(zip_path))
+                zip_cmd = "zip -r {}.partial ."
+                subprocess.check_call(zip_cmd.format(zip_path),
+                                      shell=True,
+                                      stdout=subprocess.DEVNULL)
+                mv_cmd = "mv {0}.partial {0}"
+                subprocess.check_call(mv_cmd.format(zip_path),
+                                      shell=True,
+                                      stdout=subprocess.DEVNULL)
+                shutil.rmtree(subdir)
+                return zip_path
+
+            except subprocess.CalledProcessError as e:
+                self.log.error(_("Creating CSAR archive failed: {0}").
+                               format(e))
+
+            except Exception as e:
+                self.log.exception(e)
+
+            finally:
+                os.chdir(prev_dir)
+
+    def write_output(self, output,
+                     output_dir=None,
+                     archive=False,):
+        if output:
+            zip_files = []
+            for key in output.keys():
+                if output_dir:
+                    zf = self._create_csar_files(output_dir,
+                                                 key,
+                                                 output[key],
+                                                 archive=archive,)
+                    zip_files.append(zf)
+                else:
+                    print(_("TOSCA Template {0}:\n{1}").
+                          format(key, output[key]))
+            return zip_files