Update property to identify SOL004 packages
[sdc.git] / openecomp-be / lib / openecomp-sdc-vendor-software-product-lib / openecomp-sdc-vendor-software-product-core / src / main / java / org / openecomp / sdc / vendorsoftwareproduct / services / impl / etsi / ETSIServiceImpl.java
index 1b74b00..a0ab46e 100644 (file)
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
-
 package org.openecomp.sdc.vendorsoftwareproduct.services.impl.etsi;
 
-import org.apache.commons.io.IOUtils;
-import org.onap.sdc.tosca.parser.utils.YamlToObjectConverter;
+import static org.openecomp.sdc.tosca.csar.CSARConstants.ARTIFACTS_FOLDER;
+import static org.openecomp.sdc.tosca.csar.CSARConstants.ETSI_VERSION_2_6_1;
+import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_MF_FILE_NAME;
+import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA;
+import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ORIG_PATH_FILE_NAME;
+import static org.openecomp.sdc.tosca.csar.ManifestTokenType.COMPATIBLE_SPECIFICATION_VERSIONS;
+import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion251.ENTRY_MANIFEST;
+import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ENTRY_DEFINITIONS;
+import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_CHANGE_LOG;
+import static org.openecomp.sdc.tosca.csar.ToscaMetaEntryVersion261.ETSI_ENTRY_MANIFEST;
+import static org.openecomp.sdc.tosca.csar.ToscaMetadataFileInfo.TOSCA_META_PATH_FILE_NAME;
+
+import com.vdurmont.semver4j.Semver;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import org.apache.commons.collections.MapUtils;
+import org.onap.sdc.tosca.datatypes.model.ServiceTemplate;
+import org.onap.sdc.tosca.services.YamlUtil;
 import org.openecomp.core.utilities.file.FileContentHandler;
+import org.openecomp.sdc.be.config.NonManoArtifactType;
+import org.openecomp.sdc.be.config.NonManoConfiguration;
+import org.openecomp.sdc.be.config.NonManoConfigurationManager;
+import org.openecomp.sdc.be.config.NonManoFolderType;
 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
+import org.openecomp.sdc.common.CommonConfigurationManager;
+import org.openecomp.sdc.logging.api.Logger;
+import org.openecomp.sdc.logging.api.LoggerFactory;
 import org.openecomp.sdc.tosca.csar.Manifest;
 import org.openecomp.sdc.tosca.csar.OnboardingToscaMetadata;
 import org.openecomp.sdc.tosca.csar.SOL004ManifestOnboarding;
 import org.openecomp.sdc.tosca.csar.ToscaMetadata;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.List;
