2547b1f738381c3fcb1764276c40eb17ac3e74e6
[sdc.git] / catalog-be-plugins / etsi-nfv-nsd-csar-plugin / src / main / java / org / openecomp / sdc / be / plugins / etsi / nfv / nsd / generator / VnfDescriptorGeneratorImpl.java
1 /*
2  * ============LICENSE_START=======================================================
3  *  Copyright (C) 2020 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.be.plugins.etsi.nfv.nsd.generator;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.nio.charset.StandardCharsets;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Map.Entry;
32 import java.util.Optional;
33 import java.util.stream.Collectors;
34 import org.apache.commons.collections.MapUtils;
35 import org.apache.commons.io.FilenameUtils;
36 import org.apache.commons.io.IOUtils;
37 import org.onap.sdc.tosca.services.YamlUtil;
38 import org.openecomp.core.utilities.file.FileContentHandler;
39 import org.openecomp.core.utilities.file.FileUtils;
40 import org.openecomp.sdc.be.csar.storage.StorageFactory;
41 import org.openecomp.sdc.be.model.ArtifactDefinition;
42 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdToscaMetadataBuilder;
43 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.VnfDescriptorException;
44 import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import org.springframework.stereotype.Component;
48 import org.yaml.snakeyaml.Yaml;
49
50 /**
51  * Implementation of a VNF Descriptor Generator
52  */
53 @Component("vnfPackageGenerator")
54 public class VnfDescriptorGeneratorImpl implements VnfDescriptorGenerator {
55
56     private static final Logger LOGGER = LoggerFactory.getLogger(VnfDescriptorGeneratorImpl.class);
57     private static final String SPACE_REGEX = "\\s+";
58     private static final String CSAR = "csar";
59     private static final String COLON = ":";
60     private static final String EMPTY_STRING = "";
61     private static final String SLASH = "/";
62     private static final String DEFINITIONS_DIRECTORY = "Definitions";
63     private static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta";
64
65     private static boolean isACsarArtifact(final ArtifactDefinition definition) {
66         return definition.getPayloadData() != null && definition.getArtifactName() != null
67                 && CSAR.equalsIgnoreCase(FilenameUtils.getExtension(definition.getArtifactName()));
68     }
69
70     public Optional<VnfDescriptor> generate(final String name, final ArtifactDefinition onboardedPackageArtifact) throws VnfDescriptorException {
71         if (!isACsarArtifact(onboardedPackageArtifact)) {
72             return Optional.empty();
73         }
74         final FileContentHandler fileContentHandler;
75         try {
76             final var artifactStorageManager = new StorageFactory().createArtifactStorageManager();
77             final byte[] payloadData = onboardedPackageArtifact.getPayloadData();
78             if (artifactStorageManager.isEnabled()) {
79                 final var inputStream =
80                         artifactStorageManager.get(getFromPayload(payloadData, "bucket"), getFromPayload(payloadData, "object") + ".reduced");
81                 fileContentHandler = FileUtils.getFileContentMapFromZip(inputStream);
82             } else {
83                 fileContentHandler = FileUtils.getFileContentMapFromZip(new ByteArrayInputStream(payloadData));
84             }
85         } catch (final IOException e) {
86             final String errorMsg = String.format("Could not unzip artifact '%s' content", onboardedPackageArtifact.getArtifactName());
87             throw new VnfDescriptorException(errorMsg, e);
88         }
89         if (MapUtils.isEmpty(fileContentHandler.getFiles())) {
90             return Optional.empty();
91         }
92         final String mainDefinitionFile;
93         try {
94             mainDefinitionFile = getMainFilePathFromMetaFile(fileContentHandler).orElse(null);
95         } catch (final IOException e) {
96             final String errorMsg = String.format("Could not read main definition file of artifact '%s'", onboardedPackageArtifact.getArtifactName());
97             throw new VnfDescriptorException(errorMsg, e);
98         }
99         LOGGER.debug("found main file: {}", mainDefinitionFile);
100         if (mainDefinitionFile == null) {
101             return Optional.empty();
102         }
103         final var vnfDescriptor = new VnfDescriptor();
104         vnfDescriptor.setName(name);
105         final String vnfdFileName = FilenameUtils.getName(mainDefinitionFile);
106         vnfDescriptor.setVnfdFileName(vnfdFileName);
107         vnfDescriptor.setDefinitionFiles(getFiles(fileContentHandler, mainDefinitionFile));
108         vnfDescriptor.setNodeType(getNodeType(getFileContent(fileContentHandler, mainDefinitionFile)));
109         return Optional.of(vnfDescriptor);
110     }
111
112     private String getFromPayload(final byte[] payload, final String name) {
113         final String[] strings = new String(payload).split("\n");
114         for (final String str : strings) {
115             if (str.contains(name)) {
116                 return str.split(": ")[1];
117             }
118         }
119         return "";
120     }
121
122     private Map<String, byte[]> getFiles(final FileContentHandler fileContentHandler, final String filePath) {
123         final Map<String, byte[]> files = new HashMap<>();
124         final byte[] fileContent = fileContentHandler.getFileContent(filePath);
125         if (fileContent != null) {
126             final String mainYmlFile = new String(fileContent);
127             LOGGER.debug("file content: {}", mainYmlFile);
128             files.put(appendDefinitionDirPath(filePath.substring(filePath.lastIndexOf(SLASH) + 1)), getVnfdAmendedForInclusionInNsd(fileContent));
129             final List<Object> imports = getImportFilesPath(mainYmlFile);
130             LOGGER.info("found imports {}", imports);
131             for (final Object importObject : imports) {
132                 if (importObject != null) {
133                     final String importFilename = importObject.toString();
134                     final String importFileFullPath = appendDefinitionDirPath(importFilename);
135                     final byte[] importFileContent = fileContentHandler.getFileContent(importFileFullPath);
136                     files.put(appendDefinitionDirPath(importFilename), importFileContent);
137                 }
138             }
139         }
140         return files;
141     }
142
143     private String getFileContent(final FileContentHandler fileContentHandler, final String filePath) {
144         final byte[] fileContent = fileContentHandler.getFileContent(filePath);
145         if (fileContent != null) {
146             return new String(fileContent);
147         }
148         return null;
149     }
150
151     private Optional<String> getMainFilePathFromMetaFile(final FileContentHandler fileContentHandler) throws IOException {
152         final Map<String, String> metaFileContent = getMetaFileContent(fileContentHandler);
153         final String mainFile = metaFileContent.get(NsdToscaMetadataBuilder.ENTRY_DEFINITIONS);
154         if (mainFile != null) {
155             return Optional.of(mainFile.replaceAll(SPACE_REGEX, EMPTY_STRING));
156         }
157         LOGGER.error("{} entry not found in {}", NsdToscaMetadataBuilder.ENTRY_DEFINITIONS, TOSCA_META_PATH);
158         return Optional.empty();
159     }
160
161     private Map<String, String> getMetaFileContent(final FileContentHandler fileContentHandler) throws IOException {
162         final InputStream inputStream = fileContentHandler.getFileContentAsStream(TOSCA_META_PATH);
163         if (inputStream == null) {
164             throw new FileNotFoundException("Unable find " + TOSCA_META_PATH + " file");
165         }
166         final List<String> lines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
167         return lines.stream().map(str -> str.split(COLON)).collect(Collectors.toMap(str -> str[0], str -> str.length > 1 ? str[1] : EMPTY_STRING));
168     }
169
170     private String appendDefinitionDirPath(final String filename) {
171         return DEFINITIONS_DIRECTORY + SLASH + filename;
172     }
173
174     private List<Object> getImportFilesPath(final String mainYmlFile) {
175         final Map<Object, Object> fileContentMap = new YamlUtil().yamlToObject(mainYmlFile, Map.class);
176         final Object importsObject = fileContentMap.get("imports");
177         if (importsObject instanceof List) {
178             return (List<Object>) importsObject;
179         }
180         return Collections.emptyList();
181     }
182
183     private byte[] getVnfdAmendedForInclusionInNsd(final byte[] vnfdFileContent) {
184         final Yaml yaml = new Yaml();
185         final Map<String, Object> toscaFileContent = (Map<String, Object>) yaml.load(new String(vnfdFileContent));
186         toscaFileContent.remove("topology_template");
187         removeInterfacesFromNodeTypes(toscaFileContent);
188         return yaml.dumpAsMap(toscaFileContent).getBytes();
189     }
190
191     private void removeInterfacesFromNodeTypes(final Map<String, Object> toscaFileContent) {
192         final Map<String, Object> nodeTypes = (Map<String, Object>) toscaFileContent.get("node_types");
193         if (nodeTypes != null) {
194             for (Entry<String, Object> nodeType : nodeTypes.entrySet()) {
195                 if (nodeType.getValue() != null && nodeType.getValue() instanceof Map) {
196                     ((Map<String, Object>) nodeType.getValue()).remove("interfaces");
197                 }
198             }
199         }
200     }
201
202     private String getNodeType(final String mainYmlFile) {
203         final Map<Object, Object> fileContentMap = new YamlUtil().yamlToObject(mainYmlFile, Map.class);
204         final Object nodeTypesObject = fileContentMap.get("node_types");
205         if (nodeTypesObject instanceof Map && ((Map<String, Object>) nodeTypesObject).size() == 1) {
206             return ((Map<String, Object>) nodeTypesObject).keySet().iterator().next();
207         }
208         return null;
209     }
210 }