54cc1fbf1c3f53a814531dbfb64ea076a32f0c41
[sdc.git] /
1 /*
2  * Copyright © 2016-2017 European Support Limited
3  * Modifications copyright (c) 2021 Nokia
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
18 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.filedatastructuremodule;
19
20 import org.apache.commons.collections4.CollectionUtils;
21 import org.openecomp.core.utilities.file.FileContentHandler;
22 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
23 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
24 import org.openecomp.sdc.vendorsoftwareproduct.dao.type.VspDetails;
25 import org.openecomp.sdc.vendorsoftwareproduct.services.HeatFileAnalyzer;
26 import org.openecomp.sdc.vendorsoftwareproduct.services.filedatastructuremodule.ManifestCreator;
27 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.AnalyzedZipHeatFiles;
28 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Constants;
29 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.FilesDataStructure;
30 import org.openecomp.sdc.vendorsoftwareproduct.types.candidateheat.Module;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.util.*;
35 import java.util.regex.Pattern;
36
37 public class ManifestCreatorNamingConventionImpl implements ManifestCreator {
38   protected static final Logger logger =
39       LoggerFactory.getLogger(ManifestCreatorNamingConventionImpl.class);
40
41   private static final String CLOUD_SPECIFIC_FIXED_KEY_WORD = "cloudtech";
42   private static final String[][] CLOUD_SPECIFIC_KEY_WORDS = {{"k8s", "azure", "aws"}, /* cloud specific technology */
43                                                               {"charts", "day0", "configtemplate"} /*cloud specific sub type*/};
44   private static final String CONTROLLER_BLUEPRINT_ARCHIVE_FIXED_KEY_WORD = "CBA";
45   private static final String HELM_KEY_WORD = "HELM";
46
47   @Override
48   public Optional<ManifestContent> createManifest(
49       VspDetails vspDetails, FilesDataStructure filesDataStructure) {
50     if (Objects.isNull(filesDataStructure)) {
51       return Optional.empty();
52     }
53
54     List<FileData> fileDataList = new ArrayList<>();
55     addModulesToManifestFileDataList(filesDataStructure, fileDataList);
56     addNestedToManifest(filesDataStructure, fileDataList);
57     addArtifactsToManifestFileDataList(filesDataStructure, fileDataList);
58
59     ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
60     return Optional.of(manifestContent);
61   }
62
63   @Override
64   public Optional<ManifestContent> createManifestFromExisting(VspDetails vspDetails, FilesDataStructure filesDataStructure, ManifestContent existingManifest) {
65     if (Objects.isNull(filesDataStructure)) {
66       return Optional.empty();
67     }
68
69     List<FileData> fileDataList = new ArrayList<>();
70     addModulesToManifestFileDataList(filesDataStructure, fileDataList);
71     addNestedToManifest(filesDataStructure, fileDataList);
72     addArtifactsToManifestFileDataList(filesDataStructure, fileDataList, existingManifest);
73
74     ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
75     return Optional.of(manifestContent);
76   }
77
78   private void addArtifactsToManifestFileDataList(FilesDataStructure filesDataStructure, List<FileData> fileDataList, ManifestContent existingManifest) {
79     Collection<String> forArtifacts = CollectionUtils
80             .union(filesDataStructure.getArtifacts(), filesDataStructure.getUnassigned());
81     if (CollectionUtils.isNotEmpty(forArtifacts)) {
82       for (String artifact : forArtifacts) {
83         if (isCloudSpecificArtifact(artifact)) {
84           fileDataList.add(createBaseFileData(FileData.Type.CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACT, artifact));
85         } else if (isControllerBlueprintArchive(artifact)) {
86           fileDataList.add(createBaseFileData(FileData.Type.CONTROLLER_BLUEPRINT_ARCHIVE, artifact));
87         } else if (isHelm(artifact)) {
88           fileDataList.add(createBaseFileData(FileData.Type.HELM, artifact));
89         } else if (isPmDictionary(artifact, existingManifest)) {
90           fileDataList.add(createBaseFileData(FileData.Type.PM_DICTIONARY, artifact));
91         }
92         else {
93           fileDataList.add(createBaseFileData(FileData.Type.OTHER, artifact));
94         }
95       }
96     }
97   }
98
99   private boolean isPmDictionary(String artifact, ManifestContent existingManifest) {
100     return existingManifest.getData()
101             .stream()
102             .filter(fileData -> fileData.getType()
103                     .equals(FileData.Type.PM_DICTIONARY))
104             .map(FileData::getFile)
105             .anyMatch(pmDictionaryFile -> pmDictionaryFile.equals(artifact));
106   }
107
108   private void addNestedToManifest(
109       FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
110     if (CollectionUtils.isNotEmpty(filesDataStructure.getNested())) {
111       for (String nested : filesDataStructure.getNested()) {
112         fileDataList.add(createBaseFileData(FileData.Type.HEAT, nested));
113       }
114     }
115   }
116
117   @Override
118   public Optional<ManifestContent> createManifest(VspDetails vspDetails,
119                                                   FileContentHandler fileContentHandler,
120                                                   AnalyzedZipHeatFiles analyzedZipHeatFiles) {
121     logger.info("Trying to generate manifest");
122     if (Objects.isNull(fileContentHandler)
123         || CollectionUtils.isEmpty(fileContentHandler.getFileList())) {
124       logger.info("fileContentHandler or filesList is empty. ManifestContent will not be created");
125       return Optional.empty();
126     }
127
128     Map<String, byte[]> files = fileContentHandler.getFiles();
129
130     List<FileData> fileDataList =
131         createFileDataListFromZipFiles(fileContentHandler, files,
132             analyzedZipHeatFiles.getFilesNotEligbleForModules());
133     ManifestContent manifestContent = createManifest(vspDetails, fileDataList);
134
135     return Optional.of(manifestContent);
136   }
137
138   private ManifestContent createManifest(VspDetails vspDetails, List<FileData> fileDataList) {
139     ManifestContent manifestContent = new ManifestContent();
140     manifestContent.setName(vspDetails.getName());
141     manifestContent.setDescription(vspDetails.getDescription());
142     manifestContent
143         .setVersion(vspDetails.getVersion() == null ? null : vspDetails.getVersion().toString());
144     // vsp version, need to check in confluence
145     manifestContent.setData(fileDataList);
146     return manifestContent;
147   }
148
149   private List<FileData> createFileDataListFromZipFiles(FileContentHandler fileContentHandler,
150                                                         Map<String, byte[]> files,
151                                                         Collection<String> filesNotEligibleForModules) {
152
153     Set<String> processedFiles = new HashSet<>();
154     List<FileData> fileDataList = new ArrayList<>();
155     for (String fileName : files.keySet()) {
156       if (processedFiles.contains(fileName)) {
157         continue;
158       }
159       if (isFileBaseFile(fileName)) {
160         fileDataList
161             .add(createModuleFileData(
162                 fileName, true, processedFiles, fileContentHandler.getFileList(), fileDataList));
163       } else if (isFileModuleFile(fileName, filesNotEligibleForModules)) {
164         fileDataList
165             .add(createModuleFileData(
166                 fileName, false, processedFiles, fileContentHandler.getFileList(), fileDataList));
167       } else {
168         if (HeatFileAnalyzer.isYamlFile(fileName)) {
169           fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT, null));
170         } else if (HeatFileAnalyzer.isEnvFile(fileName)) {
171           fileDataList.add(createBasicFileData(fileName, FileData.Type.HEAT_ENV, null));
172         } else {
173           fileDataList.add(createBasicFileData(fileName, FileData.Type.OTHER, null));
174         }
175       }
176     }
177     return fileDataList;
178   }
179
180   private boolean isFileModuleFile(String fileName, Collection<String> filesCannotBeModule) {
181     return !filesCannotBeModule.contains(fileName);
182   }
183
184   @Override
185   public boolean isFileBaseFile(String fileName) {
186     return Pattern.matches(Constants.BASE_HEAT_REGEX, fileName) && !isVolFile(fileName);
187   }
188
189   protected boolean isCloudSpecificArtifact(String artifact) {
190       if (artifact.contains(CLOUD_SPECIFIC_FIXED_KEY_WORD)) {
191           for (int i = 0; i < CLOUD_SPECIFIC_KEY_WORDS.length; i++) {
192               if (Arrays.stream(CLOUD_SPECIFIC_KEY_WORDS[i]).noneMatch(str -> artifact.contains(str))) {
193                   return false;
194               }
195           }
196           return true;
197       } else {
198           return false;
199       }
200   }
201
202   private boolean isControllerBlueprintArchive(String artifact) {
203     return artifact.toUpperCase().contains(CONTROLLER_BLUEPRINT_ARCHIVE_FIXED_KEY_WORD);
204   }
205
206   private boolean isHelm(String artifact) {
207     return artifact.toUpperCase().contains(HELM_KEY_WORD);
208   }
209
210   private void addArtifactsToManifestFileDataList(
211       FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
212     Collection<String> forArtifacts = CollectionUtils
213         .union(filesDataStructure.getArtifacts(), filesDataStructure.getUnassigned());
214     if (CollectionUtils.isNotEmpty(forArtifacts)) {
215       for (String artifact : forArtifacts) {
216         if (isCloudSpecificArtifact(artifact)) {
217             fileDataList.add(createBaseFileData(FileData.Type.CLOUD_TECHNOLOGY_SPECIFIC_ARTIFACT, artifact));
218         } else if (isControllerBlueprintArchive(artifact)) {
219           fileDataList.add(createBaseFileData(FileData.Type.CONTROLLER_BLUEPRINT_ARCHIVE, artifact));
220         } else if (isHelm(artifact)) {
221           fileDataList.add(createBaseFileData(FileData.Type.HELM, artifact));
222         } else {
223           fileDataList.add(createBaseFileData(FileData.Type.OTHER, artifact));
224         }
225       }
226     }
227   }
228
229   private void addModulesToManifestFileDataList(
230       FilesDataStructure filesDataStructure, List<FileData> fileDataList) {
231     if (CollectionUtils.isNotEmpty(filesDataStructure.getModules())) {
232       for (Module module : filesDataStructure.getModules()) {
233         FileData.Type type = module.getType();
234         if (type == null) {
235           type = FileData.Type.HEAT;
236         }
237         FileData fileData = createBaseFileData(type, module.getYaml());
238         fileData.setBase(module.getIsBase());
239         addEnv(module, fileData);
240         addVolume(module, fileData);
241         fileDataList.add(fileData);
242       }
243     }
244   }
245
246   private void addEnv(Module module, FileData fileData) {
247     if (Objects.nonNull(module.getEnv())) {
248       FileData env = createBaseFileData(FileData.Type.HEAT_ENV, module.getEnv());
249       fileData.addFileData(env);
250     }
251   }
252
253   private void addVolume(Module module, FileData fileData) {
254     String volModule = module.getVol();
255     if (Objects.nonNull(volModule)) {
256       FileData vol = createBaseFileData(FileData.Type.HEAT_VOL, volModule);
257       if (Objects.nonNull(module.getVolEnv())) {
258         vol.addFileData(createBaseFileData(FileData.Type.HEAT_ENV, module.getVolEnv()));
259       }
260       fileData.addFileData(vol);
261     }
262   }
263
264   private FileData createBaseFileData(FileData.Type heat, String yaml) {
265     FileData fileData = new FileData();
266     fileData.setType(heat);
267     fileData.setFile(yaml);
268     return fileData;
269   }
270
271   private FileData createModuleFileData(
272       String moduleFileName, boolean isBase, Set<String> processedFiles,
273       Set<String> fileNames, List<FileData> fileDataList) {
274     FileData moduleFileData = createBasicFileData(moduleFileName, FileData.Type.HEAT, isBase);
275     Optional<String> volFile = fetchRelatedVolume(moduleFileName, fileNames);
276     volFile.ifPresent(vol -> {
277       markFileAsProcessed(vol, processedFiles);
278       removeFromFileDataListIfAlreadyProcessed(fileDataList, vol);
279       FileData volFileData = createBasicFileData(vol, FileData.Type.HEAT_VOL, null);
280       Optional<String> envFile = fetchRelatedEnv(vol, fileNames);
281       envFile.ifPresent(env -> {
282         markFileAsProcessed(env, processedFiles);
283         removeFromFileDataListIfAlreadyProcessed(fileDataList, env);
284         FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null);
285         volFileData.addFileData(envFileData);
286       });
287       moduleFileData.addFileData(volFileData);
288     });
289     Optional<String> envFile = fetchRelatedEnv(moduleFileName, fileNames);
290     envFile.ifPresent(env -> {
291       markFileAsProcessed(env, processedFiles);
292       FileData envFileData = createBasicFileData(env, FileData.Type.HEAT_ENV, null);
293       moduleFileData.addFileData(envFileData);
294     });
295     return moduleFileData;
296   }
297
298   private void removeFromFileDataListIfAlreadyProcessed(List<FileData> fileDataList, String vol) {
299     fileDataList.removeIf(fileData -> fileData.getFile().equals(vol));
300   }
301
302   private FileData createBasicFileData(String fileName, FileData.Type type, Boolean isBase) {
303     FileData fileData = new FileData();
304     if (isBase != null) {
305       fileData.setBase(isBase);
306     }
307     fileData.setType(type);
308     fileData.setFile(fileName);
309     return fileData;
310   }
311
312   private Optional<String> fetchRelatedEnv(String fileName, Set<String> fileNames) {
313     String envFileName
314         = fileName.substring(0, fileName.lastIndexOf(".")) + Constants.ENV_FILE_EXTENSION;
315     return fileNames.contains(envFileName) ? Optional.of(envFileName) : Optional.empty();
316   }
317
318   private Optional<String> fetchRelatedVolume(String fileName, Set<String> fileNames) {
319
320     String volFile1stExt =
321         extractVolFileName(fileName, ".yaml");
322     String volFile2ndExt =
323         extractVolFileName(fileName, ".yml");
324
325     if (fileNames.contains(volFile1stExt)) {
326       return Optional.of(volFile1stExt);
327     }
328     if (fileNames.contains(volFile2ndExt)) {
329       return Optional.of(volFile2ndExt);
330     }
331     return Optional.empty();
332   }
333
334   private String extractVolFileName(String fileName, String fileExt) {
335     return fileName.substring(
336         0, fileName.lastIndexOf("."))
337         + Constants.VOL_FILE_NAME_SUFFIX + fileExt;
338   }
339
340
341   private boolean isVolFile(String fileName) {
342     return fileName
343         .endsWith(
344             Constants.VOL_FILE_NAME_SUFFIX + ".yaml")
345         || fileName.endsWith(Constants.VOL_FILE_NAME_SUFFIX + ".yml");
346   }
347
348
349   private void markFileAsProcessed(String fileName, Set<String> processedFiles) {
350     processedFiles.add(fileName);
351   }
352 }