aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins
diff options
context:
space:
mode:
authorandre.schmid <andre.schmid@est.tech>2020-08-21 11:40:56 +0100
committerSébastien Determe <sebastien.determe@intl.att.com>2020-09-07 08:06:05 +0000
commit4188b20055dac1974f6c6f1a6a8320099b154ca5 (patch)
tree85e8b0b4a00dc78cddc163625564bcb198e21799 /catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins
parent798f858d18403a31a4d464b07bb1a9a74666c9c7 (diff)
Plugin to Generate Service ETSI NSD CSAR
Create a catalog backend plugin to generate an ETSI compliant Network Service Descriptor (NSD) CSAR as an artifact in the generated TOSCA CSAR package of a Service. Change-Id: I2b1556148be39d7bf37602335e638d0cee2b291b Issue-ID: SDC-3251 Signed-off-by: andre.schmid <andre.schmid@est.tech>
Diffstat (limited to 'catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins')
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java163
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdToscaMetadataBuilder.java133
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/NsdException.java34
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/VnfDescriptorException.java30
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java95
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java38
-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
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGenerator.java39
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java411
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGenerator.java43
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGeneratorImpl.java202
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/Nsd.java89
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/VnfDescriptor.java67
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/NsdTemplateRepresenter.java129
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/ToscaTemplateYamlGenerator.java73
-rw-r--r--catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/UnsortedPropertyUtils.java39
16 files changed, 1951 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/builder/NsdCsarManifestBuilder.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java
new file mode 100644
index 0000000000..6dc120290c
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdCsarManifestBuilder.java
@@ -0,0 +1,163 @@
+/*
+ * ============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.builder;
+
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+
+/**
+ * Builder for the manifest (.mf) file in a NSD CSAR
+ */
+public class NsdCsarManifestBuilder {
+ private static final String METADATA = "metadata";
+ private static final String SOURCE = "Source";
+ private static final String NSD_DESIGNER = "nsd_designer";
+ private static final String NSD_FILE_STRUCTURE_VERSION = "nsd_file_structure_version";
+ private static final String NSD_RELEASE_DATE_TIME = "nsd_release_date_time";
+ private static final String NSD_NAME = "nsd_name";
+ private static final String NSD_INVARIANT_ID = "nsd_invariant_id";
+ private static final String ATTRIBUTE_SEPARATOR = ": ";
+ private static final String NEW_LINE = "\n";
+ private static final DateTimeFormatter RFC_3339_DATE_TIME_FORMATTER =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ");
+
+ private final StringBuilder builder;
+ private final StringBuilder metadataBuilder;
+ private final StringBuilder sourceBuilder;
+ private final MetadataHeader metadataHeader;
+ private final HashSet<String> sources;
+
+ public NsdCsarManifestBuilder() {
+ builder = new StringBuilder();
+ metadataBuilder = new StringBuilder();
+ sourceBuilder = new StringBuilder();
+ metadataHeader = new MetadataHeader();
+ sources = new LinkedHashSet<>();
+ metadataBuilder.append(METADATA).append(ATTRIBUTE_SEPARATOR)
+ .append(NEW_LINE);
+ }
+
+ /**
+ * Sets a value for the {@link #NSD_DESIGNER} manifest entry.
+ *
+ * @param designer the value
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withDesigner(final String designer) {
+ metadataHeader.designer = designer;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #NSD_INVARIANT_ID} manifest entry.
+ *
+ * @param invariantId the value
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withInvariantId(final String invariantId) {
+ metadataHeader.invariantId = invariantId;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #NSD_NAME} manifest entry.
+ *
+ * @param nsdName the value
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withName(final String nsdName) {
+ metadataHeader.nsdName = nsdName;
+ return this;
+ }
+
+ /**
+ * Sets the current date time to the {@link #NSD_RELEASE_DATE_TIME} manifest entry.
+ *
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withNowReleaseDateTime() {
+ metadataHeader.nsdReleaseDateTime = getNowDateTime();
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #NSD_FILE_STRUCTURE_VERSION} manifest entry.
+ *
+ * @param fileStructureVersion the value
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withFileStructureVersion(final String fileStructureVersion) {
+ metadataHeader.fileStructureVersion = fileStructureVersion;
+ return this;
+ }
+
+ /**
+ * Add a list of {@link #SOURCE} entries to the manifest
+ *
+ * @param sources a list of source path
+ * @return the builder instance
+ */
+ public NsdCsarManifestBuilder withSources(final Collection<String> sources) {
+ this.sources.addAll(sources);
+ return this;
+ }
+
+ /**
+ * Builds a string representing the manifest content based on provided values.
+ *
+ * @return a string representing the manifest content
+ */
+ public String build() {
+ appendEntry(metadataBuilder, NSD_DESIGNER, metadataHeader.designer);
+ appendEntry(metadataBuilder, NSD_INVARIANT_ID, metadataHeader.invariantId);
+ appendEntry(metadataBuilder, NSD_NAME, metadataHeader.nsdName);
+ appendEntry(metadataBuilder, NSD_RELEASE_DATE_TIME, metadataHeader.nsdReleaseDateTime);
+ appendEntry(metadataBuilder, NSD_FILE_STRUCTURE_VERSION, metadataHeader.fileStructureVersion);
+ sources.forEach(source -> appendEntry(sourceBuilder, SOURCE, source));
+
+ builder.append(metadataBuilder)
+ .append(NEW_LINE)
+ .append(sourceBuilder);
+ return builder.toString();
+ }
+
+ private String getNowDateTime() {
+ return ZonedDateTime.now().format(RFC_3339_DATE_TIME_FORMATTER);
+ }
+
+ private void appendEntry(final StringBuilder builder, final String entry, final String value) {
+ if (value != null) {
+ builder.append(entry).append(ATTRIBUTE_SEPARATOR).append(value)
+ .append(NEW_LINE);
+ }
+ }
+
+ private class MetadataHeader {
+ private String fileStructureVersion;
+ private String nsdName;
+ private String nsdReleaseDateTime;
+ private String designer;
+ private String invariantId;
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdToscaMetadataBuilder.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdToscaMetadataBuilder.java
new file mode 100644
index 0000000000..e709993b45
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/builder/NsdToscaMetadataBuilder.java
@@ -0,0 +1,133 @@
+/*
+ * ============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.builder;
+
+/**
+ * Builder for the TOSCA.meta file in a NSD CSAR
+ */
+public class NsdToscaMetadataBuilder {
+
+ public static final String CSAR_VERSION = "CSAR-Version";
+ public static final String CREATED_BY = "Created-By";
+ public static final String TOSCA_META_FILE_VERSION = "TOSCA-Meta-File-Version";
+ public static final String ENTRY_DEFINITIONS = "Entry-Definitions";
+ public static final String ETSI_ENTRY_CHANGE_LOG = "ETSI-Entry-Change-Log";
+ public static final String ETSI_ENTRY_MANIFEST = "ETSI-Entry-Manifest";
+
+ private static final String ATTRIBUTE_SEPARATOR = ": ";
+ private static final String NEW_LINE = "\n";
+
+ private final StringBuilder builder = new StringBuilder();
+ private String csarVersion;
+ private String createdBy;
+ private String entryDefinitionsPath;
+ private String toscaMetaVersion;
+ private String entryManifest;
+ private String changeLogPath;
+
+ /**
+ * Sets a value for the {@link #CSAR_VERSION} metadata entry.
+ *
+ * @param csarVersion the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withCsarVersion(final String csarVersion) {
+ this.csarVersion = csarVersion;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #CREATED_BY} metadata entry.
+ *
+ * @param createdBy the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withCreatedBy(final String createdBy) {
+ this.createdBy = createdBy;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #TOSCA_META_FILE_VERSION} metadata entry.
+ *
+ * @param toscaMetaVersion the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withToscaMetaVersion(final String toscaMetaVersion) {
+ this.toscaMetaVersion = toscaMetaVersion;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #ENTRY_DEFINITIONS} metadata entry.
+ *
+ * @param entryDefinitionsPath the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withEntryDefinitions(final String entryDefinitionsPath) {
+ this.entryDefinitionsPath = entryDefinitionsPath;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #ETSI_ENTRY_MANIFEST} metadata entry.
+ *
+ * @param entryManifest the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withEntryManifest(final String entryManifest) {
+ this.entryManifest = entryManifest;
+ return this;
+ }
+
+ /**
+ * Sets a value for the {@link #ETSI_ENTRY_CHANGE_LOG} metadata entry.
+ *
+ * @param changeLogPath the value
+ * @return the builder instance
+ */
+ public NsdToscaMetadataBuilder withEntryChangeLog(final String changeLogPath) {
+ this.changeLogPath = changeLogPath;
+ return this;
+ }
+
+ /**
+ * Builds a string representing the TOSCA metadata content based on provided values.
+ *
+ * @return a string representing the TOSCA metadata content
+ */
+ public String build() {
+ appendEntry(CSAR_VERSION, csarVersion);
+ appendEntry(CREATED_BY, createdBy);
+ appendEntry(TOSCA_META_FILE_VERSION, toscaMetaVersion);
+ appendEntry(ENTRY_DEFINITIONS, entryDefinitionsPath);
+ appendEntry(ETSI_ENTRY_MANIFEST, entryManifest);
+ appendEntry(ETSI_ENTRY_CHANGE_LOG, changeLogPath);
+ return builder.toString();
+ }
+
+ private void appendEntry(final String entry, final String value) {
+ if (value != null) {
+ builder.append(entry).append(ATTRIBUTE_SEPARATOR).append(value)
+ .append(NEW_LINE);
+ }
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/NsdException.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/NsdException.java
new file mode 100644
index 0000000000..2483b2ebe0
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/NsdException.java
@@ -0,0 +1,34 @@
+/*
+ * ============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.exception;
+
+/**
+ * Represents any problem during the NSD CSAR generation.
+ */
+public class NsdException extends Exception {
+
+ public NsdException(final String s) {
+ super(s);
+ }
+
+ public NsdException(final String s, final Throwable throwable) {
+ super(s, throwable);
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/VnfDescriptorException.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/VnfDescriptorException.java
new file mode 100644
index 0000000000..e4f966fea3
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/exception/VnfDescriptorException.java
@@ -0,0 +1,30 @@
+/*
+ * ============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.exception;
+
+/**
+ * Represents any problem during the Vnf Descriptor generation.
+ */
+public class VnfDescriptorException extends Exception {
+
+ public VnfDescriptorException(final String s, final Throwable throwable) {
+ super(s, throwable);
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java
new file mode 100644
index 0000000000..00aef05ed7
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsCsarEntryGenerator.java
@@ -0,0 +1,95 @@
+/*
+ * ============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 java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.plugins.CsarEntryGenerator;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Generates a Network Service CSAR based on a SERVICE component and wraps it in a SDC CSAR entry.
+ */
+@org.springframework.stereotype.Component("etsiNfvNsCsarEntryGenerator")
+public class EtsiNfvNsCsarEntryGenerator implements CsarEntryGenerator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(EtsiNfvNsCsarEntryGenerator.class);
+ static final String ETSI_NS_COMPONENT_CATEGORY = "ETSI Network Service";
+ static final String NSD_FILE_PATH_FORMAT = "Artifacts/%s/%s.csar";
+
+ private final EtsiNfvNsdCsarGenerator etsiNfvNsdCsarGenerator;
+
+ public EtsiNfvNsCsarEntryGenerator(final EtsiNfvNsdCsarGenerator etsiNfvNsdCsarGenerator) {
+ this.etsiNfvNsdCsarGenerator = etsiNfvNsdCsarGenerator;
+ }
+
+ /**
+ * Generates a Network Service CSAR based on a SERVICE component of category {@link
+ * EtsiNfvNsCsarEntryGenerator#ETSI_NS_COMPONENT_CATEGORY} and wraps it in a SDC CSAR entry.
+ *
+ * @param component the component to create the NS CSAR from
+ * @return an entry to be added in the Component CSAR by SDC
+ */
+ @Override
+ public Map<String, byte[]> generateCsarEntries(final Component component) {
+ final String componentName = component == null ? "null" : component.getName();
+ if (component == null || ComponentTypeEnum.SERVICE != component.getComponentType()) {
+ LOGGER.debug("Ignoring NSD CSAR generation for component '{}' as it is not a SERVICE", componentName);
+ return Collections.emptyMap();
+ }
+
+ final boolean isEOTemplate = component.getCategories().stream()
+ .anyMatch(category -> ETSI_NS_COMPONENT_CATEGORY.equals(category.getName()));
+ if (!isEOTemplate) {
+ LOGGER.debug("Ignoring NSD CSAR generation for component '{}' as it does not belong to the category '{}'",
+ componentName, ETSI_NS_COMPONENT_CATEGORY);
+ return Collections.emptyMap();
+ }
+
+ final byte[] nsdCsar;
+ try {
+ nsdCsar = etsiNfvNsdCsarGenerator.generateNsdCsar(component);
+ } catch (final NsdException e) {
+ LOGGER.error("Could not create NSD CSAR entry for component '{}'"
+ , component.getName(), e);
+ return Collections.emptyMap();
+ } catch (final Exception e) {
+ LOGGER.error("Could not create NSD CSAR entry for component '{}'. An unexpected exception occurred"
+ , component.getName(), e);
+ return Collections.emptyMap();
+ }
+
+ return createEntry(component.getNormalizedName(), nsdCsar);
+ }
+
+ private Map<String, byte[]> createEntry(final String csarName, final byte[] nsdCsar) {
+ final Map<String, byte[]> entryMap = new HashMap<>();
+ final String entryKey = String.format(NSD_FILE_PATH_FORMAT, ETSI_PACKAGE, csarName);
+ entryMap.put(entryKey, nsdCsar);
+ return entryMap;
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java
new file mode 100644
index 0000000000..f9ee55eecf
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/EtsiNfvNsdCsarGenerator.java
@@ -0,0 +1,38 @@
+/*
+ * ============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 org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.NsdException;
+
+/**
+ * Generator for a ETSI NFV NSD CSAR
+ */
+public interface EtsiNfvNsdCsarGenerator {
+
+ /**
+ * Generates the ETSI NFV Network Service Descriptor based on a SERVICE SDC component.
+ *
+ * @param component the service component
+ * @return the CSAR package content
+ */
+ byte[] generateNsdCsar(Component component) throws NsdException;
+
+}
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);
+ }
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGenerator.java
new file mode 100644
index 0000000000..d36757cf48
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGenerator.java
@@ -0,0 +1,39 @@
+/*
+ * ============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 java.util.List;
+import java.util.Optional;
+import org.openecomp.sdc.be.model.Component;
+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;
+
+public interface NsDescriptorGenerator {
+
+ /**
+ * Generates the TOSCA Network Service Descriptor (NSD) based on a SERVICE SDC component and its VNF instances.
+ *
+ * @param component the SERVICE component
+ * @param vnfDescriptorList the VNF instances
+ * @return a NSD representation
+ */
+ Optional<Nsd> generate(final Component component, final List<VnfDescriptor> vnfDescriptorList) throws NsdException;
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java
new file mode 100644
index 0000000000..0c8b86b5e7
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/NsDescriptorGeneratorImpl.java
@@ -0,0 +1,411 @@
+/*
+ * ============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 com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import fj.data.Either;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+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 org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.openecomp.sdc.be.config.ConfigurationManager;
+import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
+import org.openecomp.sdc.be.model.Component;
+import org.openecomp.sdc.be.model.tosca.constraints.ConstraintType;
+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.plugins.etsi.nfv.nsd.tosca.yaml.ToscaTemplateYamlGenerator;
+import org.openecomp.sdc.be.tosca.ToscaError;
+import org.openecomp.sdc.be.tosca.ToscaExportHandler;
+import org.openecomp.sdc.be.tosca.model.SubstitutionMapping;
+import org.openecomp.sdc.be.tosca.model.ToscaNodeTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaNodeType;
+import org.openecomp.sdc.be.tosca.model.ToscaProperty;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraint;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraintValidValues;
+import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
+import org.openecomp.sdc.be.tosca.model.ToscaTopolgyTemplate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.ObjectProvider;
+
+@org.springframework.stereotype.Component("nsDescriptorGenerator")
+public class NsDescriptorGeneratorImpl implements NsDescriptorGenerator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(NsDescriptorGeneratorImpl.class);
+ private static final String TOSCA_VERSION = "tosca_simple_yaml_1_1";
+ private static final String NS_TOSCA_TYPE = "tosca.nodes.nfv.NS";
+ private static final List<Map<String, Map<String, String>>> DEFAULT_IMPORTS_ETSI_SOL_NSD =
+ ImmutableList.of(
+ ImmutableMap.of("etsi_nfv_sol001_nsd_2_7_1_types",
+ ImmutableMap.of("file", "etsi_nfv_sol001_nsd_2_7_1_types.yaml")
+ )
+ );
+ private static final List<Map<String, Map<String, String>>> DEFAULT_IMPORTS = ConfigurationManager
+ .getConfigurationManager().getConfiguration().getDefaultImports();
+ private static final List<String> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE = Arrays
+ .asList("cds_model_name", "cds_model_version", "skip_post_instantiation_configuration", "controller_actor");
+ private static final List<String> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE = Arrays
+ .asList("nf_function", "nf_role", "nf_naming_code", "nf_type", "nf_naming", "availability_zone_max_count",
+ "min_instances", "max_instances", "multi_stage_design", "sdnc_model_name", "sdnc_model_version",
+ "sdnc_artifact_name", "skip_post_instantiation_configuration", "controller_actor");
+
+ private final ToscaExportHandler toscaExportHandler;
+ private final ObjectProvider<ToscaTemplateYamlGenerator> toscaTemplateYamlGeneratorProvider;
+
+ public NsDescriptorGeneratorImpl(final ToscaExportHandler toscaExportHandler,
+ final ObjectProvider<ToscaTemplateYamlGenerator> toscaTemplateYamlGeneratorProvider) {
+ this.toscaExportHandler = toscaExportHandler;
+ this.toscaTemplateYamlGeneratorProvider = toscaTemplateYamlGeneratorProvider;
+ }
+
+ public Optional<Nsd> generate(final Component component,
+ final List<VnfDescriptor> vnfDescriptorList) throws NsdException {
+ if (!ComponentTypeEnum.SERVICE.equals(component.getComponentType())) {
+ return Optional.empty();
+ }
+
+ final ToscaTemplate toscaTemplate = createNetworkServiceDescriptor(component, vnfDescriptorList);
+ final ToscaNodeType nsNodeType = toscaTemplate.getNode_types().values().stream()
+ .filter(toscaNodeType -> NS_TOSCA_TYPE.equals(toscaNodeType.getDerived_from())).findFirst().orElse(null);
+ if (nsNodeType == null) {
+ return Optional.empty();
+ }
+
+ return Optional.of(buildNsd(toscaTemplate, nsNodeType));
+ }
+
+ private Nsd buildNsd(final ToscaTemplate toscaTemplate, final ToscaNodeType nsNodeType) {
+ final Nsd nsd = new Nsd();
+ nsd.setDesigner(getProperty(nsNodeType, Nsd.DESIGNER_PROPERTY));
+ nsd.setVersion(getProperty(nsNodeType, Nsd.VERSION_PROPERTY));
+ nsd.setName(getProperty(nsNodeType, Nsd.NAME_PROPERTY));
+ nsd.setInvariantId(getProperty(nsNodeType, Nsd.INVARIANT_ID_PROPERTY));
+ final ToscaTemplateYamlGenerator yamlParserProvider =
+ toscaTemplateYamlGeneratorProvider.getObject(toscaTemplate);
+ final byte[] contents = yamlParserProvider.parseToYamlString().getBytes();
+ nsd.setContents(contents);
+ final List<String> interfaceImplementations = getInterfaceImplementations(toscaTemplate);
+ nsd.setArtifactReferences(interfaceImplementations);
+ return nsd;
+ }
+
+ private List<String> getInterfaceImplementations(final ToscaTemplate template) {
+ if (template.getTopology_template().getNode_templates() == null) {
+ return Collections.emptyList();
+ }
+ final List<String> interfaceImplementations = new ArrayList<>();
+ final Collection<ToscaNodeTemplate> nodeTemplates =
+ template.getTopology_template().getNode_templates().values();
+ nodeTemplates.stream()
+ .filter(toscaNodeTemplate -> toscaNodeTemplate.getInterfaces() != null)
+ .forEach(toscaNodeTemplate ->
+ toscaNodeTemplate.getInterfaces().values().forEach(interfaceInstance ->
+ interfaceImplementations.addAll(getInterfaceImplementations(interfaceInstance))
+ ));
+ return interfaceImplementations;
+ }
+
+ private Collection<String> getInterfaceImplementations(final Object interfaceInstance) {
+ final Collection<String> interfaceImplementations = new ArrayList<>();
+ if (interfaceInstance instanceof Map) {
+ for (final Object value : ((Map<?, ?>) interfaceInstance).values()) {
+ if (value instanceof Map && ((Map<?, ?>) value).get("implementation") != null) {
+ interfaceImplementations.add(((Map<?, ?>) value).get("implementation").toString());
+ }
+ }
+ }
+ return interfaceImplementations;
+ }
+
+ private String getProperty(final ToscaNodeType nodeType, final String propertyName) {
+ final ToscaProperty toscaProperty = nodeType.getProperties().get(propertyName);
+
+ final String errorMsg =
+ String.format("Property '%s' must be defined and must have a valid values constraint", propertyName);
+ final String returnValueOnError = "unknown";
+ if (toscaProperty == null || CollectionUtils.isEmpty(toscaProperty.getConstraints())) {
+ LOGGER.error(errorMsg);
+ return returnValueOnError;
+ }
+
+ final ToscaPropertyConstraint toscaPropertyConstraint = toscaProperty.getConstraints().get(0);
+ if (ConstraintType.VALID_VALUES != toscaPropertyConstraint.getConstraintType()) {
+ LOGGER.error(errorMsg);
+ return returnValueOnError;
+ }
+
+ final ToscaPropertyConstraintValidValues validValuesConstraint =
+ (ToscaPropertyConstraintValidValues) toscaPropertyConstraint;
+ final List<String> validValues = validValuesConstraint.getValidValues();
+ if(CollectionUtils.isEmpty(validValues)) {
+ LOGGER.error(errorMsg);
+ return returnValueOnError;
+ }
+
+ return validValues.get(0);
+ }
+
+ private ToscaTemplate createNetworkServiceDescriptor(final Component component,
+ final List<VnfDescriptor> vnfDescriptorList)
+ throws NsdException {
+
+ final ToscaTemplate componentToscaTemplate = parseToToscaTemplate(component);
+ final ToscaTemplate componentToscaTemplateInterface = exportComponentInterfaceAsToscaTemplate(component);
+
+ final Entry<String, ToscaNodeType> firstNodeTypeEntry =
+ componentToscaTemplateInterface.getNode_types()
+ .entrySet().stream().findFirst().orElse(null);
+ if (firstNodeTypeEntry == null) {
+ throw new NsdException("Could not find abstract Service type");
+ }
+
+ final String nsNodeTypeName = firstNodeTypeEntry.getKey();
+ final ToscaNodeType nsNodeType = firstNodeTypeEntry.getValue();
+
+ final Map<String, ToscaNodeType> nodeTypeMap = new HashMap<>();
+ nodeTypeMap.put(nsNodeTypeName, createEtsiSolNsNodeType(nsNodeType));
+
+ if (componentToscaTemplate.getNode_types() == null) {
+ componentToscaTemplate.setNode_types(nodeTypeMap);
+ } else {
+ componentToscaTemplate.getNode_types().putAll(nodeTypeMap);
+ }
+
+ setPropertiesForNodeTemplates(componentToscaTemplate);
+ removeCapabilitiesFromNodeTemplates(componentToscaTemplate);
+ removeOnapPropertiesFromInputs(componentToscaTemplate);
+ handleSubstitutionMappings(componentToscaTemplate, nsNodeTypeName);
+
+ final Map<String, ToscaNodeTemplate> nodeTemplates = new HashMap<>();
+ nodeTemplates.put(nsNodeTypeName, createNodeTemplateForNsNodeType(nsNodeTypeName,
+ componentToscaTemplateInterface.getNode_types().get(nsNodeTypeName)));
+
+ if (componentToscaTemplate.getTopology_template().getNode_templates() == null) {
+ componentToscaTemplate.getTopology_template().setNode_templates(nodeTemplates);
+ } else {
+ setNodeTemplateTypesForVnfs(componentToscaTemplate, vnfDescriptorList);
+ componentToscaTemplate.getTopology_template().getNode_templates().putAll(nodeTemplates);
+ }
+
+ removeOnapMetaData(componentToscaTemplate);
+
+ setDefaultImportsForEtsiSolNsNsd(componentToscaTemplate, vnfDescriptorList);
+
+ return componentToscaTemplate;
+ }
+
+ private void handleSubstitutionMappings(final ToscaTemplate componentToscaTemplate, final String nsNodeTypeName) {
+ final SubstitutionMapping substitutionMapping = new SubstitutionMapping();
+ substitutionMapping.setNode_type(nsNodeTypeName);
+ final SubstitutionMapping onapSubstitutionMapping = componentToscaTemplate.getTopology_template().getSubstitution_mappings();
+ if (onapSubstitutionMapping != null) {
+ substitutionMapping.setRequirements(onapSubstitutionMapping.getRequirements());
+ substitutionMapping.setCapabilities(onapSubstitutionMapping.getCapabilities());
+ }
+ componentToscaTemplate.getTopology_template().setSubstitution_mappings(substitutionMapping);
+ }
+
+ private void setNodeTemplateTypesForVnfs(final ToscaTemplate template,
+ final List<VnfDescriptor> vnfDescriptorList) {
+ if (CollectionUtils.isEmpty(vnfDescriptorList)) {
+ return;
+ }
+ final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
+ if (MapUtils.isEmpty(nodeTemplateMap)) {
+ return;
+ }
+ nodeTemplateMap.forEach((key, toscaNodeTemplate) ->
+ vnfDescriptorList.stream()
+ .filter(vnfDescriptor -> key.equals(vnfDescriptor.getName())).findFirst()
+ .ifPresent(vnfDescriptor -> toscaNodeTemplate.setType(vnfDescriptor.getNodeType()))
+ );
+ }
+
+ private void setPropertiesForNodeTemplates(final ToscaTemplate template) {
+ final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
+ if (MapUtils.isEmpty(nodeTemplateMap)) {
+ return;
+ }
+ for (final Entry<String, ToscaNodeTemplate> nodeTemplate : nodeTemplateMap.entrySet()) {
+ final Map<String, Object> propertyMap = nodeTemplate.getValue().getProperties();
+ if (MapUtils.isEmpty(propertyMap)) {
+ nodeTemplate.getValue().setProperties(null);
+ continue;
+ }
+ final Map<String, Object> editedPropertyMap = new HashMap<>();
+ for (final Entry<String, Object> property : propertyMap.entrySet()) {
+ if (!PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TEMPLATE.contains(property.getKey())
+ && propertyIsDefinedInNodeType(property.getKey())) {
+ editedPropertyMap
+ .put(property.getKey().substring(property.getKey().indexOf('_') + 1), property.getValue());
+ }
+ }
+ if (editedPropertyMap.isEmpty()) {
+ nodeTemplate.getValue().setProperties(null);
+ } else {
+ nodeTemplate.getValue().setProperties(editedPropertyMap);
+ }
+ }
+ }
+
+ private void removeCapabilitiesFromNodeTemplates(final ToscaTemplate template) {
+ final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
+ if (MapUtils.isEmpty(nodeTemplateMap)) {
+ return;
+ }
+ for (final Entry<String, ToscaNodeTemplate> nodeTemplate : nodeTemplateMap.entrySet()) {
+ nodeTemplate.getValue().setCapabilities(null);
+ }
+ }
+
+ private void removeOnapPropertiesFromInputs(final ToscaTemplate template) {
+ final ToscaTopolgyTemplate topologyTemplate = template.getTopology_template();
+ final Map<String, ToscaProperty> inputMap = topologyTemplate.getInputs();
+ if (MapUtils.isNotEmpty(inputMap)) {
+ inputMap.entrySet()
+ .removeIf(entry -> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE.contains(entry.getKey()));
+ }
+ if (MapUtils.isEmpty(inputMap)) {
+ topologyTemplate.setInputs(null);
+ }
+ }
+
+ private void removeOnapMetaData(final ToscaTemplate template) {
+ template.setMetadata(null);
+ final Map<String, ToscaNodeTemplate> nodeTemplateMap = template.getTopology_template().getNode_templates();
+ if (MapUtils.isEmpty(nodeTemplateMap)) {
+ return;
+ }
+ nodeTemplateMap.values().forEach(toscaNodeTemplate -> toscaNodeTemplate.setMetadata(null));
+ }
+
+ private void setDefaultImportsForEtsiSolNsNsd(final ToscaTemplate template,
+ final List<VnfDescriptor> vnfDescriptorList) {
+ final List<Map<String, Map<String, String>>> importEntryMap = new ArrayList<>(DEFAULT_IMPORTS_ETSI_SOL_NSD);
+ if (CollectionUtils.isNotEmpty(vnfDescriptorList)) {
+ for (final VnfDescriptor vnfDescriptor : vnfDescriptorList) {
+ final Map<String, String> vnfImportChildEntry = new HashMap<>();
+ vnfImportChildEntry.put("file", vnfDescriptor.getVnfdFileName());
+ final Map<String, Map<String, String>> vnfdImportVnfdEntry = new HashMap<>();
+ vnfdImportVnfdEntry.put(vnfDescriptor.getName(), vnfImportChildEntry);
+ importEntryMap.add(vnfdImportVnfdEntry);
+ }
+ }
+
+ template.setImports(importEntryMap);
+ }
+
+ private ToscaNodeType createEtsiSolNsNodeType(final ToscaNodeType nsNodeType) {
+ final ToscaNodeType toscaNodeType = new ToscaNodeType();
+ toscaNodeType.setDerived_from(NS_TOSCA_TYPE);
+
+ final Map<String, ToscaProperty> propertiesInNsNodeType = nsNodeType.getProperties();
+
+ for (final Entry<String, ToscaProperty> property : propertiesInNsNodeType.entrySet()) {
+ final ToscaProperty toscaProperty = property.getValue();
+ if (toscaProperty.getDefaultp() != null) {
+ final ToscaPropertyConstraintValidValues constraint = new ToscaPropertyConstraintValidValues(
+ Collections.singletonList(toscaProperty.getDefaultp().toString()));
+ toscaProperty.setConstraints(Collections.singletonList(constraint));
+ }
+ }
+
+ propertiesInNsNodeType.entrySet()
+ .removeIf(entry -> PROPERTIES_TO_EXCLUDE_FROM_ETSI_SOL_NSD_NS_NODE_TYPE.contains(entry.getKey()));
+ toscaNodeType.setProperties(propertiesInNsNodeType);
+
+ return toscaNodeType;
+ }
+
+ private boolean propertyIsDefinedInNodeType(final String propertyName) {
+ // This will achieve what we want for now, but will look into a more generic solution which would involve
+ // checking the node_type definition in the VNFD
+ return !propertyName.equals("additional_parameters");
+ }
+
+
+ private ToscaNodeTemplate createNodeTemplateForNsNodeType(final String nodeType,
+ final ToscaNodeType toscaNodeType) {
+ final ToscaNodeTemplate nodeTemplate = new ToscaNodeTemplate();
+ nodeTemplate.setType(nodeType);
+
+ final Map<String, ToscaProperty> properties = toscaNodeType.getProperties();
+ final Map<String, Object> nodeTemplateProperties = new HashMap<>();
+ for (final Entry<String, ToscaProperty> property : properties.entrySet()) {
+ nodeTemplateProperties.put(property.getKey(), property.getValue().getDefaultp());
+ }
+
+ if (!nodeTemplateProperties.isEmpty()) {
+ nodeTemplate.setProperties(nodeTemplateProperties);
+ }
+
+ final Map<String, Object> interfaces = toscaNodeType.getInterfaces();
+ if (interfaces != null) {
+ for (final Entry<String, Object> nodeInterface : interfaces.entrySet()) {
+ if ("Nslcm".equals(nodeInterface.getKey()) && nodeInterface.getValue() instanceof Map) {
+ ((Map<?, ?>) nodeInterface.getValue()).remove("type");
+ }
+ }
+ nodeTemplate.setInterfaces(interfaces);
+ }
+
+ return nodeTemplate;
+ }
+
+ private ToscaTemplate parseToToscaTemplate(final Component component) throws NsdException {
+ final Either<ToscaTemplate, ToscaError> toscaTemplateRes = toscaExportHandler.convertToToscaTemplate(component);
+ if (toscaTemplateRes.isRight()) {
+ String errorMsg = String.format("Could not parse component '%s' to tosca template. Error '%s'",
+ component.getName(), toscaTemplateRes.right().value().name());
+ throw new NsdException(errorMsg);
+ }
+
+ return toscaTemplateRes.left().value();
+ }
+
+
+ private ToscaTemplate exportComponentInterfaceAsToscaTemplate(final Component component) throws NsdException {
+ if (null == DEFAULT_IMPORTS) {
+ throw new NsdException("Could not load default CSAR imports from configuration");
+ }
+
+ final ToscaTemplate toscaTemplate = new ToscaTemplate(TOSCA_VERSION);
+ toscaTemplate.setImports(new ArrayList<>(DEFAULT_IMPORTS));
+ final Either<ToscaTemplate, ToscaError> toscaTemplateRes = toscaExportHandler
+ .convertInterfaceNodeType(new HashMap<>(), component, toscaTemplate, new HashMap<>(), false);
+ if (toscaTemplateRes.isRight()) {
+ throw new NsdException(String.format("Could not create abstract service from component '%s'",
+ component.getName()));
+ }
+
+ return toscaTemplateRes.left().value();
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGenerator.java
new file mode 100644
index 0000000000..c4599d7cf4
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGenerator.java
@@ -0,0 +1,43 @@
+/*
+ * ============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 java.util.Optional;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.VnfDescriptorException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
+
+/**
+ * Generator of a VNF Descriptor from the ONBOARDED_PACKAGE
+ */
+public interface VnfDescriptorGenerator {
+
+ /**
+ * Generates the a VNF Descriptor based on the ONBOARDED_PACKAGE artifact.
+ *
+ * @param name the name of the VNF package
+ * @param onboardedPackageArtifact the onboarded package for the VNF
+ * @return a representation of the VNF package
+ * @throws VnfDescriptorException when a problem happens during the generation
+ */
+ Optional<VnfDescriptor> generate(final String name, final ArtifactDefinition onboardedPackageArtifact)
+ throws VnfDescriptorException;
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGeneratorImpl.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGeneratorImpl.java
new file mode 100644
index 0000000000..8cf54d129a
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/generator/VnfDescriptorGeneratorImpl.java
@@ -0,0 +1,202 @@
+/*
+ * ============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 java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
+import org.onap.sdc.tosca.services.YamlUtil;
+import org.openecomp.core.utilities.file.FileContentHandler;
+import org.openecomp.core.utilities.file.FileUtils;
+import org.openecomp.sdc.be.model.ArtifactDefinition;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.builder.NsdToscaMetadataBuilder;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.exception.VnfDescriptorException;
+import org.openecomp.sdc.be.plugins.etsi.nfv.nsd.model.VnfDescriptor;
+import org.openecomp.sdc.common.zip.exception.ZipException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.Yaml;
+
+/**
+ * Implementation of a VNF Descriptor Generator
+ */
+@Component("vnfPackageGenerator")
+public class VnfDescriptorGeneratorImpl implements VnfDescriptorGenerator {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(VnfDescriptorGeneratorImpl.class);
+ private static final String SPACE_REGEX = "\\s+";
+ private static final String CSAR = "csar";
+ private static final String COLON = ":";
+ private static final String EMPTY_STRING = "";
+ private static final String SLASH = "/";
+ private static final String DEFINITIONS_DIRECTORY = "Definitions";
+ private static final String TOSCA_META_PATH = "TOSCA-Metadata/TOSCA.meta";
+
+ public Optional<VnfDescriptor> generate(final String name,
+ final ArtifactDefinition onboardedPackageArtifact)
+ throws VnfDescriptorException {
+ if (!isACsarArtifact(onboardedPackageArtifact)) {
+ return Optional.empty();
+ }
+
+ final FileContentHandler fileContentHandler;
+ try {
+ fileContentHandler = FileUtils.getFileContentMapFromZip(onboardedPackageArtifact.getPayloadData());
+ } catch (final ZipException e) {
+ final String errorMsg = String
+ .format("Could not unzip artifact '%s' content", onboardedPackageArtifact.getArtifactName());
+ throw new VnfDescriptorException(errorMsg, e);
+ }
+
+ if (MapUtils.isEmpty(fileContentHandler.getFiles())) {
+ return Optional.empty();
+ }
+ final String mainDefinitionFile;
+ try {
+ mainDefinitionFile = getMainFilePathFromMetaFile(fileContentHandler).orElse(null);
+ } catch (final IOException e) {
+ final String errorMsg = String
+ .format("Could not read main definition file of artifact '%s'",
+ onboardedPackageArtifact.getArtifactName());
+ throw new VnfDescriptorException(errorMsg, e);
+ }
+ LOGGER.debug("found main file: {}", mainDefinitionFile);
+ if (mainDefinitionFile == null) {
+ return Optional.empty();
+ }
+ final VnfDescriptor vnfDescriptor = new VnfDescriptor();
+ vnfDescriptor.setName(name);
+ final String vnfdFileName = FilenameUtils.getName(mainDefinitionFile);
+
+ vnfDescriptor.setVnfdFileName(vnfdFileName);
+ vnfDescriptor.setDefinitionFiles(getFiles(fileContentHandler, mainDefinitionFile));
+ vnfDescriptor.setNodeType(getNodeType(getFileContent(fileContentHandler, mainDefinitionFile)));
+
+ return Optional.of(vnfDescriptor);
+ }
+
+ private static boolean isACsarArtifact(final ArtifactDefinition definition) {
+ return definition.getPayloadData() != null && definition.getArtifactName() != null && CSAR
+ .equalsIgnoreCase(FilenameUtils.getExtension(definition.getArtifactName()));
+ }
+
+ private Map<String, byte[]> getFiles(final FileContentHandler fileContentHandler, final String filePath) {
+ final Map<String, byte[]> files = new HashMap<>();
+
+ final byte[] fileContent = fileContentHandler.getFileContent(filePath);
+
+ if (fileContent != null) {
+ final String mainYmlFile = new String(fileContent);
+ LOGGER.debug("file content: {}", mainYmlFile);
+
+ files.put(appendDefinitionDirPath(filePath.substring(filePath.lastIndexOf(SLASH) + 1)),
+ getVnfdWithoutTopologyTemplate(fileContent));
+ final List<Object> imports = getImportFilesPath(mainYmlFile);
+ LOGGER.info("found imports {}", imports);
+ for (final Object importObject : imports) {
+ if (importObject != null) {
+ final String importFilename = importObject.toString();
+ final String importFileFullPath = appendDefinitionDirPath(importFilename);
+ final byte[] importFileContent = fileContentHandler.getFileContent(importFileFullPath);
+ files.put(appendDefinitionDirPath(importFilename), importFileContent);
+ }
+ }
+ }
+ return files;
+ }
+
+ private String getFileContent(final FileContentHandler fileContentHandler, final String filePath) {
+ final byte[] fileContent = fileContentHandler.getFileContent(filePath);
+
+ if (fileContent != null) {
+ return new String(fileContent);
+ }
+ return null;
+ }
+
+ private Optional<String> getMainFilePathFromMetaFile(final FileContentHandler fileContentHandler)
+ throws IOException {
+ final Map<String, String> metaFileContent = getMetaFileContent(fileContentHandler);
+ final String mainFile = metaFileContent.get(NsdToscaMetadataBuilder.ENTRY_DEFINITIONS);
+ if (mainFile != null) {
+ return Optional.of(mainFile.replaceAll(SPACE_REGEX, EMPTY_STRING));
+ }
+ LOGGER.error("{} entry not found in {}", NsdToscaMetadataBuilder.ENTRY_DEFINITIONS, TOSCA_META_PATH);
+ return Optional.empty();
+ }
+
+ private Map<String, String> getMetaFileContent(final FileContentHandler fileContentHandler)
+ throws IOException {
+ final InputStream inputStream = fileContentHandler.getFileContentAsStream(TOSCA_META_PATH);
+ if (inputStream == null) {
+ throw new FileNotFoundException("Unable find " + TOSCA_META_PATH + " file");
+ }
+ final List<String> lines = IOUtils.readLines(inputStream, StandardCharsets.UTF_8);
+
+ return lines.stream().map(str -> str.split(COLON))
+ .collect(Collectors.toMap(str -> str[0], str -> str.length > 1 ? str[1] : EMPTY_STRING));
+ }
+
+ private String appendDefinitionDirPath(final String filename) {
+ return DEFINITIONS_DIRECTORY + SLASH + filename;
+ }
+
+ private List<Object> getImportFilesPath(final String mainYmlFile) {
+ final Map<Object, Object> fileContentMap = new YamlUtil().yamlToObject(mainYmlFile, Map.class);
+
+ final Object importsObject = fileContentMap.get("imports");
+
+ if (importsObject instanceof List) {
+ return (List<Object>) importsObject;
+ }
+ return Collections.emptyList();
+ }
+
+ private byte[] getVnfdWithoutTopologyTemplate(final byte[] vnfdFileContent) {
+ final Yaml yaml = new Yaml();
+ final Map<String, Object> toscaFileContent = (Map<String, Object>) yaml.load(new String(vnfdFileContent));
+ toscaFileContent.remove("topology_template");
+
+ return yaml.dumpAsMap(toscaFileContent).getBytes();
+ }
+
+ private String getNodeType(final String mainYmlFile) {
+ final Map<Object, Object> fileContentMap = new YamlUtil().yamlToObject(mainYmlFile, Map.class);
+
+ final Object nodeTypesObject = fileContentMap.get("node_types");
+ if (nodeTypesObject instanceof Map
+ && ((Map<String, Object>) nodeTypesObject).size() == 1) {
+ return ((Map<String, Object>) nodeTypesObject).keySet().iterator().next();
+ }
+ return null;
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/Nsd.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/Nsd.java
new file mode 100644
index 0000000000..a8de728702
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/Nsd.java
@@ -0,0 +1,89 @@
+/*
+ * ============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.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a Network Service Descriptor
+ */
+public class Nsd {
+
+ public static final String DESIGNER_PROPERTY = "designer";
+ public static final String VERSION_PROPERTY = "version";
+ public static final String NAME_PROPERTY = "name";
+ public static final String INVARIANT_ID_PROPERTY = "invariant_id";
+
+ private String designer;
+ private String version;
+ private String name;
+ private String invariantId;
+ private byte[] contents;
+ private List<String> artifactReferences = new ArrayList<>();
+
+ public String getDesigner() {
+ return designer;
+ }
+
+ public void setDesigner(String designer) {
+ this.designer = designer;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getInvariantId() {
+ return invariantId;
+ }
+
+ public void setInvariantId(String invariantId) {
+ this.invariantId = invariantId;
+ }
+
+ public byte[] getContents() {
+ return contents;
+ }
+
+ public void setContents(byte[] contents) {
+ this.contents = contents;
+ }
+
+ public List<String> getArtifactReferences() {
+ return artifactReferences;
+ }
+
+ public void setArtifactReferences(List<String> artifactReferences) {
+ this.artifactReferences = artifactReferences;
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/VnfDescriptor.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/VnfDescriptor.java
new file mode 100644
index 0000000000..53615effb6
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/model/VnfDescriptor.java
@@ -0,0 +1,67 @@
+/*
+ * ============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.model;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Represents a Virtual Network Function Descriptor
+ */
+public class VnfDescriptor {
+
+ private String name;
+ private String vnfdFileName;
+ private String nodeType;
+ private Map<String, byte[]> definitionFiles = new HashMap<>();
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public Map<String, byte[]> getDefinitionFiles() {
+ return definitionFiles;
+ }
+
+ public void setDefinitionFiles(Map<String, byte[]> definitionFiles) {
+ this.definitionFiles = definitionFiles;
+ }
+
+ public String getVnfdFileName() {
+ return vnfdFileName;
+ }
+
+ public void setVnfdFileName(String vnfdFileName) {
+ this.vnfdFileName = vnfdFileName;
+ }
+
+ public String getNodeType() {
+ return nodeType;
+ }
+
+ public void setNodeType(String nodeType) {
+ this.nodeType = nodeType;
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/NsdTemplateRepresenter.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/NsdTemplateRepresenter.java
new file mode 100644
index 0000000000..822d6dc82b
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/NsdTemplateRepresenter.java
@@ -0,0 +1,129 @@
+/*
+ * ============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.tosca.yaml;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.openecomp.sdc.be.tosca.model.ToscaProperty;
+import org.openecomp.sdc.be.tosca.model.ToscaPropertyConstraintValidValues;
+import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.nodes.MappingNode;
+import org.yaml.snakeyaml.nodes.Node;
+import org.yaml.snakeyaml.nodes.NodeTuple;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Represent;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * A NSD YAML Representer
+ */
+public class NsdTemplateRepresenter extends Representer {
+
+ private final Set<String> ignoredPropertySet = Stream.of("dependencies").collect(Collectors.toSet());
+
+ public NsdTemplateRepresenter() {
+ super();
+ this.nullRepresenter = new RepresentNull();
+ }
+
+ @Override
+ protected NodeTuple representJavaBeanProperty(final Object javaBean, final Property property,
+ final Object propertyValue, final Tag customTag) {
+ if (propertyValue == null) {
+ return null;
+ }
+
+ if (ignoredPropertySet.contains(property.getName())) {
+ return null;
+ }
+
+ if (javaBean instanceof ToscaTemplate) {
+ return handleToscaTemplate(javaBean, property, propertyValue, customTag);
+ }
+
+ if (javaBean instanceof ToscaPropertyConstraintValidValues) {
+ return handleToscaPropertyConstraintValidValues(javaBean, property, propertyValue, customTag);
+ }
+
+ if (javaBean instanceof ToscaProperty) {
+ return handleToscaProperty(javaBean, property, propertyValue, customTag);
+ }
+
+ return super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ }
+
+ private NodeTuple handleToscaProperty(final Object javaBean, final Property property,
+ final Object propertyValue, final Tag customTag) {
+ final NodeTuple nodeTuple = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ if ("_defaultp_".equals(property.getName())) {
+ return new NodeTuple(representData("default"), nodeTuple.getValueNode());
+ }
+
+ return nodeTuple;
+ }
+
+ private NodeTuple handleToscaPropertyConstraintValidValues(final Object javaBean, final Property property,
+ final Object propertyValue, final Tag customTag) {
+ final NodeTuple nodeTuple = super.representJavaBeanProperty(javaBean, property, propertyValue, customTag);
+ if ("validValues".equals(property.getName())) {
+ final String validValuesEntryName = ToscaPropertyConstraintValidValues.getEntryToscaName("validValues");
+ return new NodeTuple(representData(validValuesEntryName), nodeTuple.getValueNode());
+ }
+
+ return nodeTuple;
+ }
+
+ private NodeTuple handleToscaTemplate(final Object javaBean, final Property property,
+ final Object propertyValueObj, final Tag customTag) {
+ if ("imports".equals(property.getName())) {
+ final List<Map<String, Map<String, String>>> importsList =
+ (List<Map<String, Map<String, String>>>) propertyValueObj;
+
+ final List<Map<String, String>> newImportList = new ArrayList<>();
+ importsList.forEach(importMap -> importMap.forEach((key, value) -> newImportList.add(value)));
+
+ return super.representJavaBeanProperty(javaBean, property, newImportList, customTag);
+ }
+
+ return super.representJavaBeanProperty(javaBean, property, propertyValueObj, customTag);
+ }
+
+ @Override
+ protected MappingNode representJavaBean(final Set<Property> properties, final Object javaBean) {
+ if (!classTags.containsKey(javaBean.getClass())) {
+ addClassTag(javaBean.getClass(), Tag.MAP);
+ }
+
+ return super.representJavaBean(properties, javaBean);
+ }
+
+ private class RepresentNull implements Represent {
+
+ @Override
+ public Node representData(final Object data) {
+ return representScalar(Tag.NULL, "");
+ }
+ }
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/ToscaTemplateYamlGenerator.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/ToscaTemplateYamlGenerator.java
new file mode 100644
index 0000000000..4c2cd87184
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/ToscaTemplateYamlGenerator.java
@@ -0,0 +1,73 @@
+/*
+ * ============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.tosca.yaml;
+
+import org.openecomp.sdc.be.tosca.model.ToscaTemplate;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.DumperOptions;
+import org.yaml.snakeyaml.DumperOptions.FlowStyle;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.nodes.Tag;
+import org.yaml.snakeyaml.representer.Representer;
+
+/**
+ * Handles a Tosca Template YAML parsing
+ */
+@Component
+@Scope(BeanDefinition.SCOPE_PROTOTYPE)
+public class ToscaTemplateYamlGenerator {
+
+ private final ToscaTemplate toscaTemplate;
+ private final Representer representer;
+ private final DumperOptions dumperOptions;
+
+ public ToscaTemplateYamlGenerator(final ToscaTemplate toscaTemplate) {
+ this.toscaTemplate = toscaTemplate;
+ this.representer = new NsdTemplateRepresenter();
+ initRepresenter();
+ this.dumperOptions = new DumperOptions();
+ initDumperOptions();
+ }
+
+ /**
+ * Parses the ToscaTemplate to a String YAML.
+ *
+ * @return the YAML representing the ToscaTemplate
+ */
+ public String parseToYamlString() {
+ final Yaml yaml = new Yaml(representer, dumperOptions);
+ return yaml.dumpAsMap(toscaTemplate);
+ }
+
+ private void initDumperOptions() {
+ dumperOptions.setAllowReadOnlyProperties(false);
+ dumperOptions.setPrettyFlow(true);
+ dumperOptions.setDefaultFlowStyle(FlowStyle.FLOW);
+ dumperOptions.setCanonical(false);
+ }
+
+ private void initRepresenter() {
+ representer.addClassTag(toscaTemplate.getClass(), Tag.MAP);
+ representer.setPropertyUtils(new UnsortedPropertyUtils());
+ }
+
+}
diff --git a/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/UnsortedPropertyUtils.java b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/UnsortedPropertyUtils.java
new file mode 100644
index 0000000000..b93db62088
--- /dev/null
+++ b/catalog-be-plugins/etsi-nfv-nsd-csar-plugin/src/main/java/org/openecomp/sdc/be/plugins/etsi/nfv/nsd/tosca/yaml/UnsortedPropertyUtils.java
@@ -0,0 +1,39 @@
+/*
+ * ============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.tosca.yaml;
+
+import java.beans.IntrospectionException;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import org.yaml.snakeyaml.introspector.BeanAccess;
+import org.yaml.snakeyaml.introspector.Property;
+import org.yaml.snakeyaml.introspector.PropertyUtils;
+
+public class UnsortedPropertyUtils extends PropertyUtils {
+
+ @Override
+ protected Set<Property> createPropertySet(final Class clazz, final BeanAccess beanAccess)
+ throws IntrospectionException {
+
+ final Collection<Property> fields = getPropertiesMap(clazz, BeanAccess.FIELD).values();
+ return new LinkedHashSet<>(fields);
+ }
+} \ No newline at end of file