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
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.
16 * SPDX-License-Identifier: Apache-2.0
17 * ============LICENSE_END=========================================================
19 package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator;
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;
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;
49 * Implementation of a VNF Descriptor Generator
51 @Component("vnfPackageGenerator")
52 public class VnfDescriptorGeneratorImpl implements VnfDescriptorGenerator {
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";
63 private static boolean isACsarArtifact(final ArtifactDefinition definition) {
64 return definition.getPayloadData() != null && definition.getArtifactName() != null && CSAR
65 .equalsIgnoreCase(FilenameUtils.getExtension(definition.getArtifactName()));
68 public Optional<VnfDescriptor> generate(final String name, final ArtifactDefinition onboardedPackageArtifact) throws VnfDescriptorException {
69 if (!isACsarArtifact(onboardedPackageArtifact)) {
70 return Optional.empty();
72 final FileContentHandler fileContentHandler;
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);
81 fileContentHandler = FileUtils.getFileContentMapFromZip(new ByteArrayInputStream(payloadData));
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);
87 if (MapUtils.isEmpty(fileContentHandler.getFiles())) {
88 return Optional.empty();
90 final String mainDefinitionFile;
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);
98 LOGGER.debug("found main file: {}", mainDefinitionFile);
99 if (mainDefinitionFile == null) {
100 return Optional.empty();
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);
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];
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);
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);
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));
156 LOGGER.error("{} entry not found in {}", NsdToscaMetadataBuilder.ENTRY_DEFINITIONS, TOSCA_META_PATH);
157 return Optional.empty();
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");
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));
169 private String appendDefinitionDirPath(final String filename) {
170 return DEFINITIONS_DIRECTORY + SLASH + filename;
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;
179 return Collections.emptyList();
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();
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();