-#!/usr/bin/env python\r
-\r
-#\r
-# Copyright (c) 2016-2017 GigaSpaces Technologies Ltd. All rights reserved.\r
-#\r
-# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
-# not use this file except in compliance with the License. You may obtain\r
-# a copy of the License at\r
-#\r
-# http://www.apache.org/licenses/LICENSE-2.0\r
-#\r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
-# License for the specific language governing permissions and limitations\r
-# under the License.\r
-#\r
-\r
-import os\r
-from setuptools import setup\r
-import sys\r
-\r
-if sys.version_info < (2, 7):\r
- sys.exit('VNF SDK requires Python 2.7+')\r
-if sys.version_info >= (3, 0):\r
- sys.exit('VNF SDK does not support Python 3')\r
-\r
-\r
-root_dir = os.path.dirname(__file__)\r
-install_requires = []\r
-extras_require = {}\r
-\r
-with open(os.path.join(root_dir, 'requirements.txt')) as requirements:\r
- for requirement in requirements.readlines():\r
- # get rid of comments or trailing comments\r
- requirement = requirement.split('#')[0].strip()\r
- if not requirement:\r
- continue # skip empty and comment lines\r
- # dependencies which use environment markers have to go in as\r
- # conditional dependencies under "extra_require", see more at:\r
- # https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies\r
- if ';' in requirement:\r
- package, condition = requirement.split(';')\r
- cond_name = ':{0}'.format(condition.strip())\r
- extras_require.setdefault(cond_name, [])\r
- extras_require[cond_name].append(package.strip())\r
- else:\r
- install_requires.append(requirement)\r
-\r
-setup(\r
- name='vnfsdk',\r
- version='0.1',\r
- description='VNF SDK CSAR package tool',\r
- license='Apache License Version 2.0',\r
-\r
- author='GigaSpaces',\r
- author_email='info@gigaspaces.com',\r
-\r
- url='http://onap.org/',\r
-\r
- classifiers=[\r
- 'Development Status :: 4 - Beta',\r
- 'Environment :: Console',\r
- 'Environment :: Web Environment',\r
- 'Intended Audience :: Developers',\r
- 'Intended Audience :: System Administrators',\r
- 'License :: OSI Approved :: Apache Software License',\r
- 'Operating System :: OS Independent',\r
- 'Programming Language :: Python',\r
- 'Topic :: Software Development :: Libraries :: Python Modules',\r
- 'Topic :: System :: Networking',\r
- 'Topic :: System :: Systems Administration'],\r
-\r
- packages=[\r
- 'packager',\r
- 'cli',\r
- 'validator'\r
- ],\r
-\r
- package_dir={\r
- 'packager': 'packager',\r
- 'cli': 'cli',\r
- 'validator': 'validator'\r
- },\r
-\r
- entry_points={\r
- 'console_scripts': [\r
- 'vnfsdk = cli.__main__:main'],\r
- 'vnfsdk.validator': [\r
- 'aria = validator.aria_validator:AriaValidator'\r
- ]\r
- },\r
-\r
- include_package_data=True,\r
- install_requires=install_requires,\r
- extras_require=extras_require)\r
-\r
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2016-2017 GigaSpaces Technologies Ltd. All rights reserved.
+#
+# 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
+from setuptools import find_packages, setup
+import sys
+
+if sys.version_info < (2, 7):
+ sys.exit('VNF SDK requires Python 2.7+')
+if sys.version_info >= (3, 0):
+ sys.exit('VNF SDK does not support Python 3')
+
+
+root_dir = os.path.dirname(__file__)
+install_requires = []
+extras_require = {}
+
+with open(os.path.join(root_dir, 'requirements.txt')) as requirements:
+ for requirement in requirements.readlines():
+ # get rid of comments or trailing comments
+ requirement = requirement.split('#')[0].strip()
+ if not requirement:
+ continue # skip empty and comment lines
+ # dependencies which use environment markers have to go in as
+ # conditional dependencies under "extra_require", see more at:
+ # https://wheel.readthedocs.io/en/latest/index.html#defining-conditional-dependencies
+ if ';' in requirement:
+ package, condition = requirement.split(';')
+ cond_name = ':{0}'.format(condition.strip())
+ extras_require.setdefault(cond_name, [])
+ extras_require[cond_name].append(package.strip())
+ else:
+ install_requires.append(requirement)
+
+version = { }
+with open(os.path.join(root_dir, 'vnfsdk_pkgtools/version.py')) as fp:
+ exec(fp.read(), version)
+
+setup(
+ name='vnfsdk',
+ version=version['__version__'],
+ description='VNFSDK CSAR package tool',
+ long_description="VNFSDK CSAR package tool in ONAP",
+ license='Apache License Version 2.0',
+
+ author='ONAP',
+
+ url='https://git.onap.org/vnfsdk/pkgtools',
+
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Environment :: Console',
+ 'Environment :: Web Environment',
+ 'Intended Audience :: Developers',
+ 'Intended Audience :: System Administrators',
+ 'License :: OSI Approved :: Apache Software License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2',
+ 'Programming Language :: Python :: 2.7',
+ 'Topic :: Software Development :: Libraries :: Python Modules',
+ 'Topic :: System :: Networking',
+ 'Topic :: System :: Systems Administration'],
+
+ packages=find_packages(exclude=['tests*']),
+
+ entry_points={
+ 'console_scripts': [
+ 'vnfsdk = vnfsdk_pkgtools.cli.__main__:main'],
+ 'vnfsdk.pkgtools.validator': [
+ 'aria = vnfsdk_pkgtools.validator.aria_validator:AriaValidator'
+ ]
+ },
+
+ include_package_data=True,
+ install_requires=install_requires,
+ extras_require=extras_require)
+
-#\r
-# Copyright (c) 2016-2017 GigaSpaces Technologies Ltd. All rights reserved.\r
-#\r
-# Licensed under the Apache License, Version 2.0 (the "License"); you may\r
-# not use this file except in compliance with the License. You may obtain\r
-# a copy of the License at\r
-#\r
-# http://www.apache.org/licenses/LICENSE-2.0\r
-#\r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT\r
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\r
-# License for the specific language governing permissions and limitations\r
-# under the License.\r
-#\r
-\r
-from packager import csar\r
-import sys\r
-import logging\r
-import argparse\r
-from aria import install_aria_extensions\r
-import os\r
-import shutil\r
-import tempfile\r
-\r
-import validator\r
-\r
-def csar_create_func(namespace):\r
- csar.write(namespace.source,\r
- namespace.entry,\r
- namespace.destination,\r
- logging,\r
- args=namespace)\r
-def csar_open_func(namespace):\r
- csar.read(namespace.source,\r
- namespace.destination,\r
- logging)\r
-def csar_validate_func(namespace):\r
- workdir = tempfile.mkdtemp()\r
- try:\r
- reader = None\r
- reader = csar.read(namespace.source,\r
- workdir,\r
- logging)\r
-\r
- driver = validator.get_validator(namespace.parser)\r
- driver.validate(reader)\r
- finally:\r
- shutil.rmtree(workdir, ignore_errors=True)\r
-\r
-\r
-def parse_args(args_list):\r
- """\r
- CLI entry point\r
- """\r
- install_aria_extensions()\r
-\r
- parser = argparse.ArgumentParser(description='VNF SDK CSAR manipulation tool')\r
-\r
- subparsers = parser.add_subparsers(help='csar-create')\r
- csar_create = subparsers.add_parser('csar-create')\r
- csar_create.set_defaults(func=csar_create_func)\r
- csar_create.add_argument('-v', '--verbose',\r
- dest='verbosity',\r
- action='count',\r
- default=0,\r
- help='Set verbosity level (can be passed multiple times)')\r
- csar_create.add_argument(\r
- 'source',\r
- help='Service template directory')\r
- csar_create.add_argument(\r
- 'entry',\r
- help='Entry definition file relative to service template directory')\r
- csar_create.add_argument(\r
- '-d', '--destination',\r
- help='Output CSAR zip destination',\r
- required=True)\r
- csar_create.add_argument(\r
- '--manifest',\r
- help='Manifest file relative to service template directory')\r
- csar_create.add_argument(\r
- '--history',\r
- help='Change history file relative to service template directory')\r
- csar_create.add_argument(\r
- '--tests',\r
- help='Directory containing test information, relative to service template directory')\r
- csar_create.add_argument(\r
- '--licenses',\r
- help='Directory containing license information, relative to service template directory')\r
-\r
-\r
- csar_open = subparsers.add_parser('csar-open')\r
- csar_open.set_defaults(func=csar_open_func)\r
- csar_open.add_argument(\r
- 'source',\r
- help='CSAR file location')\r
- csar_open.add_argument(\r
- '-d', '--destination',\r
- help='Output directory to extract the CSAR into',\r
- required=True)\r
-\r
- csar_validate = subparsers.add_parser('csar-validate')\r
- csar_validate.set_defaults(func=csar_validate_func)\r
- csar_validate.add_argument(\r
- 'source',\r
- help='CSAR file location')\r
- csar_validate.add_argument(\r
- '-p', '--parser',\r
- default='aria',\r
- help='use which csar parser to validate')\r
-\r
- return parser.parse_args(args_list)\r
-\r
-def main():\r
- args = parse_args(sys.argv[1:])\r
- args.func(args)\r
-\r
-\r
-if __name__ == '__main__':\r
- main()\r
+#
+# Copyright (c) 2016-2017 GigaSpaces Technologies Ltd. All rights reserved.
+#
+# 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.
+#
+
+from vnfsdk_pkgtools.packager import csar
+import sys
+import logging
+import argparse
+from aria import install_aria_extensions
+import os
+import shutil
+import tempfile
+
+from vnfsdk_pkgtools import validator
+
+def csar_create_func(namespace):
+ csar.write(namespace.source,
+ namespace.entry,
+ namespace.destination,
+ logging,
+ args=namespace)
+def csar_open_func(namespace):
+ csar.read(namespace.source,
+ namespace.destination,
+ logging)
+def csar_validate_func(namespace):
+ workdir = tempfile.mkdtemp()
+ try:
+ reader = None
+ reader = csar.read(namespace.source,
+ workdir,
+ logging)
+
+ driver = validator.get_validator(namespace.parser)
+ driver.validate(reader)
+ finally:
+ shutil.rmtree(workdir, ignore_errors=True)
+
+
+def parse_args(args_list):
+ """
+ CLI entry point
+ """
+ install_aria_extensions()
+
+ parser = argparse.ArgumentParser(description='VNF SDK CSAR manipulation tool')
+
+ subparsers = parser.add_subparsers(help='csar-create')
+ csar_create = subparsers.add_parser('csar-create')
+ csar_create.set_defaults(func=csar_create_func)
+ csar_create.add_argument('-v', '--verbose',
+ dest='verbosity',
+ action='count',
+ default=0,
+ help='Set verbosity level (can be passed multiple times)')
+ csar_create.add_argument(
+ 'source',
+ help='Service template directory')
+ csar_create.add_argument(
+ 'entry',
+ help='Entry definition file relative to service template directory')
+ csar_create.add_argument(
+ '-d', '--destination',
+ help='Output CSAR zip destination',
+ required=True)
+ csar_create.add_argument(
+ '--manifest',
+ help='Manifest file relative to service template directory')
+ csar_create.add_argument(
+ '--history',
+ help='Change history file relative to service template directory')
+ csar_create.add_argument(
+ '--tests',
+ help='Directory containing test information, relative to service template directory')
+ csar_create.add_argument(
+ '--licenses',
+ help='Directory containing license information, relative to service template directory')
+
+
+ csar_open = subparsers.add_parser('csar-open')
+ csar_open.set_defaults(func=csar_open_func)
+ csar_open.add_argument(
+ 'source',
+ help='CSAR file location')
+ csar_open.add_argument(
+ '-d', '--destination',
+ help='Output directory to extract the CSAR into',
+ required=True)
+
+ csar_validate = subparsers.add_parser('csar-validate')
+ csar_validate.set_defaults(func=csar_validate_func)
+ csar_validate.add_argument(
+ 'source',
+ help='CSAR file location')
+ csar_validate.add_argument(
+ '-p', '--parser',
+ default='aria',
+ help='use which csar parser to validate')
+
+ return parser.parse_args(args_list)
+
+def main():
+ args = parse_args(sys.argv[1:])
+ args.func(args)
+
+
+if __name__ == '__main__':
+ main()
-# Licensed to the Apache Software Foundation (ASF) under one or more\r
-# contributor license agreements. See the NOTICE file distributed with\r
-# this work for additional information regarding copyright ownership.\r
-# The ASF licenses this file to You under the Apache License, Version 2.0\r
-# (the "License"); you may not use this file except in compliance with\r
-# the License. You may obtain a copy of the License at\r
-#\r
-# http://www.apache.org/licenses/LICENSE-2.0\r
-#\r
-# Unless required by applicable law or agreed to in writing, software\r
-# distributed under the License is distributed on an "AS IS" BASIS,\r
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
-# See the License for the specific language governing permissions and\r
-# limitations under the License.\r
-\r
-import os\r
-import pprint\r
-import tempfile\r
-import zipfile\r
-\r
-import requests\r
-from ruamel import yaml # @UnresolvedImport\r
-\r
-\r
-META_FILE = 'TOSCA-Metadata/TOSCA.meta'\r
-META_FILE_VERSION_KEY = 'TOSCA-Meta-File-Version'\r
-META_FILE_VERSION_VALUE = '1.0'\r
-META_CSAR_VERSION_KEY = 'CSAR-Version'\r
-META_CSAR_VERSION_VALUE = '1.1'\r
-META_CREATED_BY_KEY = 'Created-By'\r
-META_CREATED_BY_VALUE = 'ONAP'\r
-META_ENTRY_DEFINITIONS_KEY = 'Entry-Definitions'\r
-META_ENTRY_MANIFEST_FILE_KEY = 'Entry-Manifest'\r
-META_ENTRY_HISTORY_FILE_KEY = 'Entry-Change-Log'\r
-META_ENTRY_TESTS_DIR_KEY = 'Entry-Tests'\r
-META_ENTRY_LICENSES_DIR_KEY = 'Entry-Licenses'\r
-\r
-BASE_METADATA = {\r
- META_FILE_VERSION_KEY: META_FILE_VERSION_VALUE,\r
- META_CSAR_VERSION_KEY: META_CSAR_VERSION_VALUE,\r
- META_CREATED_BY_KEY: META_CREATED_BY_VALUE,\r
-}\r
-\r
-\r
-def check_file_dir(root, entry, msg, check_for_non=False, check_dir=False):\r
- path = os.path.join(root, entry)\r
- if check_for_non:\r
- ret = not os.path.exists(path)\r
- error_msg = '{0} already exists. ' + msg\r
- elif check_dir:\r
- ret = os.path.isdir(path)\r
- error_msg = '{0} is not an existing directory. ' + msg\r
- else:\r
- ret = os.path.isfile(path)\r
- error_msg = '{0} is not an existing file. ' + msg\r
- if not ret:\r
- raise ValueError(error_msg.format(path))\r
-\r
-\r
-def write(source, entry, destination, logger, args):\r
- source = os.path.expanduser(source)\r
- destination = os.path.expanduser(destination)\r
- metadata = BASE_METADATA.copy()\r
-\r
- check_file_dir(root=source,\r
- entry='',\r
- msg='Please specify the service template directory.',\r
- check_dir=True)\r
-\r
- check_file_dir(root=source,\r
- entry=entry,\r
- msg='Please specify a valid entry point.',\r
- check_dir=False)\r
- metadata[META_ENTRY_DEFINITIONS_KEY] = entry\r
-\r
- check_file_dir(root='',\r
- entry=destination,\r
- msg='Please provide a path to where the CSAR should be created.',\r
- check_for_non=True)\r
-\r
- check_file_dir(root=source,\r
- entry=META_FILE,\r
- msg='This commands generates a meta file for you. Please '\r
- 'remove the existing metafile.',\r
- check_for_non=True)\r
-\r
- if(args.manifest):\r
- check_file_dir(root=source,\r
- entry=args.manifest,\r
- msg='Please specify a valid manifest file.',\r
- check_dir=False)\r
- metadata[META_ENTRY_MANIFEST_FILE_KEY] = args.manifest\r
-\r
- if(args.history):\r
- check_file_dir(root=source,\r
- entry=args.history,\r
- msg='Please specify a valid change history file.',\r
- check_dir=False)\r
- metadata[META_ENTRY_HISTORY_FILE_KEY] = args.history\r
-\r
- if(args.tests):\r
- check_file_dir(root=source,\r
- entry=args.tests,\r
- msg='Please specify a valid test directory.',\r
- check_dir=True)\r
- metadata[META_ENTRY_TESTS_DIR_KEY] = args.tests\r
-\r
- if(args.licenses):\r
- check_file_dir(root=source,\r
- entry=args.licenses,\r
- msg='Please specify a valid license directory.',\r
- check_dir=True)\r
- metadata[META_ENTRY_LICENSES_DIR_KEY] = args.licenses\r
-\r
- logger.debug('Compressing root directory to ZIP')\r
- with zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) as f:\r
- for root, dirs, files in os.walk(source):\r
- for file in files:\r
- file_full_path = os.path.join(root, file)\r
- file_relative_path = os.path.relpath(file_full_path, source)\r
- logger.debug('Writing to archive: {0}'.format(file_relative_path))\r
- f.write(file_full_path, file_relative_path)\r
- # add empty dir\r
- for dir in dirs:\r
- dir_full_path = os.path.join(root, dir)\r
- if len(os.listdir(dir_full_path)) == 0:\r
- dir_relative_path = os.path.relpath(dir_full_path, source) + os.sep\r
- logger.debug('Writing to archive: {0}'.format(dir_relative_path))\r
- f.write(dir_full_path + os.sep, dir_relative_path)\r
-\r
- logger.debug('Writing new metadata file to {0}'.format(META_FILE))\r
- f.writestr(META_FILE, yaml.dump(metadata, default_flow_style=False))\r
-\r
-\r
-class _CSARReader(object):\r
-\r
- def __init__(self, source, destination, logger):\r
- self.logger = logger\r
- if os.path.isdir(destination) and os.listdir(destination):\r
- raise ValueError('{0} already exists and is not empty. '\r
- 'Please specify the location where the CSAR '\r
- 'should be extracted.'.format(destination))\r
- downloaded_csar = '://' in source\r
- if downloaded_csar:\r
- file_descriptor, download_target = tempfile.mkstemp()\r
- os.close(file_descriptor)\r
- self._download(source, download_target)\r
- source = download_target\r
- self.source = os.path.expanduser(source)\r
- self.destination = os.path.expanduser(destination)\r
- self.metadata = {}\r
- try:\r
- if not os.path.exists(self.source):\r
- raise ValueError('{0} does not exists. Please specify a valid CSAR path.'\r
- .format(self.source))\r
- if not zipfile.is_zipfile(self.source):\r
- raise ValueError('{0} is not a valid CSAR.'.format(self.source))\r
- self._extract()\r
- self._read_metadata()\r
- self._validate()\r
- finally:\r
- if downloaded_csar:\r
- os.remove(self.source)\r
-\r
- @property\r
- def created_by(self):\r
- return self.metadata.get(META_CREATED_BY_KEY)\r
-\r
- @property\r
- def csar_version(self):\r
- return self.metadata.get(META_CSAR_VERSION_KEY)\r
-\r
- @property\r
- def meta_file_version(self):\r
- return self.metadata.get(META_FILE_VERSION_KEY)\r
-\r
- @property\r
- def entry_definitions(self):\r
- return self.metadata.get(META_ENTRY_DEFINITIONS_KEY)\r
-\r
- @property\r
- def entry_definitions_yaml(self):\r
- with open(os.path.join(self.destination, self.entry_definitions)) as f:\r
- return yaml.load(f)\r
-\r
- @property\r
- def entry_manifest_file(self):\r
- return self.metadata.get(META_ENTRY_MANIFEST_FILE_KEY)\r
-\r
- @property\r
- def entry_history_file(self):\r
- return self.metadata.get(META_ENTRY_HISTORY_FILE_KEY)\r
-\r
- @property\r
- def entry_tests_dir(self):\r
- return self.metadata.get(META_ENTRY_TESTS_DIR_KEY)\r
-\r
- @property\r
- def entry_licenses_dir(self):\r
- return self.metadata.get(META_ENTRY_LICENSES_DIR_KEY)\r
-\r
- def _extract(self):\r
- self.logger.debug('Extracting CSAR contents')\r
- if not os.path.exists(self.destination):\r
- os.mkdir(self.destination)\r
- with zipfile.ZipFile(self.source) as f:\r
- f.extractall(self.destination)\r
- self.logger.debug('CSAR contents successfully extracted')\r
-\r
- def _read_metadata(self):\r
- csar_metafile = os.path.join(self.destination, META_FILE)\r
- if not os.path.exists(csar_metafile):\r
- raise ValueError('Metadata file {0} is missing from the CSAR'.format(csar_metafile))\r
- self.logger.debug('CSAR metadata file: {0}'.format(csar_metafile))\r
- self.logger.debug('Attempting to parse CSAR metadata YAML')\r
- with open(csar_metafile) as f:\r
- self.metadata.update(yaml.load(f))\r
- self.logger.debug('CSAR metadata:\n{0}'.format(pprint.pformat(self.metadata)))\r
-\r
- def _validate(self):\r
- def validate_key(key, expected=None):\r
- if not self.metadata.get(key):\r
- raise ValueError('{0} is missing from the metadata file.'.format(key))\r
- actual = str(self.metadata[key])\r
- if expected and actual != expected:\r
- raise ValueError('{0} is expected to be {1} in the metadata file while it is in '\r
- 'fact {2}.'.format(key, expected, actual))\r
- validate_key(META_FILE_VERSION_KEY, expected=META_FILE_VERSION_VALUE)\r
- validate_key(META_CSAR_VERSION_KEY, expected=META_CSAR_VERSION_VALUE)\r
- validate_key(META_CREATED_BY_KEY)\r
- validate_key(META_ENTRY_DEFINITIONS_KEY)\r
- self.logger.debug('CSAR entry definitions: {0}'.format(self.entry_definitions))\r
- self.logger.debug('CSAR manifest file: {0}'.format(self.entry_manifest_file))\r
- self.logger.debug('CSAR change history file: {0}'.format(self.entry_history_file))\r
- self.logger.debug('CSAR tests directory: {0}'.format(self.entry_tests_dir))\r
- self.logger.debug('CSAR licenses directory: {0}'.format(self.entry_licenses_dir))\r
-\r
- check_file_dir(self.destination,\r
- self.entry_definitions,\r
- 'The entry definitions {0} referenced by the metadata '\r
- 'file does not exist.'.format(self.entry_definitions),\r
- check_dir=False)\r
-\r
- if(self.entry_manifest_file):\r
- check_file_dir(self.destination,\r
- self.entry_manifest_file,\r
- 'The manifest file {0} referenced by the metadata '\r
- 'file does not exist.'.format(self.entry_manifest_file),\r
- check_dir=False)\r
-\r
- if(self.entry_history_file):\r
- check_file_dir(self.destination,\r
- self.entry_history_file,\r
- 'The change history file {0} referenced by the metadata '\r
- 'file does not exist.'.format(self.entry_history_file),\r
- check_dir=False)\r
-\r
- if(self.entry_tests_dir):\r
- check_file_dir(self.destination,\r
- self.entry_tests_dir,\r
- 'The test directory {0} referenced by the metadata '\r
- 'file does not exist.'.format(self.entry_tests_dir),\r
- check_dir=True)\r
-\r
- if(self.entry_licenses_dir):\r
- check_file_dir(self.destination,\r
- self.entry_licenses_dir,\r
- 'The license directory {0} referenced by the metadata '\r
- 'file does not exist.'.format(self.entry_licenses_dir),\r
- check_dir=True)\r
-\r
- def _download(self, url, target):\r
- response = requests.get(url, stream=True)\r
- if response.status_code != 200:\r
- raise ValueError('Server at {0} returned a {1} status code'\r
- .format(url, response.status_code))\r
- self.logger.info('Downloading {0} to {1}'.format(url, target))\r
- with open(target, 'wb') as f:\r
- for chunk in response.iter_content(chunk_size=8192):\r
- if chunk:\r
- f.write(chunk)\r
-\r
-\r
-def read(source, destination, logger):\r
- return _CSARReader(source=source, destination=destination, logger=logger)\r
+# 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 pprint
+import tempfile
+import zipfile
+
+import requests
+from ruamel import yaml # @UnresolvedImport
+
+
+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 = 'ONAP'
+META_ENTRY_DEFINITIONS_KEY = 'Entry-Definitions'
+META_ENTRY_MANIFEST_FILE_KEY = 'Entry-Manifest'
+META_ENTRY_HISTORY_FILE_KEY = 'Entry-Change-Log'
+META_ENTRY_TESTS_DIR_KEY = 'Entry-Tests'
+META_ENTRY_LICENSES_DIR_KEY = 'Entry-Licenses'
+
+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,
+}
+
+
+def check_file_dir(root, entry, msg, check_for_non=False, check_dir=False):
+ path = os.path.join(root, entry)
+ if check_for_non:
+ ret = not os.path.exists(path)
+ error_msg = '{0} already exists. ' + msg
+ elif check_dir:
+ ret = os.path.isdir(path)
+ error_msg = '{0} is not an existing directory. ' + msg
+ else:
+ ret = os.path.isfile(path)
+ error_msg = '{0} is not an existing file. ' + msg
+ if not ret:
+ raise ValueError(error_msg.format(path))
+
+
+def write(source, entry, destination, logger, args):
+ source = os.path.expanduser(source)
+ destination = os.path.expanduser(destination)
+ metadata = BASE_METADATA.copy()
+
+ check_file_dir(root=source,
+ entry='',
+ msg='Please specify the service template directory.',
+ check_dir=True)
+
+ check_file_dir(root=source,
+ entry=entry,
+ msg='Please specify a valid entry point.',
+ check_dir=False)
+ metadata[META_ENTRY_DEFINITIONS_KEY] = entry
+
+ check_file_dir(root='',
+ entry=destination,
+ msg='Please provide a path to where the CSAR should be created.',
+ check_for_non=True)
+
+ check_file_dir(root=source,
+ entry=META_FILE,
+ msg='This commands generates a meta file for you. Please '
+ 'remove the existing metafile.',
+ check_for_non=True)
+
+ if(args.manifest):
+ check_file_dir(root=source,
+ entry=args.manifest,
+ msg='Please specify a valid manifest file.',
+ check_dir=False)
+ metadata[META_ENTRY_MANIFEST_FILE_KEY] = args.manifest
+
+ if(args.history):
+ check_file_dir(root=source,
+ entry=args.history,
+ msg='Please specify a valid change history file.',
+ check_dir=False)
+ metadata[META_ENTRY_HISTORY_FILE_KEY] = args.history
+
+ if(args.tests):
+ check_file_dir(root=source,
+ entry=args.tests,
+ msg='Please specify a valid test directory.',
+ check_dir=True)
+ metadata[META_ENTRY_TESTS_DIR_KEY] = args.tests
+
+ if(args.licenses):
+ check_file_dir(root=source,
+ entry=args.licenses,
+ msg='Please specify a valid license directory.',
+ check_dir=True)
+ metadata[META_ENTRY_LICENSES_DIR_KEY] = args.licenses
+
+ logger.debug('Compressing root directory to ZIP')
+ with zipfile.ZipFile(destination, 'w', zipfile.ZIP_DEFLATED) as f:
+ for root, dirs, 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)
+ # add empty dir
+ for dir in dirs:
+ dir_full_path = os.path.join(root, dir)
+ if len(os.listdir(dir_full_path)) == 0:
+ dir_relative_path = os.path.relpath(dir_full_path, source) + os.sep
+ logger.debug('Writing to archive: {0}'.format(dir_relative_path))
+ f.write(dir_full_path + os.sep, dir_relative_path)
+
+ logger.debug('Writing new metadata file to {0}'.format(META_FILE))
+ f.writestr(META_FILE, yaml.dump(metadata, default_flow_style=False))
+
+
+class _CSARReader(object):
+
+ def __init__(self, source, destination, logger):
+ self.logger = logger
+ if os.path.isdir(destination) and os.listdir(destination):
+ raise ValueError('{0} already exists and is not empty. '
+ 'Please specify the location where the CSAR '
+ 'should be extracted.'.format(destination))
+ downloaded_csar = '://' in source
+ if downloaded_csar:
+ file_descriptor, download_target = tempfile.mkstemp()
+ os.close(file_descriptor)
+ self._download(source, download_target)
+ source = download_target
+ self.source = os.path.expanduser(source)
+ self.destination = os.path.expanduser(destination)
+ self.metadata = {}
+ try:
+ if not os.path.exists(self.source):
+ raise ValueError('{0} does not exists. Please specify a valid CSAR path.'
+ .format(self.source))
+ if not zipfile.is_zipfile(self.source):
+ raise ValueError('{0} is not a valid CSAR.'.format(self.source))
+ self._extract()
+ self._read_metadata()
+ self._validate()
+ finally:
+ if downloaded_csar:
+ os.remove(self.source)
+
+ @property
+ def created_by(self):
+ return self.metadata.get(META_CREATED_BY_KEY)
+
+ @property
+ def csar_version(self):
+ return self.metadata.get(META_CSAR_VERSION_KEY)
+
+ @property
+ def meta_file_version(self):
+ return self.metadata.get(META_FILE_VERSION_KEY)
+
+ @property
+ def entry_definitions(self):
+ return self.metadata.get(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)
+
+ @property
+ def entry_manifest_file(self):
+ return self.metadata.get(META_ENTRY_MANIFEST_FILE_KEY)
+
+ @property
+ def entry_history_file(self):
+ return self.metadata.get(META_ENTRY_HISTORY_FILE_KEY)
+
+ @property
+ def entry_tests_dir(self):
+ return self.metadata.get(META_ENTRY_TESTS_DIR_KEY)
+
+ @property
+ def entry_licenses_dir(self):
+ return self.metadata.get(META_ENTRY_LICENSES_DIR_KEY)
+
+ def _extract(self):
+ self.logger.debug('Extracting CSAR contents')
+ if not os.path.exists(self.destination):
+ os.mkdir(self.destination)
+ with zipfile.ZipFile(self.source) as f:
+ f.extractall(self.destination)
+ self.logger.debug('CSAR contents successfully extracted')
+
+ def _read_metadata(self):
+ csar_metafile = os.path.join(self.destination, META_FILE)
+ if not os.path.exists(csar_metafile):
+ raise ValueError('Metadata file {0} is missing from the CSAR'.format(csar_metafile))
+ self.logger.debug('CSAR metadata file: {0}'.format(csar_metafile))
+ self.logger.debug('Attempting to parse CSAR metadata YAML')
+ with open(csar_metafile) as f:
+ self.metadata.update(yaml.load(f))
+ self.logger.debug('CSAR metadata:\n{0}'.format(pprint.pformat(self.metadata)))
+
+ def _validate(self):
+ def validate_key(key, expected=None):
+ if not self.metadata.get(key):
+ raise ValueError('{0} is missing from the metadata file.'.format(key))
+ actual = str(self.metadata[key])
+ if expected and actual != expected:
+ raise ValueError('{0} is expected to be {1} in the metadata file while it is in '
+ 'fact {2}.'.format(key, expected, actual))
+ validate_key(META_FILE_VERSION_KEY, expected=META_FILE_VERSION_VALUE)
+ validate_key(META_CSAR_VERSION_KEY, expected=META_CSAR_VERSION_VALUE)
+ validate_key(META_CREATED_BY_KEY)
+ validate_key(META_ENTRY_DEFINITIONS_KEY)
+ self.logger.debug('CSAR entry definitions: {0}'.format(self.entry_definitions))
+ self.logger.debug('CSAR manifest file: {0}'.format(self.entry_manifest_file))
+ self.logger.debug('CSAR change history file: {0}'.format(self.entry_history_file))
+ self.logger.debug('CSAR tests directory: {0}'.format(self.entry_tests_dir))
+ self.logger.debug('CSAR licenses directory: {0}'.format(self.entry_licenses_dir))
+
+ check_file_dir(self.destination,
+ self.entry_definitions,
+ 'The entry definitions {0} referenced by the metadata '
+ 'file does not exist.'.format(self.entry_definitions),
+ check_dir=False)
+
+ if(self.entry_manifest_file):
+ check_file_dir(self.destination,
+ self.entry_manifest_file,
+ 'The manifest file {0} referenced by the metadata '
+ 'file does not exist.'.format(self.entry_manifest_file),
+ check_dir=False)
+
+ if(self.entry_history_file):
+ check_file_dir(self.destination,
+ self.entry_history_file,
+ 'The change history file {0} referenced by the metadata '
+ 'file does not exist.'.format(self.entry_history_file),
+ check_dir=False)
+
+ if(self.entry_tests_dir):
+ check_file_dir(self.destination,
+ self.entry_tests_dir,
+ 'The test directory {0} referenced by the metadata '
+ 'file does not exist.'.format(self.entry_tests_dir),
+ check_dir=True)
+
+ if(self.entry_licenses_dir):
+ check_file_dir(self.destination,
+ self.entry_licenses_dir,
+ 'The license directory {0} referenced by the metadata '
+ 'file does not exist.'.format(self.entry_licenses_dir),
+ check_dir=True)
+
+ def _download(self, url, target):
+ response = requests.get(url, stream=True)
+ if response.status_code != 200:
+ raise ValueError('Server at {0} returned a {1} status code'
+ .format(url, response.status_code))
+ self.logger.info('Downloading {0} to {1}'.format(url, target))
+ with open(target, 'wb') as f:
+ for chunk in response.iter_content(chunk_size=8192):
+ if chunk:
+ f.write(chunk)
+
+
+def read(source, destination, logger):
+ return _CSARReader(source=source, destination=destination, logger=logger)