From 0a1d82ac04a8ef78bfdcbcced4f5096c050edcfe Mon Sep 17 00:00:00 2001 From: "bilal.iqbal" Date: Sun, 10 Mar 2019 00:47:55 +0000 Subject: CSAR Package validation Change-Id: I11af8d93f5a2cd0566a5caf0dad0519d70bd57d7 Issue-ID: SDC-2147 Issue-ID: SDC-2148 Issue-ID: SDC-2149 Issue-ID: SDC-2150 Signed-off-by: bilal.iqbal --- .../OrchestrationTemplateCSARHandler.java | 133 +------- .../csar/validation/ONAPCsarValidator.java | 157 +++++++++ .../validation/SOL004MetaDirectoryValidator.java | 360 +++++++++++++++++++++ .../orchestration/csar/validation/Validator.java | 41 +++ .../csar/validation/ValidatorFactory.java | 45 +++ .../InvalidManifestMetadataException.java | 28 ++ 6 files changed, 639 insertions(+), 125 deletions(-) create mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ONAPCsarValidator.java create mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/SOL004MetaDirectoryValidator.java create mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/Validator.java create mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ValidatorFactory.java create mode 100644 openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/exceptions/InvalidManifestMetadataException.java (limited to 'openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main') diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java index a3772d9298..af5512d119 100644 --- a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/OrchestrationTemplateCSARHandler.java @@ -3,6 +3,7 @@ * Copyright (c) 2018 AT&T Intellectual Property. * Modifications Copyright (c) 2018 Verizon Property. + * Modifications Copyright (c) 2019 Nordix Foundation. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,48 +30,36 @@ import org.openecomp.sdc.common.utils.CommonUtil; import org.openecomp.sdc.common.utils.SdcCommon; import org.openecomp.sdc.datatypes.error.ErrorLevel; import org.openecomp.sdc.datatypes.error.ErrorMessage; -import org.openecomp.sdc.logging.api.Logger; -import org.openecomp.sdc.logging.api.LoggerFactory; -import org.openecomp.sdc.tosca.csar.ToscaMetadata; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.OrchestrationTemplateCandidateData; import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails; -import org.openecomp.sdc.tosca.csar.Manifest; -import org.openecomp.sdc.tosca.csar.OnboardingManifest; -import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata; -import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.exceptions.OrchestrationTemplateHandlerException; +import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.Validator; +import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.ValidatorFactory; import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.CandidateService; import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse; import java.io.IOException; -import java.io.InputStream; import java.nio.ByteBuffer; -import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Collectors; import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters; -import static org.openecomp.sdc.tosca.csar.CSARConstants.ELIGBLE_FOLDERS; -import static org.openecomp.sdc.tosca.csar.CSARConstants.ELIGIBLE_FILES; -import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_MF_FILE_NAME; -import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME; -import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS; -import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME; public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateHandler implements OrchestrationTemplateFileHandler { - private static Logger logger = LoggerFactory.getLogger(OrchestrationTemplateCSARHandler.class); + @Override public Optional getFileContentMap(UploadFileResponse uploadFileResponse, byte[] uploadedFileData) { FileContentHandler contentMap = null; - List folderList = new ArrayList<>(); + List folderList; try { Pair> fileContentMapFromOrchestrationCandidateZip = CommonUtil.getFileContentMapFromOrchestrationCandidateZip(uploadedFileData); contentMap = fileContentMapFromOrchestrationCandidateZip.getKey(); folderList = fileContentMapFromOrchestrationCandidateZip.getRight(); + Validator validator = ValidatorFactory.getValidator(contentMap); + uploadFileResponse.addStructureErrors(validator.validateContent(contentMap, folderList)); } catch (IOException exception) { logger.error(exception.getMessage(), exception); uploadFileResponse.addStructureError( @@ -81,113 +70,8 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH uploadFileResponse.addStructureError( SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, coreException.getMessage())); } - validateContent(uploadFileResponse, contentMap, folderList); - return Optional.ofNullable(contentMap); - } - - private void validateContent(UploadFileResponse uploadFileResponse, FileContentHandler contentMap, - List folderList) { - validateManifest(uploadFileResponse, contentMap); - validateMetadata(uploadFileResponse, contentMap); - validateNoExtraFiles(uploadFileResponse, contentMap); - validateFolders(uploadFileResponse, folderList); - } - - private void validateMetadata(UploadFileResponse uploadFileResponse, - FileContentHandler contentMap){ - if (!validateTOSCAYamlFileInRootExist(contentMap, MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME)) { - try (InputStream metaFileContent = contentMap.getFileContent(TOSCA_META_PATH_FILE_NAME)) { - - ToscaMetadata onboardingToscaMetadata = OnboardingToscaMetadata.parseToscaMetadataFile(metaFileContent); - String entryDefinitionsPath = onboardingToscaMetadata.getMetaEntries().get(TOSCA_META_ENTRY_DEFINITIONS); - if (entryDefinitionsPath != null) { - validateFileExist(uploadFileResponse, contentMap, entryDefinitionsPath); - } else { - uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, - Messages.METADATA_NO_ENTRY_DEFINITIONS.getErrorMessage())); - } - } catch (IOException exception) { - logger.error(exception.getMessage(), exception); - uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, - new ErrorMessage(ErrorLevel.ERROR, Messages.FAILED_TO_VALIDATE_METADATA.getErrorMessage())); - } - } else { - validateFileExist(uploadFileResponse, contentMap, MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME); - } - } - - private void validateManifest(UploadFileResponse uploadFileResponse, - FileContentHandler contentMap) { - - if (!validateFileExist(uploadFileResponse, contentMap, MAIN_SERVICE_TEMPLATE_MF_FILE_NAME)) { - return; - } - - try (InputStream fileContent = contentMap.getFileContent(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME)) { - - Manifest onboardingManifest = OnboardingManifest.parse(fileContent); - if (!onboardingManifest.isValid()) { - onboardingManifest.getErrors().forEach(error -> uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, error))); - } - - } catch (IOException e) { - // convert to runtime to keep the throws unchanged - throw new OrchestrationTemplateHandlerException("Failed to validate manifest", e); - } - } - - private void validateNoExtraFiles(UploadFileResponse uploadFileResponse, - FileContentHandler contentMap) { - List unwantedFiles = contentMap.getFileList().stream() - .filter(this::filterFiles).collect(Collectors.toList()); - if (!unwantedFiles.isEmpty()) { - unwantedFiles.stream().filter(this::filterFiles).forEach(unwantedFile -> - uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, - getErrorWithParameters(Messages.CSAR_FILES_NOT_ALLOWED.getErrorMessage(), - unwantedFile)))); - } - } - - private void validateFolders(UploadFileResponse uploadFileResponse, List folderList) { - List filterResult = - folderList.stream().filter(this::filterFolders).collect(Collectors.toList()); - if (!filterResult.isEmpty()) { - folderList.stream().filter(this::filterFolders).forEach(unwantedFolder -> - uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, - getErrorWithParameters(Messages.CSAR_DIRECTORIES_NOT_ALLOWED.getErrorMessage(), - unwantedFolder)))); - } - } - - private boolean filterFiles(String inFileName) { - boolean valid = ELIGIBLE_FILES.stream().anyMatch(fileName -> fileName.equals(inFileName)); - return !valid && filterFolders(inFileName); - } - - private boolean filterFolders(String fileName) { - return ELIGBLE_FOLDERS.stream().noneMatch(fileName::startsWith); - } - - private boolean validateTOSCAYamlFileInRootExist(FileContentHandler contentMap, String fileName) { - return contentMap.containsFile(fileName); - } - - private boolean validateFileExist(UploadFileResponse uploadFileResponse, - FileContentHandler contentMap, String fileName) { - - boolean containsFile = contentMap.containsFile(fileName); - if (!containsFile) { - uploadFileResponse.addStructureError( - SdcCommon.UPLOAD_FILE, new ErrorMessage(ErrorLevel.ERROR, - getErrorWithParameters(Messages.CSAR_FILE_NOT_FOUND.getErrorMessage(), fileName))); - } - return containsFile; + return Optional.ofNullable(contentMap); } @Override @@ -210,7 +94,6 @@ public class OrchestrationTemplateCSARHandler extends BaseOrchestrationTemplateH return false; } - @Override protected OnboardingTypesEnum getHandlerType() { return OnboardingTypesEnum.CSAR; diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ONAPCsarValidator.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ONAPCsarValidator.java new file mode 100644 index 0000000000..0f44427edd --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ONAPCsarValidator.java @@ -0,0 +1,157 @@ +/*- + * ============LICENSE_START======================================================= + * Modification Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation; + +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.datatypes.error.ErrorMessage; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.tosca.csar.Manifest; +import org.openecomp.sdc.tosca.csar.OnboardingManifest; +import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata; +import org.openecomp.sdc.tosca.csar.ToscaMetadata; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.openecomp.core.validation.errors.ErrorMessagesFormatBuilder.getErrorWithParameters; +import static org.openecomp.sdc.tosca.csar.CSARConstants.ELIGBLE_FOLDERS; +import static org.openecomp.sdc.tosca.csar.CSARConstants.ELIGIBLE_FILES; +import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_MF_FILE_NAME; +import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME; + +class ONAPCsarValidator implements Validator { + + private static Logger logger = LoggerFactory.getLogger(ONAPCsarValidator.class); + + private List uploadFileErrors = new ArrayList<>(); + + @Override + public Map> validateContent(FileContentHandler contentHandler, List folderList) { + + Map> errors = new HashMap<>(); + validateManifest(contentHandler); + validateMetadata(contentHandler); + validateNoExtraFiles(contentHandler); + validateFolders(folderList); + + if(uploadFileErrors == null || uploadFileErrors.isEmpty()){ + return errors; + } + errors.put(SdcCommon.UPLOAD_FILE, uploadFileErrors); + return errors; + } + + private void validateMetadata(FileContentHandler contentMap){ + if (!validateTOSCAYamlFileInRootExist(contentMap, MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME)) { + try (InputStream metaFileContent = contentMap.getFileContent(TOSCA_META_PATH_FILE_NAME)) { + + ToscaMetadata onboardingToscaMetadata = OnboardingToscaMetadata.parseToscaMetadataFile(metaFileContent); + String entryDefinitionsPath = onboardingToscaMetadata.getMetaEntries().get(TOSCA_META_ENTRY_DEFINITIONS); + if (entryDefinitionsPath != null) { + validateFileExist(contentMap, entryDefinitionsPath); + } else { + uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + Messages.METADATA_NO_ENTRY_DEFINITIONS.getErrorMessage())); + } + } catch (IOException exception) { + logger.error(exception.getMessage(), exception); + uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + Messages.FAILED_TO_VALIDATE_METADATA.getErrorMessage())); + } + } else { + validateFileExist(contentMap, MAIN_SERVICE_TEMPLATE_YAML_FILE_NAME); + } + } + + private void validateManifest(FileContentHandler contentMap) { + + if (!validateFileExist(contentMap, MAIN_SERVICE_TEMPLATE_MF_FILE_NAME)) { + return; + } + + try (InputStream fileContent = contentMap.getFileContent(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME)) { + + Manifest onboardingManifest = OnboardingManifest.parse(fileContent); + if (!onboardingManifest.isValid()) { + onboardingManifest.getErrors().forEach(error -> uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + error))); + } + + } catch (IOException e) { + // convert to runtime to keep the throws unchanged + throw new RuntimeException("Failed to validateContent manifest", e); + } + } + + private void validateNoExtraFiles(FileContentHandler contentMap) { + List unwantedFiles = contentMap.getFileList().stream() + .filter(this::filterFiles).collect(Collectors.toList()); + if (!unwantedFiles.isEmpty()) { + unwantedFiles.stream().filter(this::filterFiles).forEach(unwantedFile -> + uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + getErrorWithParameters(Messages.CSAR_FILES_NOT_ALLOWED.getErrorMessage(), unwantedFile)))); + } + } + + private void validateFolders(List folderList) { + List filterResult = + folderList.stream().filter(this::filterFolders).collect(Collectors.toList()); + if (!filterResult.isEmpty()) { + folderList.stream().filter(this::filterFolders).forEach(unwantedFolder -> + uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + getErrorWithParameters(Messages.CSAR_DIRECTORIES_NOT_ALLOWED.getErrorMessage(), + unwantedFolder)))); + } + } + + private boolean filterFiles(String inFileName) { + boolean valid = ELIGIBLE_FILES.stream().anyMatch(fileName -> fileName.equals(inFileName)); + return !valid && filterFolders(inFileName); + } + + private boolean filterFolders(String fileName) { + return ELIGBLE_FOLDERS.stream().noneMatch(fileName::startsWith); + } + + private boolean validateTOSCAYamlFileInRootExist(FileContentHandler contentMap, String fileName) { + return contentMap.containsFile(fileName); + } + + private boolean validateFileExist(FileContentHandler contentMap, String fileName) { + + boolean containsFile = contentMap.containsFile(fileName); + if (!containsFile) { + uploadFileErrors.add(new ErrorMessage(ErrorLevel.ERROR, + getErrorWithParameters(Messages.CSAR_FILE_NOT_FOUND.getErrorMessage(), fileName))); + } + return containsFile; + } +} diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/SOL004MetaDirectoryValidator.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/SOL004MetaDirectoryValidator.java new file mode 100644 index 0000000000..570eee3736 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/SOL004MetaDirectoryValidator.java @@ -0,0 +1,360 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation; + +import org.openecomp.core.converter.ServiceTemplateReaderService; +import org.openecomp.core.impl.services.ServiceTemplateReaderServiceImpl; +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.sdc.common.errors.Messages; +import org.openecomp.sdc.common.utils.SdcCommon; +import org.openecomp.sdc.datatypes.error.ErrorLevel; +import org.openecomp.sdc.datatypes.error.ErrorMessage; +import org.openecomp.sdc.logging.api.Logger; +import org.openecomp.sdc.logging.api.LoggerFactory; +import org.openecomp.sdc.tosca.csar.Manifest; +import org.openecomp.sdc.tosca.csar.OnboardingManifest; +import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata; +import org.openecomp.sdc.tosca.csar.ToscaMetadata; +import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.exceptions.InvalidManifestMetadataException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_0; +import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_1; +import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_METADATA_LIMIT; +import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA; +import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_VNF_METADATA; +import static org.openecomp.sdc.tosca.csar.CSARConstants.NON_FILE_IMPORT_ATTRIBUTES; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_FILE_VERSION_ENTRY; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_CREATED_BY_ENTRY; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_CSAR_VERSION_ENTRY; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_CHANGE_LOG; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_LICENSES; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_MANIFEST; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_TESTS; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_FILE_VERSION; +import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME; + +/** + * Validates the contents of the package to ensure it complies with the "CSAR with TOSCA-Metadata directory" structure + * as defined in ETSI GS NFV-SOL 004 v2.5.1. + * + */ + +class SOL004MetaDirectoryValidator implements Validator{ + + private static final Logger LOGGER = LoggerFactory.getLogger(SOL004MetaDirectoryValidator.class); + + private final List errorsByFile = new ArrayList<>(); + private final Set verifiedImports = new HashSet<>(); + + @Override + public Map> validateContent(FileContentHandler contentHandler, List folderList) { + validateMetaFile(contentHandler, folderList); + return Collections.unmodifiableMap(getAnyValidationErrors()); + } + + private void validateMetaFile(FileContentHandler contentHandler, List folderList) { + try { + ToscaMetadata toscaMetadata = OnboardingToscaMetadata.parseToscaMetadataFile(contentHandler.getFileContent(TOSCA_META_PATH_FILE_NAME)); + if(toscaMetadata.isValid() && hasETSIMetadata(toscaMetadata)) { + verifyManifestNameAndExtension(toscaMetadata); + handleMetadataEntries(contentHandler, folderList, toscaMetadata); + }else { + errorsByFile.addAll(toscaMetadata.getErrors()); + } + }catch (IOException e){ + reportError(ErrorLevel.ERROR, Messages.METADATA_PARSER_INTERNAL.getErrorMessage()); + LOGGER.error(Messages.METADATA_PARSER_INTERNAL.getErrorMessage(), e.getMessage(), e); + } + } + + private void verifyManifestNameAndExtension(ToscaMetadata toscaMetadata) { + Map entries = toscaMetadata.getMetaEntries(); + String manifestFileName = getFileName(entries.get(TOSCA_META_ENTRY_MANIFEST)); + String manifestExtension = getFileExtension(entries.get(TOSCA_META_ENTRY_MANIFEST)); + String mainDefinitionFileName= getFileName(entries.get(TOSCA_META_ENTRY_DEFINITIONS)); + if(!("mf").equals(manifestExtension)){ + reportError(ErrorLevel.ERROR, Messages.MANIFEST_INVALID_EXT.getErrorMessage()); + } + if(!mainDefinitionFileName.equals(manifestFileName)){ + reportError(ErrorLevel.ERROR, Messages.MANIFEST_INVALID_NAME.getErrorMessage()); + } + } + + public String getFileExtension(String filePath){ + return filePath.substring(filePath.lastIndexOf(".") + 1); + } + + private String getFileName(String filePath){ + return filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".")); + } + + private boolean hasETSIMetadata(ToscaMetadata toscaMetadata){ + Map entries = toscaMetadata.getMetaEntries(); + return hasEntry(entries, TOSCA_META_FILE_VERSION_ENTRY) + && hasEntry(entries, TOSCA_META_CSAR_VERSION_ENTRY) + && hasEntry(entries, TOSCA_META_CREATED_BY_ENTRY); + } + + private boolean hasEntry(Map entries, String mandatoryEntry) { + if (!entries.containsKey(mandatoryEntry)) { + reportError(ErrorLevel.ERROR, String.format(Messages.METADATA_MISSING_ENTRY.getErrorMessage(),mandatoryEntry)); + return false; + } + return true; + } + + private void handleMetadataEntries(FileContentHandler contentHandler, List folderList, ToscaMetadata toscaMetadata) { + for(Map.Entry entry: toscaMetadata.getMetaEntries().entrySet()){ + String key = (String) entry.getKey(); + String value = (String) entry.getValue(); + switch (key){ + case TOSCA_META_FILE_VERSION_ENTRY: + case TOSCA_META_CSAR_VERSION_ENTRY: + case TOSCA_META_CREATED_BY_ENTRY: + verifyMetadataEntryVersions(key, value); + break; + case TOSCA_META_ENTRY_DEFINITIONS: + validateDefinitionFile(contentHandler, value); + break; + case TOSCA_META_ENTRY_MANIFEST: + validateManifestFile(contentHandler, value); + break; + case TOSCA_META_ENTRY_CHANGE_LOG: + validateChangeLog(contentHandler, value); + break; + case TOSCA_META_ENTRY_TESTS: + case TOSCA_META_ENTRY_LICENSES: + validateOtherEntries(folderList, value); + break; + default: + errorsByFile.add(new ErrorMessage(ErrorLevel.ERROR, String.format(Messages.METADATA_UNSUPPORTED_ENTRY.getErrorMessage(), entry))); + LOGGER.warn(Messages.METADATA_UNSUPPORTED_ENTRY.getErrorMessage(), entry); + break; + } + + } + } + + + private void verifyMetadataEntryVersions(String key, String version) { + if(!(isValidTOSCAVersion(key,version) || isValidCSARVersion(key, version) || TOSCA_META_CREATED_BY_ENTRY.equals(key))) { + errorsByFile.add(new ErrorMessage(ErrorLevel.ERROR, Messages.ENTITY_NOT_FOUND.getErrorMessage())); + LOGGER.error("{}: key {} - value {} ", Messages.ENTITY_NOT_FOUND.getErrorMessage(), key, version); + } + } + + private boolean isValidTOSCAVersion(String key, String version){ + return TOSCA_META_FILE_VERSION_ENTRY.equals(key) && TOSCA_META_FILE_VERSION.equals(version); + } + + private boolean isValidCSARVersion(String value, String version){ + return "CSAR-Version".equals(value) && (CSAR_VERSION_1_1.equals(version) + || CSAR_VERSION_1_0.equals(version)); + } + + private void validateDefinitionFile(FileContentHandler contentHandler, String filePath) { + Set existingFiles = contentHandler.getFileList(); + + if (verifyFileExists(existingFiles, filePath)) { + byte[] definitionFile = getFileContent(filePath, contentHandler); + handleImports(contentHandler, filePath, existingFiles, definitionFile); + }else{ + reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_DEFINITION_FILE.getErrorMessage(), filePath)); + } + } + + private void handleImports(FileContentHandler contentHandler, String filePath, Set existingFiles, + byte[] definitionFile) { + try { + ServiceTemplateReaderService readerService = new ServiceTemplateReaderServiceImpl(definitionFile); + List imports = (readerService).getImports(); + for (Object o : imports) { + String rootDir = "/"; + if (filePath.contains("/")) { + rootDir = filePath.substring(0, filePath.lastIndexOf("/")); + } + String verifiedFile = verifyImport(existingFiles, o, rootDir); + if (verifiedFile != null && !verifiedImports.contains(verifiedFile)) { + verifiedImports.add(verifiedFile); + handleImports(contentHandler, verifiedFile, existingFiles, getFileContent(verifiedFile, + contentHandler)); + } + } + } + catch (Exception e){ + reportError(ErrorLevel.ERROR, String.format(Messages.INVALID_YAML_FORMAT.getErrorMessage(), e.getMessage())); + LOGGER.error("{}", Messages.INVALID_YAML_FORMAT_REASON, e.getMessage(), e); + } + } + + private String verifyImport(Set existingFiles, Object o, String parentDir) { + if(o instanceof String){ + String filePath = ((String) o); + if(!filePath.contains("/")){ + filePath = parentDir + "/" + filePath; + } + if(!verifyFileExists(existingFiles, filePath)){ + reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_IMPORT_FILE.getErrorMessage(), (String) o)); + return null; + } + return filePath; + } else if(o instanceof Map){ + Map o1 = (Map)o; + for(Map.Entry entry: o1.entrySet()){ + if(NON_FILE_IMPORT_ATTRIBUTES.stream().noneMatch(attr -> entry.getKey().equals(attr))){ + verifyImport(existingFiles, entry.getValue(), parentDir); + } + } + }else { + reportError(ErrorLevel.ERROR, Messages.INVALID_IMPORT_STATEMENT.getErrorMessage()); + } + return null; + } + + private boolean verifyFileExists(Set existingFiles, String filePath){ + return existingFiles.contains(filePath); + } + + private byte[] getFileContent(String filename, FileContentHandler contentHandler){ + Map files = contentHandler.getFiles(); + return files.get(filename); + } + + private void validateManifestFile(FileContentHandler contentHandler, String filePath){ + final Set exitingFiles = contentHandler.getFileList(); + if(verifyFileExists(exitingFiles, filePath)) { + Manifest onboardingManifest = OnboardingManifest.parse(contentHandler.getFileContent(filePath)); + if(onboardingManifest.isValid()){ + try { + verifyManifestMetadata(onboardingManifest.getMetadata()); + }catch (InvalidManifestMetadataException e){ + reportError(ErrorLevel.ERROR, e.getMessage()); + LOGGER.error(e.getMessage(), e); + } + verifySourcesExists(exitingFiles, onboardingManifest); + }else{ + List manifestErrors = onboardingManifest.getErrors(); + for(String error: manifestErrors){ + reportError(ErrorLevel.ERROR, error); + } + } + }else { + reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_NOT_EXIST.getErrorMessage(), filePath)); + } + } + + private void verifyManifestMetadata(Map metadata) { + if(metadata.size() != MANIFEST_METADATA_LIMIT){ + reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT.getErrorMessage(), + MANIFEST_METADATA_LIMIT)); + } + if(isPnfMetadata(metadata)){ + handlePnfMetadataEntries(metadata); + }else { + handleVnfMetadataEntries(metadata); + } + } + + private boolean isPnfMetadata(Map metadata) { + String metadataType = null; + for(String key: metadata.keySet()) { + if(metadataType == null){ + metadataType = key.contains("pnf") ? "pnf" : "vnf"; + }else if(!key.contains(metadataType)){ + throw new InvalidManifestMetadataException(Messages.MANIFEST_METADATA_INVALID_ENTRY.getErrorMessage()); + } + } + return "pnf".equals(metadataType); + } + + private void handleVnfMetadataEntries(Map metadata) { + for (String requiredPnfEntry : MANIFEST_VNF_METADATA) { + if (!metadata.containsKey(requiredPnfEntry)) { + reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_METADATA_MISSING_ENTRY.getErrorMessage(), requiredPnfEntry)); + } + } + } + + private void handlePnfMetadataEntries(Map metadata) { + for (String requiredPnfEntry : MANIFEST_PNF_METADATA) { + if (!metadata.containsKey(requiredPnfEntry)) { + reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_METADATA_MISSING_ENTRY.getErrorMessage(), requiredPnfEntry)); + } + } + } + + private void verifySourcesExists(Set exitingFiles, Manifest onboardingManifest) { + List sources = onboardingManifest.getSources(); + Map> nonManoArtifacts = onboardingManifest.getNonManoSources(); + verifyFilesExist(exitingFiles, sources); + for (Map.Entry entry : nonManoArtifacts.entrySet()) { + verifyFilesExist(exitingFiles, (List) entry.getValue()); + } + } + + private void validateOtherEntries(List folderList, String folderPath){ + if(!verifyFoldersExist(folderList, folderPath)) + reportError(ErrorLevel.ERROR, String.format(Messages.METADATA_MISSING_OPTIONAL_FOLDERS.getErrorMessage(), + folderPath)); + } + + private boolean verifyFoldersExist(List folderList, String folderPath){ + return folderList.contains(folderPath + "/"); + } + + private void verifyFilesExist(Set existingFiles, List sources){ + for(String file: sources){ + if(!verifyFileExists(existingFiles, file)){ + reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_ARTIFACT.getErrorMessage(), file)); + } + + } + } + + private void validateChangeLog(FileContentHandler contentHandler, String filePath){ + if(!verifyFileExists(contentHandler.getFileList(), filePath)){ + reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_ARTIFACT.getErrorMessage(), filePath)); + } + } + + private void reportError(ErrorLevel errorLevel, String errorMessage){ + errorsByFile.add(new ErrorMessage(errorLevel, errorMessage)); + } + + private Map> getAnyValidationErrors(){ + + if(errorsByFile.isEmpty()){ + return Collections.emptyMap(); + } + Map> errors = new HashMap<>(); + errors.put(SdcCommon.UPLOAD_FILE, errorsByFile); + return errors; + } +} diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/Validator.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/Validator.java new file mode 100644 index 0000000000..927f3c0b69 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/Validator.java @@ -0,0 +1,41 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation; + +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.sdc.datatypes.error.ErrorMessage; +import java.util.List; +import java.util.Map; + +/** + * Validates the contents of the CSAR package uploaded in SDC. + */ + +public interface Validator { + + /** + * + * @param contentHandler contains file and its data + * @param folderList folder structure inside the package + * @return errors Map of errors that occur + */ + Map> validateContent(FileContentHandler contentHandler, List folderList); +} diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ValidatorFactory.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ValidatorFactory.java new file mode 100644 index 0000000000..bc44496fef --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/csar/validation/ValidatorFactory.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation; + +import org.openecomp.core.utilities.file.FileContentHandler; +import org.openecomp.sdc.vendorsoftwareproduct.services.impl.etsi.ETSIService; +import org.openecomp.sdc.vendorsoftwareproduct.services.impl.etsi.ETSIServiceImpl; +import java.io.IOException; + +public class ValidatorFactory { + + private ValidatorFactory(){ + + } + + /** + * Returns a validator based on the contents of the csar package. + * + * @param contentMap the csar package + * @return Validator based on the contents of the csar package provided + * @throws IOException when metafile is invalid + */ + public static Validator getValidator(FileContentHandler contentMap) throws IOException{ + ETSIService etsiService = new ETSIServiceImpl(null); + return etsiService.isSol004WithToscaMetaDirectory(contentMap) ? new SOL004MetaDirectoryValidator() : new ONAPCsarValidator(); + } +} diff --git a/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/exceptions/InvalidManifestMetadataException.java b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/exceptions/InvalidManifestMetadataException.java new file mode 100644 index 0000000000..137891c0c9 --- /dev/null +++ b/openecomp-be/backend/openecomp-sdc-vendor-software-product-manager/src/main/java/org/openecomp/sdc/vendorsoftwareproduct/impl/orchestration/exceptions/InvalidManifestMetadataException.java @@ -0,0 +1,28 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * 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. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.exceptions; + +public class InvalidManifestMetadataException extends RuntimeException{ + + public InvalidManifestMetadataException(String message){ + super(message); + } +} -- cgit 1.2.3-korg