-import java.util.Map;
-
-import static org.openecomp.sdc.tosca.csar.CSARConstants.MAIN_SERVICE_TEMPLATE_MF_FILE_NAME;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.MANIFEST_PNF_METADATA;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ENTRY_DEFINITIONS;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ETSI_ENTRY_CHANGE_LOG;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ETSI_ENTRY_MANIFEST;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_ORIG_PATH_FILE_NAME;
-import static org.openecomp.sdc.tosca.csar.CSARConstants.TOSCA_META_PATH_FILE_NAME;
+import org.openecomp.sdc.tosca.datatypes.ToscaServiceModel;
 
 public class ETSIServiceImpl implements ETSIService {
 
-    private Configuration configuration;
+    private static final Logger LOGGER = LoggerFactory.getLogger(ETSIServiceImpl.class);
+    private final NonManoConfiguration nonManoConfiguration;
+    private final String ONAP_CSAR = "onap_csar";
 
-    public ETSIServiceImpl() throws IOException {
-        InputStream io = getClass().getClassLoader().getResourceAsStream("nonManoConfig.yaml");
-        if (io == null) {
-            throw new IOException("Non Mano configuration not found");
-        }
-        String data = IOUtils.toString(io, StandardCharsets.UTF_8);
-        YamlToObjectConverter yamlToObjectConverter = new YamlToObjectConverter();
-        configuration = yamlToObjectConverter.convertFromString(data, Configuration.class);
+    public ETSIServiceImpl() {
+        nonManoConfiguration = NonManoConfigurationManager.getInstance().getNonManoConfiguration();
     }
 
-    public ETSIServiceImpl(Configuration configuration) {
-        this.configuration = configuration;
+    public ETSIServiceImpl(final NonManoConfiguration nonManoConfiguration) {
+        this.nonManoConfiguration = nonManoConfiguration;
     }
 
     @Override
-    public boolean isSol004WithToscaMetaDirectory(FileContentHandler handler) throws IOException {
-        Map<String, byte[]> templates = handler.getFiles();
+    public boolean hasEtsiSol261Metadata(FileContentHandler handler) throws IOException {
+        final Map<String, byte[]> templates = handler.getFiles();
         return isMetaFilePresent(templates) && hasMetaMandatoryEntries(getMetadata(handler));
     }
 
     @Override
-    public void moveNonManoFileToArtifactFolder(FileContentHandler handler, Manifest manifest) {
-        for (Map.Entry<String, List<String>> entry : manifest.getNonManoSources().entrySet()) {
-            String e = entry.getKey();
-            List<String> k = entry.getValue();
-            updateNonManoLocation(handler, e, k);
+    public boolean isEtsiPackage(final FileContentHandler fileContentHandler) throws IOException {
+        return hasEtsiSol261Metadata(fileContentHandler) || !hasOnapCsarMetadata(fileContentHandler)
+            && !ONAP_CSAR.equalsIgnoreCase(getDefaultCsarFormat());
+    }
+
+    private boolean hasOnapCsarMetadata(final FileContentHandler fileContentHandler) throws IOException {
+        if (fileContentHandler.containsFile(TOSCA_META_PATH_FILE_NAME)){
+            final ToscaMetadata metadata =
+                OnboardingToscaMetadata.parseToscaMetadataFile(fileContentHandler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
+            return metadata.hasEntry(ONAP_CSAR);
         }
+        return false;
     }
 
+    private String getDefaultCsarFormat() {
+        return CommonConfigurationManager.getInstance().getConfigValue("csarFormat", "defaultFormat", ONAP_CSAR);
+    }
 
-    private void updateNonManoLocation(FileContentHandler handler, String nonManoKey, List<String> sources) {
-        Map<String, byte[]> files = handler.getFiles();
-        for (String key : sources) {
-            if (files.containsKey(key)) {
-                updateLocation(key, nonManoKey, files);
+    @Override
+    public Optional<Map<String, Path>> moveNonManoFileToArtifactFolder(final FileContentHandler handler) throws IOException {
+        final Manifest manifest = loadManifest(handler);
+        final Path originalManifestPath;
+        try {
+            originalManifestPath = getOriginalManifestPath(handler);
+        } catch (final IOException ex) {
+            if (LOGGER.isErrorEnabled()) {
+                LOGGER.error("An error occurred while getting the original manifest path", ex);
             }
+            throw ex;
         }
+        final Map<String, Path> fromToPathMap = new HashMap<>();
+        final Map<String, NonManoFolderType> nonManoKeyFolderMapping = nonManoConfiguration.getNonManoKeyFolderMapping();
+        manifest.getNonManoSources().entrySet().stream()
+            .filter(manifestNonManoSourceEntry -> nonManoKeyFolderMapping.containsKey(manifestNonManoSourceEntry.getKey()))
+            .forEach(manifestNonManoSourceEntry -> {
+                final NonManoFolderType nonManoFolderType = nonManoKeyFolderMapping.get(manifestNonManoSourceEntry.getKey());
+                final List<String> nonManoFileList = manifestNonManoSourceEntry.getValue();
+                final Map<String, Path> actualFromToPathMap = nonManoFileList.stream().map(nonManoFilePath -> {
+                    final Path normalizedFilePath = resolveNonManoFilePath(originalManifestPath, nonManoFilePath);
+                    final Optional<Path> changedPath = updateNonManoPathInHandler(handler, nonManoFolderType, normalizedFilePath);
+                    if (changedPath.isPresent()) {
+                        final Map<String, Path> fromAndToPathMap = new HashMap<>();
+                        fromAndToPathMap.put(nonManoFilePath, Paths.get(ARTIFACTS_FOLDER).resolve(changedPath.get()));
+                        return fromAndToPathMap;
+                    }
+                    return null;
+                }).filter(Objects::nonNull).collect(Collectors.toMap(fromToPathEntry -> fromToPathEntry.keySet().iterator().next(),
+                    fromToPathEntry -> fromToPathEntry.values().iterator().next()));
+                fromToPathMap.putAll(actualFromToPathMap);
+            });
+        return MapUtils.isEmpty(fromToPathMap) ? Optional.empty() : Optional.of(fromToPathMap);
     }
 
-    private void updateLocation(String key, String nonManoKey, Map<String, byte[]> files) {
-        if (nonManoKey == null || nonManoKey.isEmpty()) {
-            return;
+    /**
+     * Resolves the non mano file path based on the original manifest path of the onboarded package.
+     *
+     * @param originalManifestPath The original path from the onboarded package manifest
+     * @param nonManoFilePath      The non mano file path defined in the manifest
+     * @return The resolved and normalized non mano path.
+     */
+    private Path resolveNonManoFilePath(final Path originalManifestPath, final String nonManoFilePath) {
+        return originalManifestPath.resolve(Paths.get(nonManoFilePath)).normalize();
+    }
+
+    /**
+     * Updates the non mano file path in the package file handler based on the non mano type.
+     *
+     * @param handler                 The package file handler
+     * @param nonManoFolderType       The Non Mano type of the file to update
+     * @param nonManoOriginalFilePath The Non Mano file original path
+     * @return The new file path if it was updated in the package file handler, otherwise empty.
+     */
+    private Optional<Path> updateNonManoPathInHandler(final FileContentHandler handler, final NonManoFolderType nonManoFolderType,
+                                                      final Path nonManoOriginalFilePath) {
+        final Path fixedSourcePath = fixNonManoPath(nonManoOriginalFilePath);
+        if (handler.containsFile(fixedSourcePath.toString())) {
+            final Path newNonManoPath = Paths
+                .get(nonManoFolderType.getType(), nonManoFolderType.getLocation(), fixedSourcePath.getFileName().toString());
+            if (!handler.containsFile(newNonManoPath.toString())) {
+                handler.addFile(newNonManoPath.toString(), handler.remove(fixedSourcePath.toString()));
+                return Optional.of(newNonManoPath);
+            }
         }
-        Map<String, NonManoType> map = configuration.getNonManoKeyFolderMapping();
-        if (map.containsKey(nonManoKey)) {
-            NonManoType nonManoPair = map.get(nonManoKey);
-            String newLocation = nonManoPair.getType() + "/" +
-                    nonManoPair.getLocation() + "/" + getFileName(key);
-            if (!files.containsKey(newLocation)) {
-                files.put(newLocation, files.remove(key));
+        return Optional.empty();
+    }
+
+    /**
+     * Fix the original non mano file path to the ONAP package file path.
+     * <p>
+     * Non mano artifacts that were inside the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} path are not moved when parsed to
+     * ONAP package, but the Manifest declaration can still have the {@link org.openecomp.sdc.tosca.csar.CSARConstants#ARTIFACTS_FOLDER} reference in
+     * it. If so, that reference is removed.
+     *
+     * @param nonManoOriginalFilePath The original non mano file path
+     * @return The non mano fixed path to ONAP package structure.
+     */
+    private Path fixNonManoPath(final Path nonManoOriginalFilePath) {
+        final Path rootArtifactsPath = Paths.get("/", ARTIFACTS_FOLDER);
+        if (nonManoOriginalFilePath.startsWith(rootArtifactsPath)) {
+            return rootArtifactsPath.relativize(nonManoOriginalFilePath);
+        }
+        final Path relativeArtifactsPath = Paths.get(ARTIFACTS_FOLDER);
+        if (nonManoOriginalFilePath.startsWith(relativeArtifactsPath)) {
+            return relativeArtifactsPath.relativize(nonManoOriginalFilePath);
+        }
+        return nonManoOriginalFilePath;
+    }
+
+    @Override
+    public void updateMainDescriptorPaths(final ToscaServiceModel toscaServiceModel, final Map<String, Path> fromToMovedArtifactMap) {
+        final ServiceTemplate entryDefinition = toscaServiceModel.getServiceTemplates().get(toscaServiceModel.getEntryDefinitionServiceTemplate());
+        final YamlUtil yamlUtil = new YamlUtil();
+        final String[] entryDefinitionYaml = {yamlUtil.objectToYaml(entryDefinition)};
+        fromToMovedArtifactMap.forEach((fromPath, toPath) -> entryDefinitionYaml[0] = entryDefinitionYaml[0].replaceAll(fromPath, toPath.toString()));
+        toscaServiceModel.addServiceTemplate(toscaServiceModel.getEntryDefinitionServiceTemplate(),
+            yamlUtil.yamlToObject(entryDefinitionYaml[0], ServiceTemplate.class));
+    }
+
+    private boolean hasMetaMandatoryEntries(final ToscaMetadata toscaMetadata) {
+        final Map<String, String> metaDataEntries = toscaMetadata.getMetaEntries();
+        return metaDataEntries.containsKey(ENTRY_DEFINITIONS.getName()) && metaDataEntries.containsKey(ETSI_ENTRY_MANIFEST.getName())
+            && metaDataEntries.containsKey(ETSI_ENTRY_CHANGE_LOG.getName());
+    }
+
+    @Override
+    public Semver getHighestCompatibleSpecificationVersion(final FileContentHandler handler) {
+        try {
+            Map<String, String> metadata = getManifest(handler).getMetadata();
+            if (metadata.containsKey(COMPATIBLE_SPECIFICATION_VERSIONS.getToken())) {
+                return Arrays.stream(metadata.get(COMPATIBLE_SPECIFICATION_VERSIONS.getToken()).split(",")).map(String::trim).map(Semver::new)
+                    .max(Comparator.naturalOrder()).orElse(new Semver(ETSI_VERSION_2_6_1));
             }
+        } catch (Exception ex) {
+            LOGGER.error("An error occurred while getting highest compatible version from manifest file", ex);
         }
+        return new Semver(ETSI_VERSION_2_6_1);
     }
 
-    private String getFileName(String key) {
-        return key.substring(key.lastIndexOf('/') + 1);
+    @Override
+    public boolean hasCnfEnhancements(final FileContentHandler fileContentHandler) throws IOException {
+        final Manifest manifest = loadManifest(fileContentHandler);
+        return manifest.getNonManoSources().entrySet().stream()
+            .filter(manifestNonManoSourceEntry -> NonManoArtifactType.ONAP_CNF_HELM.getType().equalsIgnoreCase(manifestNonManoSourceEntry.getKey()))
+            .findFirst().isPresent();
     }
 
-    private boolean hasMetaMandatoryEntries(ToscaMetadata toscaMetadata) {
-        Map<String, String> metaDataEntries = toscaMetadata.getMetaEntries();
-        return metaDataEntries.containsKey(TOSCA_META_ENTRY_DEFINITIONS) && metaDataEntries.containsKey(TOSCA_META_ETSI_ENTRY_MANIFEST)
-                && metaDataEntries.containsKey(TOSCA_META_ETSI_ENTRY_CHANGE_LOG);
+    private Manifest loadManifest(final FileContentHandler handler) throws IOException {
+        final Manifest manifest;
+        try {
+            manifest = getManifest(handler);
+        } catch (final IOException ex) {
+            if (LOGGER.isErrorEnabled()) {
+                LOGGER.error("An error occurred while getting the manifest file", ex);
+            }
+            throw ex;
+        }
+        return manifest;
     }
 
     private boolean isMetaFilePresent(Map<String, byte[]> handler) {
@@ -117,15 +248,16 @@ public class ETSIServiceImpl implements ETSIService {
 
     public ResourceTypeEnum getResourceType(FileContentHandler handler) throws IOException {
         ToscaMetadata metadata = getMetadata(handler);
-        Manifest manifest = getManifest(handler, metadata.getMetaEntries().get(TOSCA_META_ETSI_ENTRY_MANIFEST));
+        Manifest manifest = getManifest(handler, getEntryManifestLocation(metadata));
         return getResourceType(manifest);
     }
 
     public ResourceTypeEnum getResourceType(Manifest manifest) {
         // Valid manifest should contain whether vnf or pnf related metadata data exclusively in SOL004 standard,
+
         // validation of manifest done during package upload stage
-        if (manifest != null && !manifest.getMetadata().isEmpty()
-                && MANIFEST_PNF_METADATA.stream().anyMatch(e -> manifest.getMetadata().containsKey(e))) {
+        if (manifest != null && !manifest.getMetadata().isEmpty() && MANIFEST_PNF_METADATA.stream()
+            .anyMatch(e -> manifest.getMetadata().containsKey(e))) {
             return ResourceTypeEnum.PNF;
         }
         // VNF is default resource type
@@ -134,40 +266,65 @@ public class ETSIServiceImpl implements ETSIService {
 
     public Manifest getManifest(FileContentHandler handler) throws IOException {
         ToscaMetadata metadata = getMetadata(handler);
-        return getManifest(handler, metadata.getMetaEntries().get(TOSCA_META_ETSI_ENTRY_MANIFEST));
+        return getManifest(handler, getEntryManifestLocation(metadata));
+    }
+
+    private String getEntryManifestLocation(final ToscaMetadata metadata) {
+        return metadata.getMetaEntries().containsKey(ETSI_ENTRY_MANIFEST.getName()) ?
+            metadata.getMetaEntries().get(ETSI_ENTRY_MANIFEST.getName()):
+            metadata.getMetaEntries().get(ENTRY_MANIFEST.getName());
     }
 
     private Manifest getManifest(FileContentHandler handler, String manifestLocation) throws IOException {
-        try(InputStream manifestInputStream = getManifestInputStream(handler, manifestLocation)) {
+        try (InputStream manifestInputStream = getManifestInputStream(handler, manifestLocation)) {
             Manifest onboardingManifest = new SOL004ManifestOnboarding();
             onboardingManifest.parse(manifestInputStream);
             return onboardingManifest;
         }
     }
 
+    public Path getOriginalManifestPath(final FileContentHandler handler) throws IOException {
+        final ToscaMetadata metadata = getOriginalMetadata(handler);
+        final String originalMetadataPath = getEntryManifestLocation(metadata);
+        final Path path = Paths.get(originalMetadataPath);
+        return path.getParent() == null ? Paths.get("") : path.getParent();
+    }
+
     private ToscaMetadata getMetadata(FileContentHandler handler) throws IOException {
         ToscaMetadata metadata;
         if (handler.containsFile(TOSCA_META_PATH_FILE_NAME)) {
-            metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContent(TOSCA_META_PATH_FILE_NAME));
+            metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_PATH_FILE_NAME));
         } else if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
-            metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContent(TOSCA_META_ORIG_PATH_FILE_NAME));
+            metadata = OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
         } else {
             throw new IOException("TOSCA.meta file not found!");
         }
         return metadata;
     }
 
+    private ToscaMetadata getOriginalMetadata(final FileContentHandler handler) throws IOException {
+        if (handler.containsFile(TOSCA_META_ORIG_PATH_FILE_NAME)) {
+            return OnboardingToscaMetadata.parseToscaMetadataFile(handler.getFileContentAsStream(TOSCA_META_ORIG_PATH_FILE_NAME));
+        } else {
+            throw new IOException(String.format("%s file not found", TOSCA_META_ORIG_PATH_FILE_NAME));
+        }
+    }
+
     private InputStream getManifestInputStream(FileContentHandler handler, String manifestLocation) throws IOException {
         InputStream io;
         if (manifestLocation == null || !handler.containsFile(manifestLocation)) {
-            io = handler.getFileContent(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME);
+            io = handler.getFileContentAsStream(MAIN_SERVICE_TEMPLATE_MF_FILE_NAME);
         } else {
-            io = handler.getFileContent(manifestLocation);
+            io = handler.getFileContentAsStream(manifestLocation);
         }
-
         if (io == null) {
             throw new IOException("Manifest file not found!");
         }
         return io;
     }
+
+    public NonManoConfiguration getConfiguration() {
+        return nonManoConfiguration;
+    }
+
 }