a40f2ebd30d9544541c5bab82bb5d6afdf637965
[sdc.git] / openecomp-be / backend / openecomp-sdc-vendor-software-product-manager / src / main / java / org / openecomp / sdc / vendorsoftwareproduct / impl / onboarding / OnboardingPackageProcessor.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  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License.
15  *
16  *  SPDX-License-Identifier: Apache-2.0
17  *  ============LICENSE_END=========================================================
18  */
19
20 package org.openecomp.sdc.vendorsoftwareproduct.impl.onboarding;
21
22 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_EMPTY_ERROR;
23 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_INVALID_ERROR;
24 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_INVALID_EXTENSION;
25 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_MISSING_INTERNAL_PACKAGE;
26 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_ERROR;
27 import static org.openecomp.sdc.common.errors.Messages.PACKAGE_PROCESS_INTERNAL_PACKAGE_ERROR;
28 import static org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager.ALLOWED_CERTIFICATE_EXTENSIONS;
29 import static org.openecomp.sdc.vendorsoftwareproduct.security.SecurityManager.ALLOWED_SIGNATURE_EXTENSIONS;
30
31 import java.io.ByteArrayInputStream;
32 import java.io.File;
33 import java.io.FileInputStream;
34 import java.io.InputStream;
35 import java.nio.ByteBuffer;
36 import java.nio.charset.StandardCharsets;
37 import java.util.ArrayList;
38 import java.util.HashSet;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Objects;
42 import java.util.Optional;
43 import java.util.Set;
44 import org.apache.commons.collections4.CollectionUtils;
45 import org.apache.commons.collections4.MapUtils;
46 import org.apache.commons.io.FilenameUtils;
47 import org.openecomp.core.utilities.file.FileContentHandler;
48 import org.openecomp.core.utilities.json.JsonUtil;
49 import org.openecomp.core.utilities.orchestration.OnboardingTypesEnum;
50 import org.openecomp.sdc.common.utils.SdcCommon;
51 import org.openecomp.sdc.common.zip.exception.ZipException;
52 import org.openecomp.sdc.common.utils.CommonUtil;
53 import org.openecomp.sdc.datatypes.error.ErrorLevel;
54 import org.openecomp.sdc.datatypes.error.ErrorMessage;
55 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
56 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
57 import org.openecomp.sdc.logging.api.Logger;
58 import org.openecomp.sdc.logging.api.LoggerFactory;
59 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackage;
60 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardPackageInfo;
61 import org.openecomp.sdc.vendorsoftwareproduct.types.OnboardSignedPackage;
62
63 public class OnboardingPackageProcessor {
64     private static final Logger LOGGER = LoggerFactory.getLogger(OnboardingPackageProcessor.class);
65     private static final String CSAR_EXTENSION = "csar";
66     private static final String ZIP_EXTENSION = "zip";
67     private static  boolean helmBase = false;
68
69     private final String packageFileName;
70     private final byte[] packageFileContent;
71     private FileContentHandler onboardPackageContentHandler;
72     private Set<ErrorMessage> errorMessageSet = new HashSet<>();
73     private OnboardPackageInfo onboardPackageInfo;
74
75     public OnboardingPackageProcessor(final String packageFileName, final byte[] packageFileContent) {
76         this.packageFileName = packageFileName;
77         this.packageFileContent = packageFileContent;
78         onboardPackageInfo = processPackage();
79     }
80
81     private OnboardPackageInfo processPackage() {
82         if (!hasValidExtension()) {
83             final String message = PACKAGE_INVALID_EXTENSION.formatMessage(packageFileName, String.join(", ", CSAR_EXTENSION, ZIP_EXTENSION));
84             reportError(ErrorLevel.ERROR, message);
85             return null;
86         }
87         try {
88             onboardPackageContentHandler = CommonUtil.getZipContent(packageFileContent);
89         } catch (final ZipException e) {
90             final String message = PACKAGE_PROCESS_ERROR.formatMessage(packageFileName);
91             LOGGER.error(message, e);
92             reportError(ErrorLevel.ERROR, message);
93             return null;
94         }
95         if (isPackageEmpty()) {
96             final String message = PACKAGE_EMPTY_ERROR.formatMessage(packageFileName);
97             reportError(ErrorLevel.ERROR, message);
98             return null;
99         }
100
101         final String packageName = FilenameUtils.getBaseName(packageFileName);
102         final String packageExtension = FilenameUtils.getExtension(packageFileName);
103
104         if (hasSignedPackageStructure()) {
105             return processSignedPackage(packageName, packageExtension);
106         } else {
107             if (packageExtension.equalsIgnoreCase(CSAR_EXTENSION)) {
108                 final OnboardPackage onboardPackage = new OnboardPackage(packageName, packageExtension,
109                     ByteBuffer.wrap(packageFileContent), new OnboardingPackageContentHandler(onboardPackageContentHandler));
110                 return new OnboardPackageInfo(onboardPackage, OnboardingTypesEnum.CSAR);
111             } else if (packageExtension.equalsIgnoreCase(ZIP_EXTENSION)) {
112                 addDummyHeat();
113                 final OnboardPackage onboardPackage = new OnboardPackage(packageName, packageExtension,
114                     ByteBuffer.wrap(packageFileContent), onboardPackageContentHandler);
115                 return new OnboardPackageInfo(onboardPackage, OnboardingTypesEnum.ZIP);
116             }
117         }
118
119         reportError(ErrorLevel.ERROR, PACKAGE_INVALID_ERROR.formatMessage(packageFileName));
120         return null;
121     }
122
123     private void addDummyHeat() {
124         // temporary fix for adding dummy base
125         List<FileData> newfiledata = new ArrayList<>();
126         try (InputStream zipFileManifest = onboardPackageContentHandler.getFileContentAsStream(SdcCommon.MANIFEST_NAME)) {
127             ManifestContent manifestContent =
128                     JsonUtil.json2Object(zipFileManifest, ManifestContent.class);
129             for (FileData fileData : manifestContent.getData()) {
130                 if (Objects.nonNull(fileData.getType()) &&
131                         fileData.getType().equals(FileData.Type.HELM) && fileData.getBase()) {
132                     helmBase = true;
133                     fileData.setBase(false);
134                     FileData dummyHeat = new FileData();
135                     dummyHeat.setBase(true);
136                     dummyHeat.setFile("base_template_dummy_ignore.yaml");
137                     dummyHeat.setType(FileData.Type.HEAT);
138                     FileData dummyEnv = new FileData();
139                     dummyEnv.setBase(false);
140                     dummyEnv.setFile("base_template_dummy_ignore.env");
141                     dummyEnv.setType(FileData.Type.HEAT_ENV);
142                     List<FileData> dataEnvList = new ArrayList<>();
143                     dataEnvList.add(dummyEnv);
144                     dummyHeat.setData(dataEnvList);
145                     newfiledata.add(dummyHeat);
146                     String filePath = new File("").getAbsolutePath() + "/resources";
147                     File envFilePath = new File(filePath + "/base_template.env");
148                     File baseFilePath = new File(filePath + "/base_template.yaml");
149                     try (
150                             InputStream envStream = new FileInputStream(envFilePath);
151                             InputStream baseStream = new FileInputStream(baseFilePath);) {
152                         onboardPackageContentHandler.addFile("base_template_dummy_ignore.env", envStream);
153                         onboardPackageContentHandler.addFile("base_template_dummy_ignore.yaml", baseStream);
154                     } catch (Exception e) {
155                         LOGGER.error("Failed creating input stream {}", e);
156                     }
157                 }
158             }
159             if (helmBase) {
160                 manifestContent.getData().addAll(newfiledata);
161                 InputStream manifestContentStream = new ByteArrayInputStream((JsonUtil.object2Json(manifestContent)).getBytes(StandardCharsets.UTF_8));
162                 onboardPackageContentHandler.remove(SdcCommon.MANIFEST_NAME);
163                 onboardPackageContentHandler.addFile(SdcCommon.MANIFEST_NAME, manifestContentStream);
164             }
165         } catch (Exception e) {
166             final String message = PACKAGE_INVALID_ERROR.formatMessage(packageFileName);
167             LOGGER.error(message, e);
168         }
169     }
170     private boolean hasValidExtension() {
171         final String packageExtension = FilenameUtils.getExtension(packageFileName);
172         return packageExtension.equalsIgnoreCase(CSAR_EXTENSION) || packageExtension.equalsIgnoreCase(ZIP_EXTENSION);
173     }
174
175     private OnboardPackageInfo processSignedPackage(final String packageName, final String packageExtension) {
176         final String internalPackagePath = findInternalPackagePath().orElse(null);
177         if (internalPackagePath == null) {
178             reportError(ErrorLevel.ERROR, PACKAGE_MISSING_INTERNAL_PACKAGE.getErrorMessage());
179             return null;
180         }
181         final String signatureFilePath = findSignatureFilePath().orElse(null);
182         final String certificateFilePath = findCertificateFilePath().orElse(null);
183         final OnboardSignedPackage onboardSignedPackage =
184             new OnboardSignedPackage(packageName, packageExtension, ByteBuffer.wrap(packageFileContent),
185                 onboardPackageContentHandler, signatureFilePath, internalPackagePath, certificateFilePath);
186
187         final String internalPackageName = FilenameUtils.getName(internalPackagePath);
188         final String internalPackageBaseName = FilenameUtils.getBaseName(internalPackagePath);
189         final String internalPackageExtension = FilenameUtils.getExtension(internalPackagePath);
190         final byte[] internalPackageContent = onboardPackageContentHandler.getFileContent(internalPackagePath);
191         final OnboardPackage onboardPackage;
192         try {
193             final OnboardingPackageContentHandler fileContentHandler =
194                 new OnboardingPackageContentHandler(CommonUtil.getZipContent(internalPackageContent));
195             onboardPackage = new OnboardPackage(internalPackageBaseName, internalPackageExtension,
196                 internalPackageContent, fileContentHandler);
197         } catch (final ZipException e) {
198             final String message = PACKAGE_PROCESS_INTERNAL_PACKAGE_ERROR.formatMessage(internalPackageName);
199             LOGGER.error(message, e);
200             reportError(ErrorLevel.ERROR, message);
201             return null;
202         }
203
204         return new OnboardPackageInfo(onboardSignedPackage, onboardPackage, OnboardingTypesEnum.SIGNED_CSAR);
205     }
206
207     private void reportError(final ErrorLevel errorLevel, final String message) {
208         errorMessageSet.add(new ErrorMessage(errorLevel, message));
209     }
210
211     public boolean hasErrors() {
212         return !errorMessageSet.isEmpty();
213     }
214
215     public Set<ErrorMessage> getErrorMessageSet() {
216         return errorMessageSet;
217     }
218
219     private Optional<String> findInternalPackagePath() {
220         return onboardPackageContentHandler.getFileList().stream()
221             .filter(filePath -> {
222                     final String extension = FilenameUtils.getExtension(filePath);
223                     return CSAR_EXTENSION.equalsIgnoreCase(extension) || ZIP_EXTENSION.equalsIgnoreCase(extension);
224                 }
225             )
226             .findFirst();
227     }
228
229     private boolean isPackageEmpty() {
230         return MapUtils.isEmpty(onboardPackageContentHandler.getFiles());
231     }
232
233     private boolean hasSignedPackageStructure() {
234         if (MapUtils.isEmpty(onboardPackageContentHandler.getFiles()) || !CollectionUtils.isEmpty(
235             onboardPackageContentHandler.getFolderList())) {
236             return false;
237         }
238         final int numberOfFiles = onboardPackageContentHandler.getFileList().size();
239         if (numberOfFiles == 2) {
240             return hasOneInternalPackageFile(onboardPackageContentHandler) &&
241                 hasOneSignatureFile(onboardPackageContentHandler);
242         }
243
244         if (numberOfFiles == 3) {
245             return hasOneInternalPackageFile(onboardPackageContentHandler) &&
246                 hasOneSignatureFile(onboardPackageContentHandler) &&
247                 hasOneCertificateFile(onboardPackageContentHandler);
248         }
249
250         return false;
251     }
252
253     private boolean hasOneInternalPackageFile(final FileContentHandler fileContentHandler) {
254         return fileContentHandler.getFileList().parallelStream()
255             .map(FilenameUtils::getExtension)
256             .map(String::toLowerCase)
257             .filter(file -> file.endsWith(CSAR_EXTENSION)).count() == 1;
258     }
259
260     private boolean hasOneSignatureFile(final FileContentHandler fileContentHandler) {
261         return fileContentHandler.getFileList().parallelStream()
262             .map(FilenameUtils::getExtension)
263             .map(String::toLowerCase)
264             .filter(ALLOWED_SIGNATURE_EXTENSIONS::contains).count() == 1;
265     }
266
267     private boolean hasOneCertificateFile(final FileContentHandler fileContentHandler) {
268         return fileContentHandler.getFileList().parallelStream()
269             .map(FilenameUtils::getExtension)
270             .map(String::toLowerCase)
271             .filter(ALLOWED_CERTIFICATE_EXTENSIONS::contains).count() == 1;
272     }
273
274     private Optional<String> findSignatureFilePath() {
275         final Map<String, byte[]> files = onboardPackageContentHandler.getFiles();
276         return files.keySet().stream()
277             .filter(fileName -> ALLOWED_SIGNATURE_EXTENSIONS.contains(FilenameUtils.getExtension(fileName).toLowerCase()))
278             .findFirst();
279     }
280
281     private Optional<String> findCertificateFilePath() {
282         final Map<String, byte[]> files = onboardPackageContentHandler.getFiles();
283         return files.keySet().stream()
284             .filter(fileName -> ALLOWED_CERTIFICATE_EXTENSIONS.contains(FilenameUtils.getExtension(fileName).toLowerCase()))
285             .findFirst();
286     }
287
288     public Optional<OnboardPackageInfo> getOnboardPackageInfo() {
289         return Optional.ofNullable(onboardPackageInfo);
290     }
291 }