# Copyright (c) 2019 Intel Corp. All rights reserved. # # 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 logging import os import pprint from ruamel import yaml # @UnresolvedImport import six from vnfsdk_pkgtools.packager import utils LOG = logging.getLogger(__name__) 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 VNFSDK pkgtools' META_ENTRY_DEFINITIONS_KEY = 'Entry-Definitions' BASE_META = { META_FILE_VERSION_KEY: META_FILE_VERSION_VALUE, META_CSAR_VERSION_KEY: META_CSAR_VERSION_VALUE, } class ToscaMeta(object): META_ENTRY_MANIFEST_FILE_KEY = 'ETSI-Entry-Manifest' META_ENTRY_HISTORY_FILE_KEY = 'ETSI-Entry-Change-Log' META_ENTRY_TESTS_DIR_KEY = 'ETSI-Entry-Tests' META_ENTRY_LICENSES_DIR_KEY = 'ETSI-Entry-Licenses' META_ENTRY_CERT_FILE_KEY = 'ETSI-Entry-Certificate' REQUIRED_KEYS = [ META_FILE_VERSION_KEY, META_CSAR_VERSION_KEY, META_CREATED_BY_KEY, META_ENTRY_DEFINITIONS_KEY, META_ENTRY_MANIFEST_FILE_KEY, META_ENTRY_HISTORY_FILE_KEY, META_ENTRY_LICENSES_DIR_KEY, ] OPTIONAL_KEYS = [META_ENTRY_TESTS_DIR_KEY, META_ENTRY_CERT_FILE_KEY] def __init__(self, base_dir, entry, manifest=None, changelog=None, licenses=None, tests=None, certificate=None, meta_file_version=META_FILE_VERSION_VALUE, meta_csar_version=META_CSAR_VERSION_VALUE, meta_created_by=META_CREATED_BY_VALUE): self.base_dir = base_dir metadata = {} metadata[META_FILE_VERSION_KEY] = str(meta_file_version) metadata[META_CSAR_VERSION_KEY] = str(meta_csar_version) metadata[META_CREATED_BY_KEY] = meta_created_by metadata[META_ENTRY_DEFINITIONS_KEY] = entry if manifest: metadata[self.META_ENTRY_MANIFEST_FILE_KEY] = manifest if changelog: metadata[self.META_ENTRY_HISTORY_FILE_KEY] = changelog if licenses: metadata[self.META_ENTRY_LICENSES_DIR_KEY] = licenses if tests: metadata[self.META_ENTRY_TESTS_DIR_KEY] = tests if certificate: metadata[self.META_ENTRY_CERT_FILE_KEY] = certificate self.metadata = self._validate(metadata) def _validate(self, metadata): for (key, value) in six.iteritems(BASE_META): if metadata.get(key) != value: raise ValueError('TOSCA.meta: {} must be {}'.format(key, value)) utils.check_file_dir(root=self.base_dir, entry=metadata.get(META_ENTRY_DEFINITIONS_KEY), msg='Please specify a valid entry point.', check_dir=False) entry_file = os.path.join(self.base_dir, metadata.get(META_ENTRY_DEFINITIONS_KEY)) try: with open(entry_file) as f: v = yaml.safe_load(f)['tosca_definitions_version'] except: raise ValueError('Entry file {} is not a valid tosca simple yaml file'.format(entry_file)) if metadata.get(self.META_ENTRY_MANIFEST_FILE_KEY): utils.check_file_dir(root=self.base_dir, entry=metadata[self.META_ENTRY_MANIFEST_FILE_KEY], msg='Please specify a valid manifest file.', check_dir=False) if metadata.get(self.META_ENTRY_HISTORY_FILE_KEY): utils.check_file_dir(root=self.base_dir, entry=metadata[self.META_ENTRY_HISTORY_FILE_KEY], msg='Please specify a valid change history file.', check_dir=False) if metadata.get(self.META_ENTRY_LICENSES_DIR_KEY): utils.check_file_dir(root=self.base_dir, entry=metadata[self.META_ENTRY_LICENSES_DIR_KEY], msg='Please specify a valid license directory.', check_dir=True) if metadata.get(self.META_ENTRY_TESTS_DIR_KEY): utils.check_file_dir(root=self.base_dir, entry=metadata[self.META_ENTRY_TESTS_DIR_KEY], msg='Please specify a valid test directory.', check_dir=True) if metadata.get(self.META_ENTRY_CERT_FILE_KEY): utils.check_file_dir(root=self.base_dir, entry=metadata[self.META_ENTRY_CERT_FILE_KEY], msg='Please specify a valid certificate file.', check_dir=False) missing_keys = [key for key in self.REQUIRED_KEYS if key not in metadata] if missing_keys: raise ValueError('TOSCA.meta: missing keys: {}'.format(','.join(missing_keys))) return metadata def dump_as_string(self): s = "" for key in self.REQUIRED_KEYS + self.OPTIONAL_KEYS: if self.metadata.get(key): s += "{}: {}\n".format(key, self.metadata.get(key)) return s @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_manifest_file(self): return self.metadata.get(self.META_ENTRY_MANIFEST_FILE_KEY) @property def entry_history_file(self): return self.metadata.get(self.META_ENTRY_HISTORY_FILE_KEY) @property def entry_tests_dir(self): return self.metadata.get(self.META_ENTRY_TESTS_DIR_KEY) @property def entry_licenses_dir(self): return self.metadata.get(self.META_ENTRY_LICENSES_DIR_KEY) @property def entry_certificate_file(self): return self.metadata.get(self.META_ENTRY_CERT_FILE_KEY) class ToscaMeta241(ToscaMeta): # SOL004 v2.4.1 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' META_ENTRY_CERT_FILE_KEY = 'Entry-Certificate' REQUIRED_KEYS = [ META_FILE_VERSION_KEY, META_CSAR_VERSION_KEY, META_CREATED_BY_KEY, META_ENTRY_DEFINITIONS_KEY, ] OPTIONAL_KEYS = [ META_ENTRY_MANIFEST_FILE_KEY, META_ENTRY_HISTORY_FILE_KEY, META_ENTRY_LICENSES_DIR_KEY, META_ENTRY_TESTS_DIR_KEY, META_ENTRY_CERT_FILE_KEY, ] class ToscaMeta261(ToscaMeta): # SOL004 v2.6.1 pass def create_from_file(base_dir): csar_metafile = os.path.join(base_dir, META_FILE) if not os.path.exists(csar_metafile): raise ValueError('Metadata file {0} is missing from the CSAR'.format(csar_metafile)) LOG.debug('CSAR metadata file: {0}'.format(csar_metafile)) LOG.debug('Attempting to parse CSAR metadata YAML') with open(csar_metafile) as f: metadata = yaml.safe_load(f) LOG.debug('CSAR metadata:\n{0}'.format(pprint.pformat(metadata))) # By default we assume it's SOL004 2.4.1 cls = ToscaMeta241 for key in metadata.keys(): if key.startswith('ETSI-'): cls = ToscaMeta261 break return cls(base_dir, entry=metadata.get(META_ENTRY_DEFINITIONS_KEY), manifest=metadata.get(cls.META_ENTRY_MANIFEST_FILE_KEY), changelog=metadata.get(cls.META_ENTRY_HISTORY_FILE_KEY), licenses=metadata.get(cls.META_ENTRY_LICENSES_DIR_KEY), tests=metadata.get(cls.META_ENTRY_TESTS_DIR_KEY), certificate=metadata.get(cls.META_ENTRY_CERT_FILE_KEY), meta_file_version=metadata.get(META_FILE_VERSION_KEY), meta_csar_version=metadata.get(META_CSAR_VERSION_KEY), meta_created_by=metadata.get(META_CREATED_BY_KEY))