ariatosca-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dankil...@apache.org
Subject incubator-ariatosca git commit: ARIA-23 TBD [Forced Update!]
Date Mon, 28 Nov 2016 16:55:01 GMT
Repository: incubator-ariatosca
Updated Branches:
  refs/heads/ARIA-23-integrate-csar-packager 3075251bd -> eea536dec (forced update)


ARIA-23 TBD


Project: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/commit/eea536de
Tree: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/tree/eea536de
Diff: http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/diff/eea536de

Branch: refs/heads/ARIA-23-integrate-csar-packager
Commit: eea536dec3f79a87d5668727e136143033d22de1
Parents: 3323819
Author: Dan Kilman <dank@gigaspaces.com>
Authored: Thu Nov 17 12:43:49 2016 +0200
Committer: Dan Kilman <dank@gigaspaces.com>
Committed: Mon Nov 28 18:54:56 2016 +0200

----------------------------------------------------------------------
 aria/cli/args_parser.py    |  44 +++++++++++++++++
 aria/cli/cli.py            |   6 +++
 aria/cli/commands.py       |  72 +++++++++++++++++++++++++++-
 aria/cli/csar/__init__.py  |  14 ++++++
 aria/cli/csar/constants.py |  30 ++++++++++++
 aria/cli/csar/reader.py    | 101 ++++++++++++++++++++++++++++++++++++++++
 aria/cli/csar/writer.py    |  36 ++++++++++++++
 tox.ini                    |   1 +
 8 files changed, 303 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/args_parser.py
----------------------------------------------------------------------
diff --git a/aria/cli/args_parser.py b/aria/cli/args_parser.py
index 56fd074..8eacf05 100644
--- a/aria/cli/args_parser.py
+++ b/aria/cli/args_parser.py
@@ -69,6 +69,9 @@ def config_parser(parser=None):
     add_execute_parser(sub_parser)
     add_parse_parser(sub_parser)
     add_spec_parser(sub_parser)
+    add_csar_create_parser(sub_parser)
+    add_csar_open_parser(sub_parser)
+    add_csar_validate_parser(sub_parser)
     return parser
 
 
@@ -199,3 +202,44 @@ def add_spec_parser(spec):
         '--csv',
         action='store_true',
         help='output as CSV')
+
+
+@sub_parser_decorator(
+    name='csar-create',
+    help='Create a CSAR file from a TOSCA service template directory',
+    formatter_class=SmartFormatter)
+def add_csar_create_parser(parse):
+    parse.add_argument(
+        'source',
+        help='Service template directory')
+    parse.add_argument(
+        'entry',
+        help='Entry definition file relative to service template directory')
+    parse.add_argument(
+        '-d', '--destination',
+        help='Output CSAR zip destination',
+        required=True)
+
+
+@sub_parser_decorator(
+    name='csar-open',
+    help='Extracts a CSAR file to a TOSCA service template directory',
+    formatter_class=SmartFormatter)
+def add_csar_open_parser(parse):
+    parse.add_argument(
+        'source',
+        help='CSAR file location')
+    parse.add_argument(
+        '-d', '--destination',
+        help='Output directory to extract the CSAR into',
+        required=True)
+
+
+@sub_parser_decorator(
+    name='csar-validate',
+    help='Validates a CSAR file',
+    formatter_class=SmartFormatter)
+def add_csar_validate_parser(parse):
+    parse.add_argument(
+        'source',
+        help='CSAR file location')

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/cli.py
----------------------------------------------------------------------
diff --git a/aria/cli/cli.py b/aria/cli/cli.py
index ad9784c..c5830d5 100644
--- a/aria/cli/cli.py
+++ b/aria/cli/cli.py
@@ -33,6 +33,9 @@ from .commands import (
     ExecuteCommand,
     ParseCommand,
     SpecCommand,
+    CSARCreateCommand,
+    CSAROpenCommand,
+    CSARValidateCommand,
 )
 
 __version__ = '0.1.0'
@@ -50,6 +53,9 @@ class AriaCli(LoggerMixin):
             'execute': ExecuteCommand.with_logger(base_logger=self.logger),
             'parse': ParseCommand.with_logger(base_logger=self.logger),
             'spec': SpecCommand.with_logger(base_logger=self.logger),
+            'csar-create': CSARCreateCommand.with_logger(base_logger=self.logger),
+            'csar-open': CSAROpenCommand.with_logger(base_logger=self.logger),
+            'csar-validate': CSARValidateCommand.with_logger(base_logger=self.logger),
         }
 
     def __enter__(self):

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/commands.py
----------------------------------------------------------------------
diff --git a/aria/cli/commands.py b/aria/cli/commands.py
index 57118a7..32f2e0f 100644
--- a/aria/cli/commands.py
+++ b/aria/cli/commands.py
@@ -21,6 +21,8 @@ import json
 import os
 import sys
 import csv
+import shutil
+import tempfile
 from glob import glob
 from importlib import import_module
 
