summaryrefslogtreecommitdiffstats
path: root/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java')
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java366
1 files changed, 366 insertions, 0 deletions
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
new file mode 100644
index 0000000000..64356ca7aa
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGeneratorImpl.java
@@ -0,0 +1,366 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2020 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.sdc.be.plugins.etsi.nfv.nsd.generator;
+
+import static org.openecomp.sdc.common.api.ArtifactTypeEnum.ETSI_PACKAGE;
+import static org.openecomp.sdc.common.api.ArtifactTypeEnum.ONBOARDED_PACKAGE;
+
+import fj.data.Either;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.io.output.ByteArrayOutputStream;
+import org.apache.commons.lang.StringUtils;
+import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao;
+import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus;
+import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.ComponentInstance;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdCsarManifestBuilder;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdToscaMetadataBuilder;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.Nsd;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
+import org.openecomp.sdc.be.resources.data.DAOArtifactData;
+import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+
+/**
+ * Implementation of a ETSI NFV NSD CSAR generator
+ */
+@org.springframework.stereotype.Component("etsiNfvNsdCsarGenerator")
+public class EtsiNfvNsdCsarGeneratorImpl implements EtsiNfvNsdCsarGenerator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(EtsiNfvNsdCsarGeneratorImpl.class);
+
+ private static final String MANIFEST_EXT = "mf";
+ private static final String SLASH = "/";
+ private static final String DOT = ".";
+ private static final String DOT_YAML = DOT + "yaml";
+
+ private static final String DEFINITION = "Definitions";
+ private static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta";
+
+ private final VnfDescriptorGenerator vnfDescriptorGenerator;
+ private final NsDescriptorGenerator nsDescriptorGeneratorImpl;
+ private final ArtifactCassandraDao artifactCassandraDao;
+
+ public EtsiNfvNsdCsarGeneratorImpl(final VnfDescriptorGenerator vnfDescriptorGenerator,
+ final NsDescriptorGenerator nsDescriptorGenerator,
+ final ArtifactCassandraDao artifactCassandraDao) {
+ this.vnfDescriptorGenerator = vnfDescriptorGenerator;
+ this.nsDescriptorGeneratorImpl = nsDescriptorGenerator;
+ this.artifactCassandraDao = artifactCassandraDao;
+ }
+
+ @Override
+ public byte[] generateNsdCsar(final Component component) throws NsdException {
+ if (component == null) {
+ throw new NsdException("Could not generate the NSD CSAR, invalid component argument");
+ }
+
+ loadComponentArtifacts(component);
+ loadComponentInstancesArtifacts(component);
+
+ final String componentName = component.getName();
+
+ try {
+ LOGGER.debug("Starting NSD CSAR generation for component '{}'", componentName);
+ final Map<String, byte[]> nsdCsarFiles = new HashMap<>();
+
+ final List<VnfDescriptor> vnfDescriptorList = generateVnfPackages(component);
+ vnfDescriptorList.forEach(vnfPackage -> nsdCsarFiles.putAll(vnfPackage.getDefinitionFiles()));
+
+ final String nsdFileName = getNsdFileName(component);
+ final Nsd nsd = generateNsd(component, vnfDescriptorList);
+ nsdCsarFiles.put(getNsdPath(nsdFileName), nsd.getContents());
+ nsdCsarFiles.put(TOSCA_META_PATH, buildToscaMetaContent(nsdFileName).getBytes());
+ addEtsiSolNsdTypes(nsdCsarFiles);
+ for (final String referencedFile : nsd.getArtifactReferences()) {
+ getReferencedArtifact(component, referencedFile).ifPresent(
+ artifactDefinition -> nsdCsarFiles.put(referencedFile, artifactDefinition.getPayloadData())
+ );
+ }
+ nsdCsarFiles
+ .put(getManifestPath(nsdFileName), getManifestFileContent(nsd, nsdCsarFiles.keySet()).getBytes());
+
+ final byte[] csar = buildCsarPackage(nsdCsarFiles);
+ LOGGER.debug("Successfully generated NSD CSAR package");
+ return csar;
+ } catch (final Exception exception) {
+ throw new NsdException("Could not generate the NSD CSAR file", exception);
+ }
+ }
+
+ private void loadComponentArtifacts(final Component component) {
+ final Map<String, ArtifactDefinition> allArtifactsMap = component.getAllArtifacts();
+ if (allArtifactsMap == null) {
+ return;
+ }
+ allArtifactsMap.keySet().forEach(key -> {
+ final ArtifactDefinition artifactDefinition = allArtifactsMap.get(key);
+ if (StringUtils.isNotEmpty(artifactDefinition.getEsId())) {
+ final Optional<byte[]> artifactPayload = loadArtifactPayload(artifactDefinition.getEsId());
+ if (artifactPayload.isPresent()) {
+ artifactDefinition.setPayload(artifactPayload.get());
+ } else {
+ LOGGER.warn("Could not load component '{}' artifact '{}'",
+ component.getName(), artifactDefinition.getArtifactName());
+ }
+ }
+ });
+ }
+
+ private void loadComponentInstancesArtifacts(final Component component) {
+ final List<ComponentInstance> componentInstanceList = component.getComponentInstances();
+ if (CollectionUtils.isEmpty(componentInstanceList)) {
+ return;
+ }
+ for (final ComponentInstance componentInstance : componentInstanceList) {
+ final Map<String, ArtifactDefinition> deploymentArtifacts = componentInstance.getDeploymentArtifacts();
+ if (MapUtils.isEmpty(deploymentArtifacts)) {
+ continue;
+ }
+ deploymentArtifacts.values().stream()
+ .filter(artifactDefinition -> StringUtils.isNotEmpty(artifactDefinition.getEsId()))
+ .forEach(artifactDefinition -> {
+ final Optional<byte[]> artifactPayload = loadArtifactPayload(artifactDefinition.getEsId());
+ if (artifactPayload.isPresent()) {
+ artifactDefinition.setPayload(artifactPayload.get());
+ } else {
+ LOGGER.warn("Could not load component '{}' instance '{}' artifact '{}'",
+ component.getName(), componentInstance.getName(), artifactDefinition.getArtifactName());
+ }
+ });
+ }
+ }
+
+ private List<VnfDescriptor> generateVnfPackages(final Component component) throws NsdException {
+ final List<ComponentInstance> componentInstanceList = component.getComponentInstances();
+ if (CollectionUtils.isEmpty(componentInstanceList)) {
+ LOGGER.warn("Could not find any instance in service '{}'", component.getName());
+ return Collections.emptyList();
+ }
+
+ final List<VnfDescriptor> vnfDescriptorList = new ArrayList<>();
+ for (final ComponentInstance componentInstance : componentInstanceList) {
+ final String componentInstanceName = componentInstance.getName();
+ final ArtifactDefinition onboardedCsarArtifact = findOnboardedCsar(componentInstance).orElse(null);
+ if (onboardedCsarArtifact == null) {
+ LOGGER.warn(
+ "Unable to generate VNF Package for component instance '{}', no onboarded package present",
+ componentInstanceName);
+ continue;
+ }
+ final Optional<VnfDescriptor> vnfPackage;
+ try {
+ vnfPackage = vnfDescriptorGenerator.generate(componentInstanceName, onboardedCsarArtifact);
+ } catch (final Exception e) {
+ final String errorMsg =
+ String.format("Could not generate VNF package for component instance %s", componentInstanceName);
+ throw new NsdException(errorMsg, e);
+ }
+ if (vnfPackage.isPresent()) {
+ vnfDescriptorList.add(vnfPackage.get());
+ } else {
+ LOGGER.warn(
+ "Unable to generate VNF Package for component instance '{}', no onboarded package present",
+ componentInstanceName);
+ }
+ }
+
+ return vnfDescriptorList;
+ }
+
+ private Optional<ArtifactDefinition> findOnboardedCsar(final ComponentInstance componentInstance) {
+ final Map<String, ArtifactDefinition> artifactDefinitionMap = componentInstance.getDeploymentArtifacts();
+ if (artifactDefinitionMap == null || artifactDefinitionMap.isEmpty()) {
+ return Optional.empty();
+ }
+ return artifactDefinitionMap.values()
+ .stream()
+ .filter(artifactDefinition -> {
+ final String artifactType = (String) artifactDefinition
+ .getToscaPresentationValue(JsonPresentationFields.ARTIFACT_TYPE);
+ return ONBOARDED_PACKAGE.getType().equals(artifactType) || ETSI_PACKAGE.getType().equals(artifactType);
+ })
+ .findFirst();
+ }
+
+ private void addEtsiSolNsdTypes(final Map<String, byte[]> nsdCsarFileMap) {
+ final Path baseFolderPath = Paths.get("etsi-nfv-types");
+ String nsdTypesFilename = "etsi_nfv_sol001_nsd_2_7_1_types.yaml";
+
+ try {
+ final Resource resource =
+ new ClassPathResource(Paths.get(baseFolderPath.toString(), nsdTypesFilename).toString());
+ nsdCsarFileMap.put(DEFINITION + "/" + nsdTypesFilename,
+ IOUtils.toByteArray(resource.getInputStream()));
+ } catch (final IOException exception) {
+ LOGGER.error("Error adding {} to NSD CSAR", nsdTypesFilename, exception);
+ }
+
+ String commonTypesFilename = "etsi_nfv_sol001_common_types.yaml";
+ try {
+ final Resource resource =
+ new ClassPathResource(Paths.get(baseFolderPath.toString(), commonTypesFilename).toString());
+ nsdCsarFileMap.put(DEFINITION + "/" + commonTypesFilename,
+ IOUtils.toByteArray(resource.getInputStream()));
+ } catch (final IOException exception) {
+ LOGGER.error("Error adding {} to NSD CSAR", commonTypesFilename, exception);
+ }
+ }
+
+ private Nsd generateNsd(final Component component,
+ final List<VnfDescriptor> vnfDescriptorList) throws NsdException {
+ return nsDescriptorGeneratorImpl.generate(component, vnfDescriptorList)
+ .orElseThrow(() ->
+ new NsdException(String
+ .format("Could not generate the Network Service Descriptor for component %s", component.getName()))
+ );
+ }
+
+ private Optional<ArtifactDefinition> getReferencedArtifact(final Component component,
+ final String filePath) throws NsdException {
+ final Map<String, ArtifactDefinition> interfaceOperationArtifactsByName =
+ OperationArtifactUtil.getDistinctInterfaceOperationArtifactsByName(component);
+ final String[] pathComponents = filePath.split(SLASH);
+ final String artifactName = pathComponents[pathComponents.length - 1];
+ final ArtifactDefinition artifactDefinition = interfaceOperationArtifactsByName.get(artifactName);
+ if (artifactDefinition == null) {
+ throw new NsdException(String.format("Could not find artifact '%s'", filePath));
+ }
+ LOGGER.debug("ArtifactName {}, unique ID {}", artifactDefinition.getArtifactName(),
+ artifactDefinition.getUniqueId());
+ if (artifactDefinition.getPayloadData() == null) {
+ final Optional<byte[]> artifactPayload = loadArtifactPayload(artifactDefinition.getEsId());
+
+ if (!artifactPayload.isPresent()) {
+ throw new NsdException(String.format("Could not load artifact '%s' payload", filePath));
+ }
+ artifactDefinition.setPayload(artifactPayload.get());
+ }
+
+ return Optional.of(artifactDefinition);
+ }
+
+ private Optional<byte[]> loadArtifactPayload(final String artifactCassandraId) {
+ final Either<DAOArtifactData, CassandraOperationStatus> artifactResponse = artifactCassandraDao
+ .getArtifact(artifactCassandraId);
+
+ if (artifactResponse.isRight()) {
+ LOGGER.debug("Failed to fetch artifact from Cassandra by id {} error {} ", artifactCassandraId,
+ artifactResponse.right().value());
+ return Optional.empty();
+ }
+ final DAOArtifactData artifactData = artifactResponse.left().value();
+ return Optional.of(artifactData.getDataAsArray());
+ }
+
+ private String buildToscaMetaContent(final String nsdFileName) {
+ LOGGER.debug("Creating TOSCA.meta content");
+ final NsdToscaMetadataBuilder builder = new NsdToscaMetadataBuilder();
+
+ builder.withCsarVersion("1.1")
+ .withCreatedBy("ONAP")
+ .withToscaMetaVersion("1.0")
+ .withEntryDefinitions(getNsdPath(nsdFileName))
+ .withEntryManifest(getManifestPath(nsdFileName))
+ .withEntryChangeLog("ChangeLog.txt");
+
+ final String toscaMetadata = builder.build();
+ LOGGER.debug("Successfully created NS CSAR TOSCA.meta content:\n {}", toscaMetadata);
+ return toscaMetadata;
+ }
+
+ private String getManifestFileContent(final Nsd nsd, final Set<String> files) {
+ LOGGER.debug("Creating NS manifest file content");
+
+ final NsdCsarManifestBuilder nsdCsarManifestBuilder = new NsdCsarManifestBuilder();
+ nsdCsarManifestBuilder.withDesigner(nsd.getDesigner())
+ .withInvariantId(nsd.getInvariantId())
+ .withName(nsd.getName())
+ .withNowReleaseDateTime()
+ .withFileStructureVersion(nsd.getVersion())
+ .withSources(files);
+
+ final String manifest = nsdCsarManifestBuilder.build();
+ LOGGER.debug("Successfully created NS CSAR manifest file content:\n {}", manifest);
+ return manifest;
+
+ }
+
+ private String getManifestPath(final String nsdFileName) {
+ return nsdFileName + DOT + MANIFEST_EXT;
+ }
+
+ private String getNsdPath(final String nsdFileName) {
+ return DEFINITION + SLASH + nsdFileName + DOT_YAML;
+ }
+
+ private String getNsdFileName(final Component component) {
+ return component.getNormalizedName();
+ }
+
+ private byte[] buildCsarPackage(final Map<String, byte[]> nsdCsarFileMap) throws NsdException {
+ if (nsdCsarFileMap.isEmpty()) {
+ throw new NsdException("No files were provided to build the NSD CSAR package");
+ }
+ try (final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ final ZipOutputStream zip = new ZipOutputStream(out)) {
+ for (final Entry<String, byte[]> entry : nsdCsarFileMap.entrySet()) {
+ final String filePath = entry.getKey();
+ final byte[] fileContent = entry.getValue();
+ if (fileContent == null) {
+ LOGGER.error("Could not add '{}' to NSD CSAR. File content is null", filePath);
+ continue;
+ }
+ LOGGER.debug("Adding '{}' to NSD CSAR with content size: '{}'", filePath, fileContent.length);
+ zip.putNextEntry(new ZipEntry(filePath));
+ zip.write(fileContent);
+ }
+ zip.flush();
+ zip.finish();
+ LOGGER.debug("NSD CSAR zip file was successfully built");
+
+ return out.toByteArray();
+ } catch (final IOException e) {
+ throw new NsdException("Could not build the NSD CSAR zip file", e);
+ }
+ }
+
+}