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