Add new SOL004 ETSI Validator
[sdc.git] / openecomp-be / backend / openecomp-sdc-vendor-software-product-manager / src / main / java / org / openecomp / sdc / vendorsoftwareproduct / impl / orchestration / csar / validation / SOL004MetaDirectoryValidator.java
1 /*-
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2019 Nordix Foundation.
4  * ================================================================================
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * SPDX-License-Identifier: Apache-2.0
18  * ============LICENSE_END=========================================================
19  *  * Modifications copyright (c) 2020 Nokia
20  * ================================================================================
21  */
22
23 package org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation;
24
25
26 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_CNF_HELM;
27 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_PM_DICTIONARY;
28 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_SW_INFORMATION;
29 import static org.openecomp.sdc.be.config.NonManoArtifactType.ONAP_VES_EVENTS;
30 import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_0;
31 import static org.openecomp.sdc.tosca.csar.CSARConstants.CSAR_VERSION_1_1;
32 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_METADATA_LIMIT;
33 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA;
34 import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_VNF_METADATA;
35 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_MANIFEST_FILE_EXT;
36 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_TYPE_PNF;
37 import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_TYPE_VNF;
38 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.CREATED_BY_ENTRY;
39 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.CSAR_VERSION_ENTRY;
40 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ENTRY_DEFINITIONS;
41 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ETSI_ENTRY_CERTIFICATE;
42 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.ETSI_ENTRY_MANIFEST;
43 import static org.openecomp.sdc.tosca.csar.ToscaMetaEntry.TOSCA_META_FILE_VERSION_ENTRY;
44 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_FILE_VERSION_1_0;
45 import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_PATH_FILE_NAME;
46
47 import java.io.IOException;
48 import java.io.InputStream;
49 import java.util.ArrayList;
50 import java.util.Collections;
51 import java.util.HashMap;
52 import java.util.HashSet;
53 import java.util.List;
54 import java.util.Map;
55 import java.util.Optional;
56 import java.util.Set;
57 import java.util.concurrent.CopyOnWriteArrayList;
58 import java.util.stream.Collectors;
59 import java.util.stream.Stream;
60
61 import com.google.common.collect.ImmutableSet;
62 import org.apache.commons.collections.CollectionUtils;
63 import org.apache.commons.io.FilenameUtils;
64 import org.openecomp.core.impl.ToscaDefinitionImportHandler;
65 import org.openecomp.core.utilities.file.FileContentHandler;
66 import org.openecomp.sdc.be.config.NonManoArtifactType;
67 import org.openecomp.sdc.be.csar.pnf.PnfSoftwareInformation;
68 import org.openecomp.sdc.be.csar.pnf.SoftwareInformationArtifactYamlParser;
69 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
70 import org.openecomp.sdc.common.errors.Messages;
71 import org.openecomp.sdc.common.utils.SdcCommon;
72 import org.openecomp.sdc.datatypes.error.ErrorLevel;
73 import org.openecomp.sdc.datatypes.error.ErrorMessage;
74 import org.openecomp.sdc.logging.api.Logger;
75 import org.openecomp.sdc.logging.api.LoggerFactory;
76 import org.openecomp.sdc.tosca.csar.Manifest;
77 import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata;
78 import org.openecomp.sdc.tosca.csar.SOL004ManifestOnboarding;
79 import org.openecomp.sdc.tosca.csar.ToscaMetaEntry;
80 import org.openecomp.sdc.tosca.csar.ToscaMetadata;
81 import org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding.OnboardingPackageContentHandler;
82 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.exception.MissingCertificateException;
83 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.FileExtractor;
84 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.InternalFilesFilter;
85 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.csar.validation.utils.ValidatorUtils;
86 import org.openecomp.sdc.vendorsoftwareproduct.impl.orchestration.exceptions.InvalidManifestMetadataException;
87 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager;
88 import org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManagerException;
89 import org.yaml.snakeyaml.Yaml;
90
91 /**
92  * Validates the contents of the package to ensure it complies with the "CSAR with TOSCA-Metadata directory" structure
93  * as defined in ETSI GS NFV-SOL 004 v2.6.1.
94  */
95 class SOL004MetaDirectoryValidator implements Validator {
96
97     private static final Logger LOGGER = LoggerFactory.getLogger(SOL004MetaDirectoryValidator.class);
98
99     private static final String MANIFEST_SOURCE = "Source";
100     private static final String MANIFEST_NON_MANO_SOURCE = "Non-MANO Source";
101     private final List<ErrorMessage> errorsByFile = new CopyOnWriteArrayList<>();
102     private final SecurityManager securityManager;
103     private OnboardingPackageContentHandler contentHandler;
104     private Set<String> folderList;
105     private ToscaMetadata toscaMetadata;
106     private final InternalFilesFilter internalFilesFilter = new InternalFilesFilter();
107     protected final ValidatorUtils validatorUtils = new ValidatorUtils();
108
109     public SOL004MetaDirectoryValidator() {
110         securityManager = SecurityManager.getInstance();
111     }
112
113     //for tests purpose
114     SOL004MetaDirectoryValidator(final SecurityManager securityManager) {
115         this.securityManager = securityManager;
116     }
117
118     @Override
119     public Map<String, List<ErrorMessage>> validateContent(final FileContentHandler fileContentHandler) {
120         this.contentHandler = (OnboardingPackageContentHandler) fileContentHandler;
121         this.folderList = contentHandler.getFolderList();
122         parseToscaMetadata();
123         verifyMetadataFile();
124
125         if (packageHasCertificate()) {
126             verifySignedFiles();
127         }
128         validatePmDictionaryContentsAgainstSchema();
129         return Collections.unmodifiableMap(getAnyValidationErrors());
130     }
131
132     private boolean packageHasCertificate() {
133         final String certificatePath = getCertificatePath().orElse(null);
134         return contentHandler.containsFile(certificatePath);
135     }
136
137     private Optional<String> getCertificatePath() {
138         return toscaMetadata.getEntry(ETSI_ENTRY_CERTIFICATE);
139     }
140
141     /**
142      * Parses the {@link org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo#TOSCA_META_PATH_FILE_NAME} file
143      */
144     private void parseToscaMetadata() {
145         try {
146             toscaMetadata =
147                     OnboardingToscaMetadata
148                             .parseToscaMetadataFile(contentHandler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
149         } catch (final IOException e) {
150             reportError(ErrorLevel.ERROR, Messages.METADATA_PARSER_INTERNAL.getErrorMessage());
151             LOGGER.error(Messages.METADATA_PARSER_INTERNAL.getErrorMessage(), e.getMessage(), e);
152         }
153     }
154
155     private void verifyMetadataFile() {
156         if (toscaMetadata.isValid() && hasETSIMetadata()) {
157             verifyManifestNameAndExtension();
158             handleMetadataEntries();
159         } else {
160             errorsByFile.addAll(toscaMetadata.getErrors());
161         }
162     }
163
164     private void verifySignedFiles() {
165         final Map<String, String> signedFileMap = contentHandler.getFileAndSignaturePathMap(SecurityManager.ALLOWED_SIGNATURE_EXTENSIONS);
166         final String packageCertificatePath = getCertificatePath().orElse(null);
167         final byte[] packageCert = contentHandler.getFileContent(packageCertificatePath);
168         if (packageCert == null) {
169             throw new MissingCertificateException("Expected package certificate");
170         }
171         signedFileMap.entrySet().stream().filter(entry -> entry.getValue() != null).forEach(entry -> {
172             final String filePath = entry.getKey();
173             final String fileSignaturePath = entry.getValue();
174             final byte[] fileBytes = contentHandler.getFileContent(filePath);
175             final byte[] fileSignatureBytes = contentHandler.getFileContent(fileSignaturePath);
176             try {
177                 if (!securityManager.verifySignedData(fileSignatureBytes, packageCert, fileBytes)) {
178                     reportError(ErrorLevel.ERROR,
179                             Messages.ARTIFACT_INVALID_SIGNATURE.formatMessage(fileSignaturePath, filePath));
180                 }
181             } catch (final SecurityManagerException e) {
182                 final String errorMessage = Messages.ARTIFACT_SIGNATURE_VALIDATION_ERROR
183                         .formatMessage(fileSignaturePath, filePath, packageCertificatePath, e.getMessage());
184                 reportError(ErrorLevel.ERROR, errorMessage);
185                 LOGGER.error(errorMessage, e);
186             }
187         });
188     }
189
190     private void verifyManifestNameAndExtension() {
191         final Map<String, String> entries = toscaMetadata.getMetaEntries();
192         final String manifestFileName = getFileName(entries.get(ETSI_ENTRY_MANIFEST.getName()));
193         final String manifestExtension = getFileExtension(entries.get(ETSI_ENTRY_MANIFEST.getName()));
194         final String mainDefinitionFileName = getFileName(entries.get(ENTRY_DEFINITIONS.getName()));
195         if (!(TOSCA_MANIFEST_FILE_EXT).equals(manifestExtension)) {
196             reportError(ErrorLevel.ERROR, Messages.MANIFEST_INVALID_EXT.getErrorMessage());
197         }
198         if (!mainDefinitionFileName.equals(manifestFileName)) {
199             reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_INVALID_NAME.getErrorMessage(),
200                     manifestFileName, mainDefinitionFileName));
201         }
202     }
203
204     private String getFileExtension(final String filePath) {
205         return FilenameUtils.getExtension(filePath);
206     }
207
208     private String getFileName(final String filePath) {
209         return FilenameUtils.getBaseName(filePath);
210     }
211
212     private boolean hasETSIMetadata() {
213         final Map<String, String> entries = toscaMetadata.getMetaEntries();
214         return hasEntry(entries, TOSCA_META_FILE_VERSION_ENTRY.getName())
215                 && hasEntry(entries, CSAR_VERSION_ENTRY.getName())
216                 && hasEntry(entries, CREATED_BY_ENTRY.getName());
217     }
218
219     private boolean hasEntry(final Map<String, String> entries, final String mandatoryEntry) {
220         if (!entries.containsKey(mandatoryEntry)) {
221             reportError(ErrorLevel.ERROR,
222                     String.format(Messages.METADATA_MISSING_ENTRY.getErrorMessage(), mandatoryEntry));
223             return false;
224         }
225         return true;
226     }
227
228     private void handleMetadataEntries() {
229         toscaMetadata.getMetaEntries().entrySet().parallelStream().forEach(this::handleEntry);
230     }
231
232     private void handleEntry(final Map.Entry<String, String> entry) {
233         final String key = entry.getKey();
234         final ToscaMetaEntry toscaMetaEntry = ToscaMetaEntry.parse(entry.getKey()).orElse(null);
235         // allows any other unknown entry
236         if (toscaMetaEntry == null) {
237             return;
238         }
239         final String value = entry.getValue();
240
241         switch (toscaMetaEntry) {
242             case TOSCA_META_FILE_VERSION_ENTRY:
243             case CSAR_VERSION_ENTRY:
244             case CREATED_BY_ENTRY:
245                 verifyMetadataEntryVersions(key, value);
246                 break;
247             case ENTRY_DEFINITIONS:
248                 validateDefinitionFile(value);
249                 break;
250             case ETSI_ENTRY_MANIFEST:
251                 validateManifestFile(value);
252                 break;
253             case ETSI_ENTRY_CHANGE_LOG:
254                 validateChangeLog(value);
255                 break;
256             case ETSI_ENTRY_TESTS:
257             case ETSI_ENTRY_LICENSES:
258                 validateOtherEntries(entry);
259                 break;
260             case ETSI_ENTRY_CERTIFICATE:
261                 validateCertificate(value);
262                 break;
263             default:
264                 handleOtherEntry(entry);
265                 break;
266         }
267     }
268
269     private void validateOtherEntries(final Map.Entry<String, String> entry) {
270         final String manifestFile = toscaMetadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName());
271         if (verifyFileExists(contentHandler.getFileList(), manifestFile)) {
272             final Manifest onboardingManifest = new SOL004ManifestOnboarding();
273             onboardingManifest.parse(contentHandler.getFileContentAsStream(manifestFile));
274             final Optional<ResourceTypeEnum> resourceType = onboardingManifest.getType();
275             if (resourceType.isPresent() && resourceType.get() == ResourceTypeEnum.VF) {
276                 final String value = (String) entry.getValue();
277                 validateOtherEntries(value);
278             } else {
279                 final String key = (String) entry.getKey();
280                 reportError(ErrorLevel.ERROR,
281                         String.format(Messages.MANIFEST_INVALID_PNF_METADATA.getErrorMessage(), key));
282             }
283
284         }
285     }
286
287     private void verifyMetadataEntryVersions(final String key, final String version) {
288         if (!(isValidTOSCAVersion(key, version) || isValidCSARVersion(key, version)
289                 || CREATED_BY_ENTRY.getName().equals(key))) {
290             errorsByFile.add(new ErrorMessage(ErrorLevel.ERROR,
291                     String.format(Messages.METADATA_INVALID_VERSION.getErrorMessage(), key, version)));
292             LOGGER.error("{}: key {} - value {} ", Messages.METADATA_INVALID_VERSION.getErrorMessage(), key, version);
293         }
294     }
295
296     private boolean isValidTOSCAVersion(final String key, final String version) {
297         return TOSCA_META_FILE_VERSION_ENTRY.getName().equals(key) && TOSCA_META_FILE_VERSION_1_0.equals(version);
298     }
299
300     private boolean isValidCSARVersion(final String value, final String version) {
301         return CSAR_VERSION_ENTRY.getName().equals(value) && (CSAR_VERSION_1_1.equals(version)
302                 || CSAR_VERSION_1_0.equals(version));
303     }
304
305     protected void validateDefinitionFile(final String filePath) {
306         final Set<String> existingFiles = contentHandler.getFileList();
307
308         if (verifyFileExists(existingFiles, filePath)) {
309             final ToscaDefinitionImportHandler toscaDefinitionImportHandler =
310                     new ToscaDefinitionImportHandler(contentHandler.getFiles(), filePath);
311             final List<ErrorMessage> validationErrorList = toscaDefinitionImportHandler.getErrors();
312             if (CollectionUtils.isNotEmpty(validationErrorList)) {
313                 errorsByFile.addAll(validationErrorList);
314             }
315         } else {
316             reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_DEFINITION_FILE.getErrorMessage(), filePath));
317         }
318     }
319
320     private boolean verifyFileExists(final Set<String> existingFiles, final String filePath) {
321         return existingFiles.contains(filePath);
322     }
323
324     private void validateManifestFile(final String filePath) {
325         final Set<String> existingFiles = contentHandler.getFileList();
326         if (verifyFileExists(existingFiles, filePath)) {
327             final Manifest onboardingManifest = new SOL004ManifestOnboarding();
328             onboardingManifest.parse(contentHandler.getFileContentAsStream(filePath));
329             if (onboardingManifest.isValid()) {
330                 try {
331                     verifyManifestMetadata(onboardingManifest.getMetadata());
332                 } catch (final InvalidManifestMetadataException e) {
333                     reportError(ErrorLevel.ERROR, e.getMessage());
334                     LOGGER.error(e.getMessage(), e);
335                 }
336                 verifyManifestSources(onboardingManifest);
337             } else {
338                 final List<String> manifestErrors = onboardingManifest.getErrors();
339                 manifestErrors.forEach(error -> reportError(ErrorLevel.ERROR, error));
340             }
341         } else {
342             reportError(ErrorLevel.ERROR, String.format(Messages.MANIFEST_NOT_FOUND.getErrorMessage(), filePath));
343         }
344     }
345
346     private void verifyManifestMetadata(final Map<String, String> metadata) {
347         if (!validMetaLimit(metadata)) {
348             reportError(ErrorLevel.ERROR,
349                     String.format(Messages.MANIFEST_METADATA_DOES_NOT_MATCH_LIMIT.getErrorMessage(),
350                             MANIFEST_METADATA_LIMIT));
351         }
352         handleMetadataEntries(metadata);
353     }
354
355     protected boolean isPnfMetadata(final Map<String, String> metadata) {
356         final String firstMetadataDefinition = metadata.keySet().iterator().next();
357         final String expectedMetadataType =
358                 firstMetadataDefinition.contains(TOSCA_TYPE_PNF) ? TOSCA_TYPE_PNF : TOSCA_TYPE_VNF;
359         if (metadata.keySet().stream()
360                 .anyMatch((final String metadataEntry) -> !metadataEntry.contains(expectedMetadataType))) {
361             throw new InvalidManifestMetadataException(Messages.MANIFEST_METADATA_INVALID_ENTRY.getErrorMessage());
362         }
363
364         return TOSCA_TYPE_PNF.equals(expectedMetadataType);
365     }
366
367     private void handleMetadataEntries(final Map<String, String> metadata) {
368         getManifestMetadata(metadata).stream()
369                 .filter(requiredEntry -> !metadata.containsKey(requiredEntry))
370                 .forEach(requiredEntry ->
371                         reportError(ErrorLevel.ERROR,
372                             String.format(Messages.MANIFEST_METADATA_MISSING_ENTRY.getErrorMessage(), requiredEntry)));
373     }
374
375     /**
376      * Checks if all manifest sources exists within the package and if all package files are being referred.
377      *
378      * @param onboardingManifest The manifest
379      */
380     private void verifyManifestSources(final Manifest onboardingManifest) {
381         final Set<String> packageFiles = contentHandler.getFileList();
382         final List<String> sources = internalFilesFilter.filter(onboardingManifest.getSources());
383         verifyFilesExist(packageFiles, sources, MANIFEST_SOURCE);
384
385         final Map<String, List<String>> nonManoArtifacts = onboardingManifest.getNonManoSources();
386
387         final List<String> nonManoValidFilePaths = new ArrayList<>();
388         nonManoArtifacts.forEach((nonManoType, files) -> {
389             final List<String> internalNonManoFileList = internalFilesFilter.filter(files);
390             nonManoValidFilePaths.addAll(internalNonManoFileList);
391             final NonManoArtifactType nonManoArtifactType = NonManoArtifactType.parse(nonManoType).orElse(null);
392             if (nonManoArtifactType == ONAP_PM_DICTIONARY || nonManoArtifactType == ONAP_VES_EVENTS) {
393                 internalNonManoFileList.forEach(this::validateYaml);
394             } else if (nonManoArtifactType == ONAP_SW_INFORMATION) {
395                 validateSoftwareInformationNonManoArtifact(files);
396             } else if (nonManoArtifactType == ONAP_CNF_HELM) {
397                 validateOnapCnfHelmNonManoEntry(files);
398             }
399         });
400
401         verifyFilesExist(packageFiles, nonManoValidFilePaths, MANIFEST_NON_MANO_SOURCE);
402
403         final Set<String> allReferredFiles = new HashSet<>();
404         allReferredFiles.addAll(sources);
405         allReferredFiles.addAll(nonManoValidFilePaths);
406         verifyFilesBeingReferred(allReferredFiles, packageFiles);
407     }
408
409     private void validateSoftwareInformationNonManoArtifact(final List<String> files) {
410         if (CollectionUtils.isEmpty(files)) {
411             reportError(ErrorLevel.ERROR, Messages.EMPTY_SW_INFORMATION_NON_MANO_ERROR.getErrorMessage());
412             return;
413         }
414         if (files.size() != 1) {
415             final String formattedFileList = files.stream()
416                     .map(filePath -> String.format("'%s'", filePath))
417                     .collect(Collectors.joining(", "));
418             reportError(ErrorLevel.ERROR,
419                     Messages.UNIQUE_SW_INFORMATION_NON_MANO_ERROR.formatMessage(formattedFileList));
420             return;
421         }
422         final String swInformationFilePath = files.get(0);
423         final byte[] swInformationYaml = contentHandler.getFileContent(swInformationFilePath);
424         final Optional<PnfSoftwareInformation> parsedYaml = SoftwareInformationArtifactYamlParser
425                 .parse(swInformationYaml);
426         if (!parsedYaml.isPresent()) {
427             reportError(ErrorLevel.ERROR,
428                     Messages.INVALID_SW_INFORMATION_NON_MANO_ERROR.formatMessage(swInformationFilePath));
429         } else {
430             final PnfSoftwareInformation pnfSoftwareInformation = parsedYaml.get();
431             if (!pnfSoftwareInformation.isValid()) {
432                 reportError(ErrorLevel.ERROR,
433                         Messages.INCORRECT_SW_INFORMATION_NON_MANO_ERROR.formatMessage(swInformationFilePath));
434             }
435         }
436     }
437
438     /**
439      * Validates if a YAML file has the correct extension, is not empty and the content is a valid YAML. Reports each
440      * error found.
441      *
442      * @param filePath the file path inside the package
443      */
444     private void validateYaml(final String filePath) {
445         if (!contentHandler.containsFile(filePath)) {
446             return;
447         }
448         final String fileExtension = getFileExtension(filePath);
449         if (!"yaml".equalsIgnoreCase(fileExtension) && !"yml".equalsIgnoreCase(fileExtension)) {
450             reportError(ErrorLevel.ERROR, Messages.INVALID_YAML_EXTENSION.formatMessage(filePath));
451             return;
452         }
453
454         try (final InputStream fileContent = contentHandler.getFileContentAsStream(filePath)) {
455             if (fileContent == null) {
456                 reportError(ErrorLevel.ERROR, Messages.EMPTY_YAML_FILE_1.formatMessage(filePath));
457                 return;
458             }
459             new Yaml().loadAll(fileContent).iterator().next();
460         } catch (final IOException e) {
461             final String errorMsg = Messages.FILE_LOAD_CONTENT_ERROR.formatMessage(filePath);
462             reportError(ErrorLevel.ERROR, errorMsg);
463             LOGGER.debug(errorMsg, e);
464         } catch (final Exception e) {
465             final String message = Messages.INVALID_YAML_FORMAT_1.formatMessage(filePath, e.getMessage());
466             LOGGER.debug(message, e);
467             reportError(ErrorLevel.ERROR, message);
468         }
469     }
470
471     /**
472      * Checks if all package files are referred in manifest. Reports missing references.
473      *
474      * @param referredFileSet the list of referred files path
475      * @param packageFileSet  the list of package file path
476      */
477     private void verifyFilesBeingReferred(final Set<String> referredFileSet, final Set<String> packageFileSet) {
478         packageFileSet.forEach(filePath -> {
479             if (!isManifestFile(filePath) && !referredFileSet.contains(filePath)) {
480                 reportError(ErrorLevel.ERROR,
481                         String.format(Messages.MISSING_MANIFEST_REFERENCE.getErrorMessage(), filePath));
482             }
483         });
484     }
485
486     private boolean isManifestFile(final String filePath) {
487         return filePath.equals(toscaMetadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()));
488     }
489
490     private void validateOtherEntries(final String folderPath) {
491         if (!verifyFoldersExist(folderList, folderPath)) {
492             reportError(ErrorLevel.ERROR, String.format(Messages.METADATA_MISSING_OPTIONAL_FOLDERS.getErrorMessage(),
493                     folderPath));
494         }
495     }
496
497     private void validateCertificate(final String file) {
498         final Set<String> packageFiles = contentHandler.getFileList();
499         if (!verifyFileExist(packageFiles, file)) {
500             reportError(ErrorLevel.ERROR,
501                     String.format(Messages.MISSING_METADATA_FILES.getErrorMessage(), file, file));
502         }
503     }
504
505     private boolean verifyFoldersExist(final Set<String> folderList, final String folderPath) {
506         return folderList.contains(folderPath + "/");
507     }
508
509     private void verifyFilesExist(final Set<String> existingFiles, final List<String> sources, final String type) {
510         sources.forEach(file -> {
511             if (!existingFiles.contains(file)) {
512                 reportError(ErrorLevel.ERROR,
513                         String.format(Messages.MISSING_MANIFEST_SOURCE.getErrorMessage(), type, file));
514             }
515         });
516     }
517
518     private boolean verifyFileExist(final Set<String> existingFiles, final String file) {
519         return existingFiles.contains(file);
520     }
521
522     private void validateChangeLog(final String filePath) {
523         if (!verifyFileExists(contentHandler.getFileList(), filePath)) {
524             reportError(ErrorLevel.ERROR, String.format(Messages.MISSING_METADATA_FILES.getErrorMessage(), filePath));
525         }
526     }
527
528     protected void reportError(final ErrorLevel errorLevel, final String errorMessage) {
529         errorsByFile.add(new ErrorMessage(errorLevel, errorMessage));
530     }
531
532     protected boolean validMetaLimit(Map<String, String> metadata) {
533         return metadata.size() == MANIFEST_METADATA_LIMIT;
534     }
535
536     protected ImmutableSet<String> getManifestMetadata(final Map<String, String> metadata) {
537         return isPnfMetadata(metadata) ? MANIFEST_PNF_METADATA : MANIFEST_VNF_METADATA;
538     }
539
540     protected void handleOtherEntry(final Map.Entry<String, String> entry) {
541         reportError(ErrorLevel.ERROR, Messages.METADATA_UNSUPPORTED_ENTRY.formatMessage(entry.getKey()));
542         LOGGER.warn(Messages.METADATA_UNSUPPORTED_ENTRY.getErrorMessage(), entry.getKey());
543     }
544
545     private Map<String, List<ErrorMessage>> getAnyValidationErrors() {
546         if (errorsByFile.isEmpty()) {
547             return Collections.emptyMap();
548         }
549         final Map<String, List<ErrorMessage>> errors = new HashMap<>();
550         errors.put(SdcCommon.UPLOAD_FILE, errorsByFile);
551         return errors;
552     }
553
554     private void validatePmDictionaryContentsAgainstSchema() {
555         final Stream<byte[]> pmDictionaryFiles = new FileExtractor(getEtsiEntryManifestPath(), contentHandler)
556             .findFiles(ONAP_PM_DICTIONARY);
557         new PMDictionaryValidator()
558             .validate(pmDictionaryFiles, (String message) -> reportError(ErrorLevel.ERROR, message));
559     }
560
561     private String getEtsiEntryManifestPath() {
562         return toscaMetadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName());
563     }
564
565     /**
566      * Validates if onap_cnf_helm non_mano type points to a file
567      * @param files
568      */
569     private void validateOnapCnfHelmNonManoEntry(final List<String> files) {
570         if (CollectionUtils.isEmpty(files)) {
571             reportError(ErrorLevel.ERROR, Messages.EMPTY_ONAP_CNF_HELM_NON_MANO_ERROR.getErrorMessage());
572             return;
573         }
574         if (files.size() != 1) {
575             final String formattedFileList = files.stream()
576                 .map(filePath -> String.format("'%s'", filePath))
577                 .collect(Collectors.joining(", "));
578             reportError(ErrorLevel.ERROR,
579                 Messages.UNIQUE_ONAP_CNF_HELM_NON_MANO_ERROR.formatMessage(formattedFileList));
580         }
581     }
582 }