@@ -43,7 +45,7 @@ from ..parser.consumption import (
     Inputs,
     Instance
 )
-from ..parser.loading import (UriLocation, URI_LOADER_PREFIXES)
+from ..parser.loading import (LiteralLocation, UriLocation, URI_LOADER_PREFIXES)
 from ..utils.application import StorageManager
 from ..utils.caching import cachedmethod
 from ..utils.console import (puts, Colored, indent)
@@ -61,6 +63,8 @@ from .storage import (
     user_space,
     local_storage,
 )
+from .csar import writer
+from .csar.reader import CSARReader
 
 
 class BaseCommand(LoggerMixin):
@@ -388,3 +392,69 @@ class SpecCommand(BaseCommand):
                         with indent(2):
                             for k, v in details.iteritems():
                                 puts('%s: %s' % (Colored.magenta(k), v))
+
+
+class BaseCSARCommand(BaseCommand):
+
+    @staticmethod
+    def _parse_and_dump(reader):
+        context = ConsumptionContext()
+        context.loading.prefixes += [os.path.join(reader.destination, 'definitions')]
+        context.presentation.location = LiteralLocation(reader.entry_definitions_yaml)
+        chain = ConsumerChain(context, (Read, Validate, Model, Instance))
+        chain.consume()
+        if context.validation.dump_issues():
+            raise RuntimeError('Validation failed')
+        dumper = chain.consumers[-1]
+        dumper.dump()
+
+    def _read(self, source, destination):
+        reader = CSARReader(
+            source=source,
+            destination=destination,
+            logger=self.logger)
+        self.logger.info(
+            'Path: {r.destination}\n'
+            'TOSCA meta file version: {r.meta_file_version}\n'
+            'CSAR Version: {r.csar_version}\n'
+            'Created By: {r.created_by}\n'
+            'Entry definitions: {r.entry_definitions}'
+            .format(r=reader))
+        self._parse_and_dump(reader)
+
+    def _validate(self, source):
+        workdir = tempfile.mkdtemp()
+        try:
+            self._read(
+                source=source,
+                destination=workdir)
+        finally:
+            shutil.rmtree(workdir, ignore_errors=True)
+
+
+class CSARCreateCommand(BaseCSARCommand):
+
+    def __call__(self, args_namespace, unknown_args):
+        super(CSARCreateCommand, self).__call__(args_namespace, unknown_args)
+        writer.write(
+            source=args_namespace.source,
+            entry=args_namespace.entry,
+            destination=args_namespace.destination,
+            logger=self.logger)
+        self._validate(args_namespace.destination)
+
+
+class CSAROpenCommand(BaseCSARCommand):
+
+    def __call__(self, args_namespace, unknown_args):
+        super(CSAROpenCommand, self).__call__(args_namespace, unknown_args)
+        self._read(
+            source=args_namespace.source,
+            destination=args_namespace.destination)
+
+
+class CSARValidateCommand(BaseCSARCommand):
+
+    def __call__(self, args_namespace, unknown_args):
+        super(CSARValidateCommand, self).__call__(args_namespace, unknown_args)
+        self._validate(args_namespace.source)

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/csar/__init__.py
----------------------------------------------------------------------
diff --git a/aria/cli/csar/__init__.py b/aria/cli/csar/__init__.py
new file mode 100644
index 0000000..ae1e83e
--- /dev/null
+++ b/aria/cli/csar/__init__.py
@@ -0,0 +1,14 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/csar/constants.py
----------------------------------------------------------------------
diff --git a/aria/cli/csar/constants.py b/aria/cli/csar/constants.py
new file mode 100644
index 0000000..904ca8a
--- /dev/null
+++ b/aria/cli/csar/constants.py
@@ -0,0 +1,30 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+META_FILE = 'TOSCA-Metadata/TOSCA.meta'
+
+META_FILE_VERSION_KEY = 'TOSCA-Meta-File-Version'
+META_FILE_VERSION_VALUE = '1.0'
+META_CSAR_VERSION_KEY = 'CSAR-Version'
+META_CSAR_VERSION_VALUE = '1.1'
+META_CREATED_BY_KEY = 'Created-By'
+META_CREATED_BY_VALUE = 'ARIA'
+META_ENTRY_DEFINITIONS_KEY = 'Entry-Definitions'
+
+BASE_METADATA = {
+    META_FILE_VERSION_KEY: META_FILE_VERSION_VALUE,
+    META_CSAR_VERSION_KEY: META_CSAR_VERSION_VALUE,
+    META_CREATED_BY_KEY: META_CREATED_BY_VALUE,
+}

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/csar/reader.py
----------------------------------------------------------------------
diff --git a/aria/cli/csar/reader.py b/aria/cli/csar/reader.py
new file mode 100644
index 0000000..2847216
--- /dev/null
+++ b/aria/cli/csar/reader.py
@@ -0,0 +1,101 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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 base64
+import os
+import mimetypes
+import hashlib
+import glob
+import pprint
+import zipfile
+import functools
+
+from ruamel import yaml
+
+from . import constants
+
+
+class CSARReader(object):
+
+    def __init__(self, source, destination, logger):
+        self.log = logger
+        self.source = os.path.normpath(source)
+        self.destination = destination
+        self.metadata = {}
+        self._extract()
+        self._read_metadata_file()
+        self._validate()
+
+    @property
+    def created_by(self):
+        return self.metadata.get(constants.META_CREATED_BY_KEY)
+
+    @property
+    def csar_version(self):
+        return self.metadata.get(constants.META_CSAR_VERSION_KEY)
+
+    @property
+    def meta_file_version(self):
+        return self.metadata.get(constants.META_FILE_VERSION_KEY)
+
+    @property
+    def entry_definitions(self):
+        return self.metadata.get(constants.META_ENTRY_DEFINITIONS_KEY)
+
+    @property
+    def entry_definitions_yaml(self):
+        with open(os.path.join(self.destination, self.entry_definitions)) as f:
+            return yaml.load(f)
+
+    def _extract(self):
+        if not self.source:
+            raise RuntimeError('Missing CSAR file')
+        if not zipfile.is_zipfile(self.source):
+            raise RuntimeError('CSAR file is not in ZIP format')
+        self.log.debug('Extracting CSAR contents')
+        if not os.path.isdir(self.destination):
+            os.mkdir(self.destination)
+        with zipfile.ZipFile(self.source) as f:
+            f.extractall(self.destination)
+        self.log.debug('CSAR contents successfully extracted')
+
+    def _read_metadata_file(self):
+        csar_metafile = os.path.join(self.destination, constants.META_FILE)
+        self.log.debug('CSAR metadata file: {0}'.format(csar_metafile))
+        self.log.debug('Attempting to parse CSAR metadata YAML')
+        with open(csar_metafile) as f:
+            self.metadata.update(yaml.load(f))
+        self.log.debug('CSAR metadata:\n{0}'.format(pprint.pformat(self.metadata)))
+
+    def _validate(self):
+        self._validate_metadata()
+        self._validate_entry_definitions()
+
+    def _validate_metadata(self):
+        def validate_key(key, expected=None):
+            if not self.metadata.get(key):
+                raise RuntimeError('Missing metadata "{0}"'.format(key))
+            if expected and str(self.metadata[key]) != expected:
+                raise RuntimeError('Metadata "{0}" must be {1}'.format(key, expected))
+        validate_key(constants.META_FILE_VERSION_KEY, expected=constants.META_FILE_VERSION_VALUE)
+        validate_key(constants.META_CSAR_VERSION_KEY, expected=constants.META_CSAR_VERSION_VALUE)
+        validate_key(constants.META_CREATED_BY_KEY)
+        validate_key(constants.META_ENTRY_DEFINITIONS_KEY)
+
+    def _validate_entry_definitions(self):
+        self.log.debug('CSAR entry definitions: {0}'.format(self.entry_definitions))
+        if not os.path.isfile(os.path.join(self.destination, self.entry_definitions)):
+            raise RuntimeError('"{0}" points to "{1}", but the file does not exist'.format(
+                constants.META_ENTRY_DEFINITIONS_KEY, self.entry_definitions))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/aria/cli/csar/writer.py
----------------------------------------------------------------------
diff --git a/aria/cli/csar/writer.py b/aria/cli/csar/writer.py
new file mode 100644
index 0000000..79c6502
--- /dev/null
+++ b/aria/cli/csar/writer.py
@@ -0,0 +1,36 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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 zipfile
+
+from ruamel import yaml
+
+from . import constants
+
+
+def write(source, entry, destination, logger):
+    metadata = constants.BASE_METADATA.copy()
+    metadata[constants.META_ENTRY_DEFINITIONS_KEY] = entry
+    logger.debug('Compressing root directory to ZIP')
+    with zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) as f:
+        for root, _, files in os.walk(source):
+            for file in files:
+                file_full_path = os.path.join(root, file)
+                file_relative_path = os.path.relpath(file_full_path, source)
+                logger.debug('Writing to archive: {0}'.format(file_relative_path))
+                f.write(file_full_path, file_relative_path)
+        logger.debug('Writing new metadata file to {0}'.format(constants.META_FILE))
+        f.writestr(constants.META_FILE, yaml.dump(metadata, default_flow_style=False))

http://git-wip-us.apache.org/repos/asf/incubator-ariatosca/blob/eea536de/tox.ini
----------------------------------------------------------------------
diff --git a/tox.ini b/tox.ini
index 2efc329..8355b19 100644
--- a/tox.ini
+++ b/tox.ini
@@ -34,3 +34,4 @@ commands=pylint --rcfile=aria/.pylintrc --disable=fixme,missing-docstring
--igno
 
 [testenv:pylint_tests]
 commands=pylint --rcfile=tests/.pylintrc --disable=fixme,missing-docstring tests
+


Mime
View raw message