diff options
author | vasraz <vasyl.razinkov@est.tech> | 2023-09-01 14:31:28 +0100 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2023-09-07 13:16:33 +0000 |
commit | 28e1a54e6074f50dcc06f7ea4eb3943ad873b448 (patch) | |
tree | edc59848dedfda9cf5d68e08b6744516d0e761a4 /catalog-be | |
parent | c469756a1092194adedd590d35f0f1f8feac3a36 (diff) |
Create plugin point for csar generation
Issue-ID: SDC-4578
Signed-off-by: franciscovila <javier.paradela.vila@est.tech>
Change-Id: I3bb280ce4e442780598464216145abc130765539
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Diffstat (limited to 'catalog-be')
11 files changed, 1573 insertions, 940 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/plugins/CsarZipGenerator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/plugins/CsarZipGenerator.java new file mode 100644 index 0000000000..f03c930681 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/plugins/CsarZipGenerator.java @@ -0,0 +1,48 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2023 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.plugins; + +import fj.data.Either; +import java.io.IOException; +import java.util.zip.ZipOutputStream; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.exception.ResponseFormat; + +/** + * Implementations of this interface shall generate a csar file. + */ +public interface CsarZipGenerator { + + /** + * Generate the csar file. + * + * @param component the component the csar is based on + * @return Map of name to contents for entries to be included in the csar + */ + Either<ZipOutputStream, ResponseFormat> generateCsarZip( + final Component component, + boolean getFromCS, + ZipOutputStream zip, + boolean isInCertificationRequest, + boolean isAsdPackage + ) throws IOException; + + String getModel(); +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CommonCsarGenerator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CommonCsarGenerator.java new file mode 100644 index 0000000000..633dd6e483 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CommonCsarGenerator.java @@ -0,0 +1,1235 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2023 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.tosca; + +import static org.openecomp.sdc.be.dao.api.ActionStatus.ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION; +import static org.openecomp.sdc.be.dao.api.ActionStatus.ERROR_DURING_CSAR_CREATION; +import static org.openecomp.sdc.be.tosca.ComponentCache.MergeStrategy.overwriteIfSameVersions; +import static org.openecomp.sdc.be.tosca.FJToVavrHelper.Try0.fromEither; +import static org.openecomp.sdc.be.tosca.FJToVavrHelper.Try0.javaListToVavrList; +import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS; + +import com.google.common.primitives.Bytes; +import fj.F; +import fj.data.Either; +import io.vavr.Tuple2; +import io.vavr.control.Try; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.TimeZone; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.function.Supplier; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.io.output.ByteArrayOutputStream; +import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.tuple.ImmutableTriple; +import org.apache.commons.lang3.tuple.Triple; +import org.apache.commons.text.WordUtils; +import org.onap.sdc.tosca.services.YamlUtil; +import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException; +import org.openecomp.sdc.be.config.CategoryBaseTypeConfig; +import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; +import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; +import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao; +import org.openecomp.sdc.be.data.model.ToscaImportByModel; +import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.impl.ComponentsUtils; +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.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.category.CategoryDefinition; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; +import org.openecomp.sdc.be.model.operations.impl.ModelOperation; +import org.openecomp.sdc.be.plugins.CsarEntryGenerator; +import org.openecomp.sdc.be.resources.data.DAOArtifactData; +import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil; +import org.openecomp.sdc.be.utils.TypeUtils; +import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; +import org.openecomp.sdc.common.api.ArtifactTypeEnum; +import org.openecomp.sdc.common.impl.ExternalConfiguration; +import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; +import org.openecomp.sdc.common.util.GeneralUtility; +import org.openecomp.sdc.common.zip.ZipUtils; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.yaml.snakeyaml.Yaml; + +/** + * Generates a Network Service CSAR based on a SERVICE component and wraps it in a SDC CSAR entry. + */ +@org.springframework.stereotype.Component("commonCsarGenerator") +public class CommonCsarGenerator { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommonCsarGenerator.class); + public static final String ARTIFACTS_PATH = "Artifacts/"; + private static final String RESOURCES_PATH = "Resources/"; + private static final String PATH_DELIMITER = "/"; + private static final String SERVICE_MANIFEST = "NS.mf"; + private static final String ARTIFACT_NAME_UNIQUE_ID = "ArtifactName {}, unique ID {}"; + private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta"; + private static final String TOSCA_META_VERSION = "1.0"; + private static final String CSAR_VERSION = "1.1"; + private static final String SDC_VERSION = ExternalConfiguration.getAppVersion(); + public static final String NODES_YML = "nodes.yml"; + private static final String CONFORMANCE_LEVEL = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel(); + private final ToscaOperationFacade toscaOperationFacade; + private final ComponentsUtils componentsUtils; + private final ToscaExportHandler toscaExportUtils; + private final List<CsarEntryGenerator> generators; + private final ArtifactCassandraDao artifactCassandraDao; + private final String versionFirstThreeOctets; + private final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao; + private final ModelOperation modelOperation; + + @Autowired + public CommonCsarGenerator( + final ToscaOperationFacade toscaOperationFacade, + final ComponentsUtils componentsUtils, + final ToscaExportHandler toscaExportUtils, + final List<CsarEntryGenerator> generators, + final ArtifactCassandraDao artifactCassandraDao, + final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao, + final ModelOperation modelOperation) { + this.toscaOperationFacade = toscaOperationFacade; + this.componentsUtils = componentsUtils; + this.toscaExportUtils = toscaExportUtils; + this.generators = generators; + this.artifactCassandraDao = artifactCassandraDao; + this.versionFirstThreeOctets = readVersionFirstThreeOctets(); + this.sdcSchemaFilesCassandraDao = sdcSchemaFilesCassandraDao; + this.modelOperation = modelOperation; + } + + private String readVersionFirstThreeOctets() { + if (StringUtils.isEmpty(SDC_VERSION)) { + return ""; + } + // change regex to avoid DoS sonar issue + Matcher matcher = Pattern.compile("(?!\\.)(\\d{1,9}(\\.\\d{1,9}){1,9})(?![\\d\\.])").matcher(SDC_VERSION); + matcher.find(); + return matcher.group(0); + } + + /** + * Generates a Network Service CSAR based on a SERVICE component that has category configured in + * CategoriesToGenerateNsd enum 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 + */ + + public Either<ZipOutputStream, ResponseFormat> generateCsarZip(Component component, + boolean getFromCS, + ZipOutputStream zip, + boolean isInCertificationRequest, + boolean isAsdPackage, + String definitionsPath, + boolean addDependencies, + boolean isSkipImports) throws IOException { + ArtifactDefinition artifactDef = component.getToscaArtifacts().get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + Either<ToscaRepresentation, ResponseFormat> toscaRepresentation = fetchToscaRepresentation(component, getFromCS, artifactDef, isSkipImports); + + // This should not be done but in order to keep the refactoring small enough we stop here. + // TODO: Refactor the rest of this function + byte[] mainYaml; + List<Triple<String, String, Component>> dependencies; + if (toscaRepresentation.isLeft()) { + mainYaml = toscaRepresentation.left().value().getMainYaml(); + dependencies = toscaRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>()); + } else { + return Either.right(toscaRepresentation.right().value()); + } + final String fileName = artifactDef.getArtifactName(); + final byte[] toscaBlock0Byte = + createToscaBlock0(TOSCA_META_VERSION, CSAR_VERSION, component.getCreatorFullName(), fileName, isAsdPackage, definitionsPath).getBytes(); + zip.putNextEntry(new ZipEntry(TOSCA_META_PATH_FILE_NAME)); + zip.write(toscaBlock0Byte); + zip.putNextEntry(new ZipEntry(definitionsPath + fileName)); + zip.write(mainYaml); + LifecycleStateEnum lifecycleState = component.getLifecycleState(); + addServiceMf(component, zip, lifecycleState, isInCertificationRequest, fileName, mainYaml, definitionsPath); + if (addDependencies) { + //US798487 - Abstraction of complex types + if (hasToWriteComponentSubstitutionType(component)) { + LOGGER.debug("Component {} is complex - generating abstract type for it..", component.getName()); + dependencies.addAll(writeComponentInterface(component, zip, fileName, definitionsPath)); + } + //UID <cassandraId,filename,component> + Either<ZipOutputStream, ResponseFormat> zipOutputStreamOrResponseFormat = + getZipOutputStreamResponseFormatEither(zip, dependencies, definitionsPath); + if (zipOutputStreamOrResponseFormat != null && zipOutputStreamOrResponseFormat.isRight()) { + return zipOutputStreamOrResponseFormat; + } + } + if (component.getModel() == null) { + //retrieve SDC.zip from Cassandra + Either<byte[], ResponseFormat> latestSchemaFiles = getLatestSchemaFilesFromCassandra(); + if (latestSchemaFiles.isRight()) { + LOGGER.error("Error retrieving SDC Schema files from cassandra"); + return Either.right(latestSchemaFiles.right().value()); + } + final byte[] schemaFileZip = latestSchemaFiles.left().value(); + final List<String> nodesFromPackage = findNonRootNodesFromPackage(dependencies); + //add files from retrieved SDC.zip to Definitions folder in CSAR + addSchemaFilesFromCassandra(zip, schemaFileZip, nodesFromPackage, definitionsPath); + } else { + //retrieve schema files by model from Cassandra + addSchemaFilesByModel(zip, component.getModel(), definitionsPath, addDependencies); + } + Either<CsarDefinition, ResponseFormat> collectedComponentCsarDefinition = collectComponentCsarDefinition(component); + if (collectedComponentCsarDefinition.isRight()) { + return Either.right(collectedComponentCsarDefinition.right().value()); + } + if (generators != null) { + for (CsarEntryGenerator generator : generators) { + LOGGER.debug("Invoking CsarEntryGenerator: {}", generator.getClass().getName()); + for (Map.Entry<String, byte[]> pluginGeneratedFile : generator.generateCsarEntries(component).entrySet()) { + zip.putNextEntry(new ZipEntry(pluginGeneratedFile.getKey())); + zip.write(pluginGeneratedFile.getValue()); + } + } + } + return writeAllFilesToCsar(component, collectedComponentCsarDefinition.left().value(), zip, isInCertificationRequest); + } + + private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(Component component, boolean getFromCS, + ArtifactDefinition artifactDef, boolean isSkipImports) { + LifecycleStateEnum lifecycleState = component.getLifecycleState(); + boolean shouldBeFetchedFromCassandra = + getFromCS || !(lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); + Either<ToscaRepresentation, ResponseFormat> toscaRepresentation = + shouldBeFetchedFromCassandra ? fetchToscaRepresentation(artifactDef) : generateToscaRepresentation(component, isSkipImports); + return toscaRepresentation.left() + .bind(iff(myd -> !myd.getDependencies().isDefined(), myd -> fetchToscaTemplateDependencies(myd.getMainYaml(), component))); + } + + private Either<ToscaRepresentation, ResponseFormat> fetchToscaTemplateDependencies(byte[] mainYml, Component component) { + return toscaExportUtils.getDependencies(component).right().map(toscaError -> { + LOGGER.debug("Failed to retrieve dependencies for component {}, error {}", component.getUniqueId(), toscaError); + return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError)); + }).left().map(tt -> ToscaRepresentation.make(mainYml, tt)); + } + + private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(ArtifactDefinition artifactDef) { + return getFromCassandra(artifactDef.getEsId()).right().map(as -> { + LOGGER.debug(ARTIFACT_NAME_UNIQUE_ID, artifactDef.getArtifactName(), artifactDef.getUniqueId()); + return componentsUtils.getResponseFormat(as); + }).left().map(ToscaRepresentation::make); + } + + private Either<byte[], ActionStatus> getFromCassandra(String cassandraId) { + return artifactCassandraDao.getArtifact(cassandraId).right().map(operationstatus -> { + LOGGER.info("Failed to fetch artifact from Cassandra by id {} error {}.", cassandraId, operationstatus); + StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(operationstatus); + return componentsUtils.convertFromStorageResponse(storageStatus); + }).left().map(DAOArtifactData::getDataAsArray); + } + + private static <L, R> F<L, Either<L, R>> iff(Predicate<L> p, Function<L, Either<L, R>> ifTrue) { + return l -> p.test(l) ? ifTrue.apply(l) : Either.left(l); + } + + private static <A, B> F<A, B> iff(Predicate<A> p, Supplier<B> s, Function<A, B> orElse) { + return a -> p.test(a) ? s.get() : orElse.apply(a); + } + + private void addServiceMf(Component component, ZipOutputStream zip, LifecycleStateEnum lifecycleState, boolean isInCertificationRequest, + String fileName, byte[] mainYaml, String definitionsPath) throws IOException { + // add mf + if ((component.getComponentType() == ComponentTypeEnum.SERVICE) && (lifecycleState != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { + String serviceName = component.getName(); + String createdBy = component.getCreatorUserId(); + String serviceVersion; + if (isInCertificationRequest) { + int tmp = Integer.valueOf(component.getVersion().split("\\.")[0]) + 1; + serviceVersion = String.valueOf(tmp) + ".0"; + } else { + serviceVersion = component.getVersion(); + } + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'"); + format.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = new Date(); + String releaseTime = format.format(date); + if (component.getCategories() == null || component.getCategories().get(0) == null) { + return; + } + String serviceType = component.getCategories().get(0).getName(); + String description = component.getDescription(); + String serviceTemplate = definitionsPath + fileName; + String hash = GeneralUtility.calculateMD5Base64EncodedByByteArray(mainYaml); + String nsMfBlock0 = createNsMfBlock0(serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate, + hash); + byte[] nsMfBlock0Byte = nsMfBlock0.getBytes(); + zip.putNextEntry(new ZipEntry(SERVICE_MANIFEST)); + zip.write(nsMfBlock0Byte); + } + } + + private String createNsMfBlock0(String serviceName, String createdBy, String serviceVersion, String releaseTime, String serviceType, + String description, String serviceTemplate, String hash) { + final String block0template = "metadata??\n" + "ns_product_name: %s\n" + "ns_provider_id: %s\n" + "ns_package_version: %s\n" + + "ns_release_data_time: %s\n" + "ns_type: %s\n" + "ns_package_description: %s\n\n" + "Source: %s\n" + "Algorithm: MD5\n" + "Hash: %s\n\n"; + return String.format(block0template, serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate, hash); + } + + private boolean hasToWriteComponentSubstitutionType(final Component component) { + final Map<String, CategoryBaseTypeConfig> serviceNodeTypesConfig = + ConfigurationManager.getConfigurationManager().getConfiguration().getServiceBaseNodeTypes(); + List<CategoryDefinition> categories = component.getCategories(); + if (CollectionUtils.isNotEmpty(categories) && MapUtils.isNotEmpty(serviceNodeTypesConfig) + && serviceNodeTypesConfig.get(categories.get(0).getName()) != null) { + boolean doNotExtendBaseType = serviceNodeTypesConfig.get(categories.get(0).getName()).isDoNotExtendBaseType(); + if (doNotExtendBaseType) { + return false; + } + } + if (component instanceof Service) { + return !ModelConverter.isAtomicComponent(component) && ((Service) component).isSubstituteCandidate(); + } + return !ModelConverter.isAtomicComponent(component); + } + + private Either<ZipOutputStream, ResponseFormat> writeComponentInterface(Either<ToscaRepresentation, ToscaError> interfaceRepresentation, + ZipOutputStream zip, String fileName, String definitionsPath) { + // TODO: This should not be done but we need this to keep the refactoring small enough to be easily reviewable + return writeComponentInterface(interfaceRepresentation, fileName, ZipWriter.live(zip), definitionsPath) + .map(void0 -> Either.<ZipOutputStream, ResponseFormat>left(zip)).recover(th -> { + LOGGER.error("#writeComponentInterface - zip writing failed with error: ", th); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + }).get(); + } + + private Try<Void> writeComponentInterface( + Either<ToscaRepresentation, ToscaError> interfaceRepresentation, String fileName, ZipWriter zw, String definitionsPath) { + Either<byte[], ToscaError> yml = interfaceRepresentation.left() + .map(ToscaRepresentation::getMainYaml); + return fromEither(yml, ToscaErrorException::new).flatMap(zw.write(definitionsPath + ToscaExportHandler.getInterfaceFilename(fileName))); + } + + private List<Triple<String, String, Component>> writeComponentInterface(final Component component, final ZipOutputStream zip, + final String fileName, final String definitionsPath) { + final Either<ToscaRepresentation, ToscaError> interfaceRepresentation = toscaExportUtils.exportComponentInterface(component, false); + writeComponentInterface(interfaceRepresentation, zip, fileName, definitionsPath); + return interfaceRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>()); + } + + private Either<ZipOutputStream, ResponseFormat> getZipOutputStreamResponseFormatEither(ZipOutputStream zip, + List<Triple<String, String, Component>> dependencies, + String definitionsPath) + throws IOException { + ComponentCache + innerComponentsCache = ComponentCache.overwritable(overwriteIfSameVersions()).onMerge((oldValue, newValue) -> + LOGGER.warn("Overwriting component invariantID {} of version {} with a newer version {}", oldValue.getId(), + oldValue.getComponentVersion(), + newValue.getComponentVersion())); + if (dependencies != null && !dependencies.isEmpty()) { + for (Triple<String, String, Component> d : dependencies) { + String cassandraId = d.getMiddle(); + Component childComponent = d.getRight(); + Either<byte[], ResponseFormat> entryData = getEntryData(cassandraId, childComponent).right() + .map(componentsUtils::getResponseFormat); + if (entryData.isRight()) { + return Either.right(entryData.right().value()); + } + //fill innerComponentsCache + String fileName = d.getLeft(); + innerComponentsCache.put(cassandraId, fileName, childComponent); + addInnerComponentsToCache(innerComponentsCache, childComponent); + } + //add inner components to CSAR + return addInnerComponentsToCSAR(zip, innerComponentsCache, definitionsPath); + } + return null; + } + + private Either<ZipOutputStream, ResponseFormat> addInnerComponentsToCSAR(ZipOutputStream zip, ComponentCache innerComponentsCache, + String definitionsPath) + throws IOException { + for (ImmutableTriple<String, String, Component> ict : innerComponentsCache.iterable()) { + Component innerComponent = ict.getRight(); + String icFileName = ict.getMiddle(); + // add component to zip + Either<Tuple2<byte[], ZipEntry>, ResponseFormat> zipEntry = toZipEntry(ict, definitionsPath); + // TODO: this should not be done, we should instead compose this either further, + + // but in order to keep this refactoring small, we'll stop here. + if (zipEntry.isRight()) { + return Either.right(zipEntry.right().value()); + } + Tuple2<byte[], ZipEntry> value = zipEntry.left().value(); + zip.putNextEntry(value._2); + zip.write(value._1); + // add component interface to zip + if (hasToWriteComponentSubstitutionType(innerComponent)) { + writeComponentInterface(innerComponent, zip, icFileName, definitionsPath); + } + } + return null; + } + + private Either<Tuple2<byte[], ZipEntry>, ResponseFormat> toZipEntry(ImmutableTriple<String, String, Component> cachedEntry, + String definitionsPath) { + String cassandraId = cachedEntry.getLeft(); + String fileName = cachedEntry.getMiddle(); + Component innerComponent = cachedEntry.getRight(); + return getEntryData(cassandraId, innerComponent).right().map(status -> { + LOGGER.debug("Failed adding to zip component {}, error {}", cassandraId, status); + return componentsUtils.getResponseFormat(status); + }).left().map(content -> new Tuple2<>(content, new ZipEntry(definitionsPath + fileName))); + } + + private void addInnerComponentsToCache(ComponentCache componentCache, Component childComponent) { + javaListToVavrList(childComponent.getComponentInstances()).filter(ci -> componentCache.notCached(ci.getComponentUid())).forEach(ci -> { + // all resource must be only once! + Either<Resource, StorageOperationStatus> resource = toscaOperationFacade.getToscaElement(ci.getComponentUid()); + Component componentRI = checkAndAddComponent(componentCache, ci, resource); + //if not atomic - insert inner components as well + + // TODO: This could potentially create a StackOverflowException if the call stack + + // happens to be too large. Tail-recursive optimization should be used here. + if (!ModelConverter.isAtomicComponent(componentRI)) { + addInnerComponentsToCache(componentCache, componentRI); + } + }); + } + + private Component checkAndAddComponent(ComponentCache componentCache, ComponentInstance ci, Either<Resource, StorageOperationStatus> resource) { + if (resource.isRight()) { + LOGGER.debug("Failed to fetch resource with id {} for instance {}", ci.getComponentUid(), ci.getName()); + } + Component componentRI = resource.left().value(); + Map<String, ArtifactDefinition> childToscaArtifacts = componentRI.getToscaArtifacts(); + ArtifactDefinition childArtifactDefinition = childToscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); + if (childArtifactDefinition != null) { + //add to cache + componentCache.put(childArtifactDefinition.getEsId(), childArtifactDefinition.getArtifactName(), componentRI); + } + return componentRI; + } + + private Either<byte[], ActionStatus> getEntryData(String cassandraId, Component childComponent) { + if (cassandraId == null || cassandraId.isEmpty()) { + return toscaExportUtils.exportComponent(childComponent).right().map(toscaErrorToActionStatus(childComponent)).left() + .map(ToscaRepresentation::getMainYaml); + } else { + return getFromCassandra(cassandraId); + } + } + + private F<ToscaError, ActionStatus> toscaErrorToActionStatus(Component childComponent) { + return toscaError -> { + LOGGER.debug("Failed to export tosca template for child component {} error {}", childComponent.getUniqueId(), toscaError); + return componentsUtils.convertFromToscaError(toscaError); + }; + } + + private Either<byte[], ResponseFormat> getLatestSchemaFilesFromCassandra() { + String fto = versionFirstThreeOctets; + return sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(fto, CONFORMANCE_LEVEL).right().map(schemaFilesFetchDBError(fto)).left() + .bind(iff(List::isEmpty, () -> schemaFileFetchError(fto), s -> Either.left(s.iterator().next().getPayloadAsArray()))); + } + + private F<CassandraOperationStatus, ResponseFormat> schemaFilesFetchDBError(String firstThreeOctets) { + return cos -> { + LOGGER.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}. Please fix DB table accordingly.", firstThreeOctets, + CONFORMANCE_LEVEL); + StorageOperationStatus sos = DaoStatusConverter.convertCassandraStatusToStorageStatus(cos); + return componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(sos)); + }; + } + + private Either<byte[], ResponseFormat> schemaFileFetchError(String firstThreeOctets) { + LOGGER.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", firstThreeOctets, CONFORMANCE_LEVEL); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_SCHEMA_FILES_NOT_FOUND, firstThreeOctets, CONFORMANCE_LEVEL)); + } + + /** + * Create a list of all derived nodes found on the package + * + * @param dependencies all node dependencies + * @return a list of nodes + */ + private List<String> findNonRootNodesFromPackage(final List<Triple<String, String, Component>> dependencies) { + final List<String> nodes = new ArrayList<>(); + if (CollectionUtils.isNotEmpty(dependencies)) { + final String NATIVE_ROOT = "tosca.nodes.Root"; + dependencies.forEach(dependency -> { + if (dependency.getRight() instanceof Resource) { + final Resource resource = (Resource) dependency.getRight(); + if (CollectionUtils.isNotEmpty(resource.getDerivedList())) { + resource.getDerivedList().stream().filter(node -> !nodes.contains(node) && !NATIVE_ROOT.equalsIgnoreCase(node)) + .forEach(node -> nodes.add(node)); + } + } + }); + } + return nodes; + } + + /** + * Writes to a CSAR zip from casandra schema data + * + * @param zipOutputStream stores the input stream content + * @param schemaFileZip zip data from Cassandra + * @param nodesFromPackage list of all nodes found on the onboarded package + */ + private void addSchemaFilesFromCassandra(final ZipOutputStream zipOutputStream, final byte[] schemaFileZip, final List<String> nodesFromPackage, + final String definitionsPath) { + final int initSize = 2048; + LOGGER.debug("Starting copy from Schema file zip to CSAR zip"); + try (final ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream( + schemaFileZip)); final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( + byteArrayOutputStream, initSize)) { + ZipEntry entry; + while ((entry = zipInputStream.getNextEntry()) != null) { + ZipUtils.checkForZipSlipInRead(entry); + final String entryName = entry.getName(); + int readSize = initSize; + final byte[] entryData = new byte[initSize]; + if (shouldZipEntryBeHandled(entryName)) { + if (NODES_YML.equalsIgnoreCase(entryName)) { + handleNode(zipInputStream, byteArrayOutputStream, nodesFromPackage); + } else { + while ((readSize = zipInputStream.read(entryData, 0, readSize)) != -1) { + bufferedOutputStream.write(entryData, 0, readSize); + } + bufferedOutputStream.flush(); + } + byteArrayOutputStream.flush(); + zipOutputStream.putNextEntry(new ZipEntry(definitionsPath + entryName)); + zipOutputStream.write(byteArrayOutputStream.toByteArray()); + zipOutputStream.flush(); + byteArrayOutputStream.reset(); + } + } + } catch (final Exception e) { + LOGGER.error("Error while writing the SDC schema file to the CSAR", e); + throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + LOGGER.debug("Finished copy from Schema file zip to CSAR zip"); + } + + /** + * Handles the nodes.yml zip entry, updating the nodes.yml to avoid duplicated nodes on it. + * + * @param zipInputStream the zip entry to be read + * @param byteArrayOutputStream an output stream in which the data is written into a byte array. + * @param nodesFromPackage list of all nodes found on the onboarded package + */ + private void handleNode(final ZipInputStream zipInputStream, final ByteArrayOutputStream byteArrayOutputStream, + final List<String> nodesFromPackage) throws IOException { + final Map<String, Object> nodesFromArtifactFile = readYamlZipEntry(zipInputStream); + final Map<String, Object> nodesYaml = updateNodeYml(nodesFromPackage, nodesFromArtifactFile); + updateZipEntry(byteArrayOutputStream, nodesYaml); + } + + /** + * Updates the zip entry from the given parameters + * + * @param byteArrayOutputStream an output stream in which the data is written into a byte array. + * @param nodesYaml a Map of nodes to be written + */ + private void updateZipEntry(final ByteArrayOutputStream byteArrayOutputStream, final Map<String, Object> nodesYaml) throws IOException { + if (MapUtils.isNotEmpty(nodesYaml)) { + byteArrayOutputStream.write(new YamlUtil().objectToYaml(nodesYaml).getBytes()); + } + } + + /** + * Filters and removes all duplicated nodes found + * + * @param nodesFromPackage a List of all derived nodes found on the given package + * @param nodesFromArtifactFile represents the nodes.yml file stored in Cassandra + * @return a nodes Map updated + */ + private Map<String, Object> updateNodeYml(final List<String> nodesFromPackage, final Map<String, Object> nodesFromArtifactFile) { + if (MapUtils.isNotEmpty(nodesFromArtifactFile)) { + final String nodeTypeBlock = TypeUtils.ToscaTagNamesEnum.NODE_TYPES.getElementName(); + final Map<String, Object> nodeTypes = (Map<String, Object>) nodesFromArtifactFile.get(nodeTypeBlock); + nodesFromPackage.stream().filter(nodeTypes::containsKey).forEach(nodeTypes::remove); + nodesFromArtifactFile.replace(nodeTypeBlock, nodeTypes); + } + return nodesFromArtifactFile; + } + + /** + * Writes a new zip entry + * + * @param zipInputStream the zip entry to be read + * @return a map of the given zip entry + */ + private Map<String, Object> readYamlZipEntry(final ZipInputStream zipInputStream) throws IOException { + final int initSize = 2048; + final StringBuilder zipEntry = new StringBuilder(); + final byte[] buffer = new byte[initSize]; + int read = 0; + while ((read = zipInputStream.read(buffer, 0, initSize)) >= 0) { + zipEntry.append(new String(buffer, 0, read)); + } + return (Map<String, Object>) new Yaml().load(zipEntry.toString()); + } + + /** + * Checks if the zip entry should or should not be added to the CSAR based on the given global type list + * + * @param entryName the zip entry name + * @return true if the zip entry should be handled + */ + private boolean shouldZipEntryBeHandled(final String entryName) { + return ConfigurationManager.getConfigurationManager().getConfiguration().getGlobalCsarImports().stream() + .anyMatch(entry -> entry.contains(entryName)); + } + + private void addSchemaFilesByModel(final ZipOutputStream zipOutputStream, final String modelName, + final String definitionsPath, final boolean isSingleImportsFile) { + try { + final List<ToscaImportByModel> modelDefaultImportList = modelOperation.findAllModelImports(modelName, true); + final Set<Path> writtenEntryPathList = new HashSet<>(); + final var defsPath = Path.of(definitionsPath); + Map<Path, byte[]> contentToMerge = new HashMap(); + for (final ToscaImportByModel toscaImportByModel : modelDefaultImportList) { + var importPath = Path.of(toscaImportByModel.getFullPath()); + if (!isSingleImportsFile) { + if (ADDITIONAL_TYPE_DEFINITIONS.equals(Paths.get(String.valueOf(importPath)).normalize().toString())) { + final Path entryPath = defsPath.resolve(importPath); + contentToMerge.put(entryPath, toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8)); + } else { + if (writtenEntryPathList.contains(defsPath.resolve(importPath))) { + importPath = + ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId()); + } + final Path entryPath = defsPath.resolve(importPath); + writtenEntryPathList.add(entryPath); + contentToMerge.put(entryPath, toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8)); + } + } else { + if (writtenEntryPathList.contains(defsPath.resolve(importPath))) { + importPath = + ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId()); + } + final Path entryPath = defsPath.resolve(importPath); + final var zipEntry = new ZipEntry(entryPath.toString()); + zipOutputStream.putNextEntry(zipEntry); + writtenEntryPathList.add(entryPath); + final byte[] content = toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8); + zipOutputStream.write(content, 0, content.length); + zipOutputStream.closeEntry(); + } + } + if (!isSingleImportsFile) { + byte[] mergingContent = new byte[0]; + for (Map.Entry entry : contentToMerge.entrySet()) { + if (ADDITIONAL_TYPE_DEFINITIONS.equals(Paths.get(String.valueOf(entry.getKey())).normalize().toString())) { + mergingContent = (byte[]) entry.getValue(); + } else { + final var zipEntry = new ZipEntry(entry.getKey().toString()); + zipOutputStream.putNextEntry(zipEntry); + writtenEntryPathList.add((Path) entry.getKey()); + zipOutputStream.write(Bytes.concat(mergingContent, (byte[]) entry.getValue()), 0, + ((byte[]) entry.getValue()).length); + zipOutputStream.closeEntry(); + } + } + } + } catch (final IOException e) { + LOGGER.error(String.valueOf(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR), CsarUtils.class.getName(), + "Error while writing the schema files by model to the CSAR", e); + throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.CSAR_TOSCA_IMPORTS_ERROR)); + } + } + + private Either<CsarDefinition, ResponseFormat> collectComponentCsarDefinition(Component component) { + ComponentArtifacts componentArtifacts = new ComponentArtifacts(); + Component updatedComponent = component; + + //get service to receive the AII artifacts uploaded to the service + if (updatedComponent.getComponentType() == ComponentTypeEnum.SERVICE) { + Either<Service, StorageOperationStatus> getServiceResponse = toscaOperationFacade.getToscaElement(updatedComponent.getUniqueId()); + + if (getServiceResponse.isRight()) { + ActionStatus actionStatus = componentsUtils.convertFromStorageResponse(getServiceResponse.right().value()); + return Either.right(componentsUtils.getResponseFormat(actionStatus)); + } + + updatedComponent = getServiceResponse.left().value(); + } + + //find the artifacts of the main component, it would have its composed instances artifacts in a separate folder + ComponentTypeArtifacts componentInstanceArtifacts = new ComponentTypeArtifacts(); + ArtifactsInfo artifactsInfo = collectComponentArtifacts(updatedComponent); + componentInstanceArtifacts.setComponentArtifacts(artifactsInfo); + componentArtifacts.setMainTypeAndCIArtifacts(componentInstanceArtifacts); + + Map<String, ComponentTypeArtifacts> resourceTypeArtifacts = componentArtifacts + .getComponentTypeArtifacts(); //artifacts mapped by the component type(tosca name+version) + //get the component instances + List<ComponentInstance> componentInstances = updatedComponent.getComponentInstances(); + if (componentInstances != null) { + for (ComponentInstance componentInstance : componentInstances) { + //call recursive to find artifacts for all the path + Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts( + updatedComponent, componentInstance, resourceTypeArtifacts, componentInstanceArtifacts); + if (collectComponentInstanceArtifacts.isRight()) { + return Either.right(collectComponentInstanceArtifacts.right().value()); + } + } + } + + if (LOGGER.isDebugEnabled()) { + printResult(componentArtifacts, updatedComponent.getName()); + } + + return Either.left(new CsarDefinition(componentArtifacts)); + } + + private void printResult(ComponentArtifacts componentArtifacts, String name) { + StringBuilder result = new StringBuilder(); + result.append("Artifacts of main component " + name + "\n"); + ComponentTypeArtifacts componentInstanceArtifacts = componentArtifacts.getMainTypeAndCIArtifacts(); + printArtifacts(componentInstanceArtifacts); + result.append("Type Artifacts\n"); + for (Map.Entry<String, ComponentTypeArtifacts> typeArtifacts : componentArtifacts.getComponentTypeArtifacts().entrySet()) { + result.append("Folder " + typeArtifacts.getKey() + "\n"); + result.append(printArtifacts(typeArtifacts.getValue())); + } + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(result.toString()); + } + } + + private String printArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) { + StringBuilder result = new StringBuilder(); + ArtifactsInfo artifactsInfo = componentInstanceArtifacts.getComponentArtifacts(); + Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentArtifacts = artifactsInfo.getArtifactsInfo(); + printArtifacts(componentArtifacts); + result = result.append("Resources\n"); + for (Map.Entry<String, ArtifactsInfo> resourceInstance : componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()) { + result.append("Folder" + resourceInstance.getKey() + "\n"); + result.append(printArtifacts(resourceInstance.getValue().getArtifactsInfo())); + } + + return result.toString(); + } + + private String printArtifacts(Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componetArtifacts) { + StringBuilder result = new StringBuilder(); + for (Map.Entry<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactGroup : componetArtifacts.entrySet()) { + result.append(" " + artifactGroup.getKey().getType()); + for (Map.Entry<String, List<ArtifactDefinition>> groupArtifacts : artifactGroup.getValue().entrySet()) { + result.append(" " + groupArtifacts.getKey()); + for (ArtifactDefinition artifact : groupArtifacts.getValue()) { + result.append(" " + artifact.getArtifactDisplayName()); + } + } + } + + return result.toString(); + } + + private Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts(Component parentComponent, ComponentInstance componentInstance, + Map<String, ComponentTypeArtifacts> resourcesTypeArtifacts, + ComponentTypeArtifacts instanceArtifactsLocation) { + //1. get the component instance component + String componentUid; + if (componentInstance.getOriginType() == OriginTypeEnum.ServiceProxy) { + componentUid = componentInstance.getSourceModelUid(); + } else { + componentUid = componentInstance.getComponentUid(); + } + Either<Component, StorageOperationStatus> component = toscaOperationFacade.getToscaElement(componentUid); + if (component.isRight()) { + LOGGER.error("Failed to fetch resource with id {} for instance {}", componentUid, parentComponent.getUUID()); + return Either.right(componentsUtils.getResponseFormat(ActionStatus.ASSET_NOT_FOUND_DURING_CSAR_CREATION, + parentComponent.getComponentType().getValue(), parentComponent.getUUID(), + componentInstance.getOriginType().getComponentType().getValue(), componentUid)); + } + Component fetchedComponent = component.left().value(); + + //2. fill the artifacts for the current component parent type + String toscaComponentName = + componentInstance.getToscaComponentName() + "_v" + componentInstance.getComponentVersion(); + + // if there are no artifacts for this component type we need to fetch and build them + ComponentTypeArtifacts componentParentArtifacts = Optional + .ofNullable(resourcesTypeArtifacts.get(toscaComponentName)) + .orElseGet(() -> collectComponentTypeArtifacts(fetchedComponent)); + + if (componentParentArtifacts.getComponentArtifacts().isNotEmpty()) { + resourcesTypeArtifacts.put(toscaComponentName, componentParentArtifacts); + } + + //3. find the artifacts specific to the instance + Map<String, List<ArtifactDefinition>> componentInstanceSpecificInformationalArtifacts = + getComponentInstanceSpecificArtifacts(componentInstance.getArtifacts(), + componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.INFORMATIONAL); + Map<String, List<ArtifactDefinition>> componentInstanceSpecificDeploymentArtifacts = + getComponentInstanceSpecificArtifacts(componentInstance.getDeploymentArtifacts(), + componentParentArtifacts.getComponentArtifacts().getArtifactsInfo(), ArtifactGroupTypeEnum.DEPLOYMENT); + + //4. add the instances artifacts to the component type + ArtifactsInfo artifactsInfo = new ArtifactsInfo(); + if (!componentInstanceSpecificInformationalArtifacts.isEmpty()) { + artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, componentInstanceSpecificInformationalArtifacts); + } + if (!componentInstanceSpecificDeploymentArtifacts.isEmpty()) { + artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, componentInstanceSpecificDeploymentArtifacts); + } + if (!artifactsInfo.isEmpty()) { + instanceArtifactsLocation.addComponentInstancesArtifacts(componentInstance.getNormalizedName(), artifactsInfo); + } + + //5. do the same for all the component instances + List<ComponentInstance> componentInstances = fetchedComponent.getComponentInstances(); + if (componentInstances != null) { + for (ComponentInstance childComponentInstance : componentInstances) { + Either<Boolean, ResponseFormat> collectComponentInstanceArtifacts = collectComponentInstanceArtifacts( + fetchedComponent, childComponentInstance, resourcesTypeArtifacts, componentParentArtifacts); + if (collectComponentInstanceArtifacts.isRight()) { + return collectComponentInstanceArtifacts; + } + } + } + + return Either.left(true); + } + + private Map<String, List<ArtifactDefinition>> getComponentInstanceSpecificArtifacts(Map<String, ArtifactDefinition> componentArtifacts, + Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentTypeArtifacts, + ArtifactGroupTypeEnum artifactGroupTypeEnum) { + Map<String, List<ArtifactDefinition>> parentArtifacts = componentTypeArtifacts + .get(artifactGroupTypeEnum); //the artfiacts of the component itself and not the instance + + Map<String, List<ArtifactDefinition>> artifactsByTypeOfComponentInstance = new HashMap<>(); + if (componentArtifacts != null) { + for (ArtifactDefinition artifact : componentArtifacts.values()) { + List<ArtifactDefinition> parentArtifactsByType = null; + if (parentArtifacts != null) { + parentArtifactsByType = parentArtifacts.get(artifact.getArtifactType()); + } + //the artifact is of instance + if (parentArtifactsByType == null || !parentArtifactsByType.contains(artifact)) { + List<ArtifactDefinition> typeArtifacts = artifactsByTypeOfComponentInstance.get(artifact.getArtifactType()); + if (typeArtifacts == null) { + typeArtifacts = new ArrayList<>(); + artifactsByTypeOfComponentInstance.put(artifact.getArtifactType(), typeArtifacts); + } + typeArtifacts.add(artifact); + } + } + } + + return artifactsByTypeOfComponentInstance; + } + + private ComponentTypeArtifacts collectComponentTypeArtifacts(Component fetchedComponent) { + ArtifactsInfo componentArtifacts = collectComponentArtifacts(fetchedComponent); + ComponentTypeArtifacts componentArtifactsInfo = new ComponentTypeArtifacts(); + if (componentArtifacts.isNotEmpty()) { + componentArtifactsInfo.setComponentArtifacts(componentArtifacts); + } + return componentArtifactsInfo; + } + + private ArtifactsInfo collectComponentArtifacts(Component component) { + Map<String, ArtifactDefinition> informationalArtifacts = component.getArtifacts(); + Map<String, List<ArtifactDefinition>> informationalArtifactsByType = collectGroupArtifacts(informationalArtifacts); + Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts(); + Map<String, List<ArtifactDefinition>> deploymentArtifactsByType = collectGroupArtifacts(deploymentArtifacts); + ArtifactsInfo artifactsInfo = new ArtifactsInfo(); + if (!informationalArtifactsByType.isEmpty()) { + artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.INFORMATIONAL, informationalArtifactsByType); + } + if (!deploymentArtifactsByType.isEmpty()) { + artifactsInfo.addArtifactsToGroup(ArtifactGroupTypeEnum.DEPLOYMENT, deploymentArtifactsByType); + } + + return artifactsInfo; + } + + private Map<String, List<ArtifactDefinition>> collectGroupArtifacts( + final Map<String, ArtifactDefinition> componentArtifacts) { + final Map<String, List<ArtifactDefinition>> artifactsByType = new HashMap<>(); + for (final ArtifactDefinition artifact : componentArtifacts.values()) { + if (artifact.getArtifactUUID() != null) { + artifactsByType.putIfAbsent(artifact.getArtifactType(), new ArrayList<>()); + final List<ArtifactDefinition> typeArtifacts = artifactsByType.get(artifact.getArtifactType()); + typeArtifacts.add(artifact); + } + } + return artifactsByType; + } + + private Either<ZipOutputStream, ResponseFormat> writeAllFilesToCsar(Component mainComponent, CsarDefinition csarDefinition, + ZipOutputStream zipstream, boolean isInCertificationRequest) + throws IOException { + ComponentArtifacts componentArtifacts = csarDefinition.getComponentArtifacts(); + Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath = writeComponentArtifactsToSpecifiedPath(mainComponent, + componentArtifacts, zipstream, ARTIFACTS_PATH, isInCertificationRequest); + if (writeComponentArtifactsToSpecifiedPath.isRight()) { + return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); + } + ComponentTypeArtifacts mainTypeAndCIArtifacts = componentArtifacts.getMainTypeAndCIArtifacts(); + writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, mainTypeAndCIArtifacts.getComponentArtifacts(), + zipstream, ARTIFACTS_PATH, isInCertificationRequest); + if (writeComponentArtifactsToSpecifiedPath.isRight()) { + return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); + } + Map<String, ArtifactsInfo> componentInstancesArtifacts = mainTypeAndCIArtifacts.getComponentInstancesArtifacts(); + String currentPath = ARTIFACTS_PATH + RESOURCES_PATH; + for (String keyAssetName : componentInstancesArtifacts.keySet()) { + ArtifactsInfo artifactsInfo = componentInstancesArtifacts.get(keyAssetName); + String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER; + writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, artifactsInfo, zipstream, pathWithAssetName, + isInCertificationRequest); + if (writeComponentArtifactsToSpecifiedPath.isRight()) { + return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); + } + } + writeComponentArtifactsToSpecifiedPath = writeOperationsArtifactsToCsar(mainComponent, zipstream); + if (writeComponentArtifactsToSpecifiedPath.isRight()) { + return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); + } + return Either.left(zipstream); + } + + private Either<ZipOutputStream, ResponseFormat> writeOperationsArtifactsToCsar(Component component, ZipOutputStream zipstream) { + if (checkComponentBeforeOperation(component)) { + return Either.left(zipstream); + } + for (Map.Entry<String, InterfaceDefinition> interfaceEntry : ((Resource) component).getInterfaces().entrySet()) { + for (OperationDataDefinition operation : interfaceEntry.getValue().getOperations().values()) { + try { + if (checkComponentBeforeWrite(component, interfaceEntry, operation)) { + continue; + } + final String artifactUUID = operation.getImplementation().getArtifactUUID(); + if (artifactUUID == null) { + continue; + } + final Either<byte[], ActionStatus> artifactFromCassandra = getFromCassandra(artifactUUID); + final String artifactName = operation.getImplementation().getArtifactName(); + if (artifactFromCassandra.isRight()) { + LOGGER.error(ARTIFACT_NAME_UNIQUE_ID, artifactName, artifactUUID); + LOGGER.error("Failed to get {} payload from DB reason: {}", artifactName, artifactFromCassandra.right().value()); + return Either.right(componentsUtils.getResponseFormat( + ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, "Resource", component.getUniqueId(), artifactName, artifactUUID)); + } + zipstream.putNextEntry(new ZipEntry(OperationArtifactUtil.createOperationArtifactPath(component, null, operation, true))); + zipstream.write(artifactFromCassandra.left().value()); + } catch (IOException e) { + LOGGER.error("Component Name {}, Interface Name {}, Operation Name {}", component.getNormalizedName(), interfaceEntry.getKey(), + operation.getName()); + LOGGER.error("Error while writing the operation's artifacts to the CSAR", e); + return Either.right(componentsUtils.getResponseFormat(ERROR_DURING_CSAR_CREATION, "Resource", component.getUniqueId())); + } + } + } + return Either.left(zipstream); + } + + private boolean checkComponentBeforeWrite(Component component, Map.Entry<String, InterfaceDefinition> interfaceEntry, + OperationDataDefinition operation) { + final ArtifactDataDefinition implementation = operation.getImplementation(); + if (implementation == null) { + LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - no Operation Implementation found", component.getNormalizedName(), + interfaceEntry.getValue().getUniqueId(), operation.getName()); + return true; + } + final String artifactName = implementation.getArtifactName(); + if (artifactName == null) { + LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - no artifact found", component.getNormalizedName(), + interfaceEntry.getValue().getUniqueId(), operation.getName()); + return true; + } + if (OperationArtifactUtil.artifactNameIsALiteralValue(artifactName)) { + LOGGER.debug("Component Name {}, Interface Id {}, Operation Name {} - artifact name is a literal value rather than an SDC artifact", + component.getNormalizedName(), interfaceEntry.getValue().getUniqueId(), operation.getName()); + return true; + } + return false; + } + + private boolean checkComponentBeforeOperation(Component component) { + if (component instanceof Service) { + return true; + } + if (Objects.isNull(((Resource) component).getInterfaces())) { + LOGGER.debug("Component Name {}- no interfaces found", component.getNormalizedName()); + return true; + } + return false; + } + + private Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath(final Component mainComponent, + final ArtifactsInfo currArtifactsInfo, + final ZipOutputStream zip, final String path, + final boolean isInCertificationRequest) throws IOException { + final Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfo = currArtifactsInfo.getArtifactsInfo(); + for (final ArtifactGroupTypeEnum artifactGroupTypeEnum : artifactsInfo.keySet()) { + final String groupTypeFolder = path + WordUtils.capitalizeFully(artifactGroupTypeEnum.getType()) + PATH_DELIMITER; + final Map<String, List<ArtifactDefinition>> artifactTypesMap = artifactsInfo.get(artifactGroupTypeEnum); + for (final String artifactType : artifactTypesMap.keySet()) { + final List<ArtifactDefinition> artifactDefinitionList = artifactTypesMap.get(artifactType); + String artifactTypeFolder = groupTypeFolder + artifactType + PATH_DELIMITER; + if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType) && path.contains(ARTIFACTS_PATH + RESOURCES_PATH)) { + // Ignore this packaging as BPMN artifacts needs to be packaged in different manner + continue; + } + if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType)) { + artifactTypeFolder += OperationArtifactUtil.BPMN_ARTIFACT_PATH + File.separator; + } else if (ArtifactTypeEnum.ONBOARDED_PACKAGE.getType().equals(artifactType)) { + // renaming legacy folder ONBOARDED_PACKAGE to the new folder ETSI_PACKAGE + artifactTypeFolder = artifactTypeFolder + .replace(ArtifactTypeEnum.ONBOARDED_PACKAGE.getType(), ArtifactTypeEnum.ETSI_PACKAGE.getType()); + } + // TODO: We should not do this but in order to keep this refactoring small enough, + + // we'll leave this as is for now + List<ArtifactDefinition> collect = filterArtifactDefinitionToZip(mainComponent, artifactDefinitionList, isInCertificationRequest) + .collect(Collectors.toList()); + for (ArtifactDefinition ad : collect) { + zip.putNextEntry(new ZipEntry(artifactTypeFolder + ad.getArtifactName())); + zip.write(ad.getPayloadData()); + } + } + } + return Either.left(zip); + } + + private Stream<ArtifactDefinition> filterArtifactDefinitionToZip(Component mainComponent, List<ArtifactDefinition> artifactDefinitionList, + boolean isInCertificationRequest) { + return artifactDefinitionList.stream().filter(shouldBeInZip(isInCertificationRequest, mainComponent)).map(this::fetchPayLoadData) + .filter(Either::isLeft).map(e -> e.left().value()); + } + + private Predicate<ArtifactDefinition> shouldBeInZip(boolean isInCertificationRequest, Component component) { + return artifactDefinition -> !(!isInCertificationRequest && component.isService() && artifactDefinition.isHeatEnvType() || artifactDefinition + .hasNoMandatoryEsId()); + } + + private Either<ArtifactDefinition, ActionStatus> fetchPayLoadData(ArtifactDefinition ad) { + byte[] payloadData = ad.getPayloadData(); + if (payloadData == null) { + return getFromCassandra(ad.getEsId()).left().map(pd -> { + ad.setPayload(pd); + return ad; + }).right().map(as -> { + LOGGER.debug(ARTIFACT_NAME_UNIQUE_ID, ad.getArtifactName(), ad.getUniqueId()); + LOGGER.debug("Failed to get {} payload from DB reason: {}", ad.getArtifactName(), as); + return as; + }); + } else { + return Either.left(ad); + } + } + + private Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath(Component mainComponent, + ComponentArtifacts componentArtifacts, + ZipOutputStream zipstream, String currentPath, + boolean isInCertificationRequest) throws IOException { + Map<String, ComponentTypeArtifacts> componentTypeArtifacts = componentArtifacts.getComponentTypeArtifacts(); + //Keys are defined: + + //<Inner Asset TOSCA name (e.g. VFC name)> folder name: <Inner Asset TOSCA name (e.g. VFC name)>_v<version>. + + //E.g. "org.openecomp.resource.vf.vipr_atm_v1.0" + Set<String> componentTypeArtifactsKeys = componentTypeArtifacts.keySet(); + for (String keyAssetName : componentTypeArtifactsKeys) { + ComponentTypeArtifacts componentInstanceArtifacts = componentTypeArtifacts.get(keyAssetName); + ArtifactsInfo componentArtifacts2 = componentInstanceArtifacts.getComponentArtifacts(); + String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER; + Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, + componentArtifacts2, zipstream, pathWithAssetName, isInCertificationRequest); + if (writeArtifactsInfoToSpecifiedPath.isRight()) { + return writeArtifactsInfoToSpecifiedPath; + } + } + return Either.left(zipstream); + } + + private Either<ToscaRepresentation, ResponseFormat> generateToscaRepresentation(Component component, boolean isSkipImports) { + return toscaExportUtils.exportComponent(component, isSkipImports).right().map(toscaError -> { + LOGGER.debug("exportComponent failed {}", toscaError); + return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError)); + }); + } + + private String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef, boolean isAsdPackage, + String definitionsPath) { + final String block0template = "TOSCA-Meta-File-Version: %s\nCSAR-Version: %s\nCreated-By: %s\nEntry-Definitions: " + + definitionsPath + "%s\n%s\nName: csar.meta\nContent-Type: text/plain\n"; + return String.format(block0template, metaFileVersion, csarVersion, createdBy, entryDef, isAsdPackage ? "entry_definition_type: asd" : ""); + } + + private class CsarDefinition { + + private ComponentArtifacts componentArtifacts; + + // add list of tosca artifacts and meta describes CSAR zip root + public CsarDefinition(ComponentArtifacts componentArtifacts) { + this.componentArtifacts = componentArtifacts; + } + + public ComponentArtifacts getComponentArtifacts() { + return componentArtifacts; + } + } + + private class ComponentArtifacts { + + //artifacts of the component and CI's artifacts contained in it's composition (represents Informational, Deployment & Resource folders of main component) + private ComponentTypeArtifacts mainTypeAndCIArtifacts; + //artifacts of all component types mapped by their tosca name + private Map<String, ComponentTypeArtifacts> componentTypeArtifacts; + + public ComponentArtifacts() { + mainTypeAndCIArtifacts = new ComponentTypeArtifacts(); + componentTypeArtifacts = new HashMap<>(); + } + + public ComponentTypeArtifacts getMainTypeAndCIArtifacts() { + return mainTypeAndCIArtifacts; + } + + public void setMainTypeAndCIArtifacts(ComponentTypeArtifacts componentInstanceArtifacts) { + this.mainTypeAndCIArtifacts = componentInstanceArtifacts; + } + + public Map<String, ComponentTypeArtifacts> getComponentTypeArtifacts() { + return componentTypeArtifacts; + } + } + + /** + * The artifacts of the component and of all its composed instances + */ + private class ComponentTypeArtifacts { + + private ArtifactsInfo componentArtifacts; //component artifacts (describes the Informational Deployment folders) + + private Map<String, ArtifactsInfo> componentInstancesArtifacts; //artifacts of the composed instances mapped by the resourceInstance normalized name (describes the Resources folder) + + public ComponentTypeArtifacts() { + componentArtifacts = new ArtifactsInfo(); + componentInstancesArtifacts = new HashMap<>(); + } + + public ArtifactsInfo getComponentArtifacts() { + return componentArtifacts; + } + + public void setComponentArtifacts(ArtifactsInfo artifactsInfo) { + this.componentArtifacts = artifactsInfo; + } + + public Map<String, ArtifactsInfo> getComponentInstancesArtifacts() { + return componentInstancesArtifacts; + } + + public void addComponentInstancesArtifacts(String normalizedName, ArtifactsInfo artifactsInfo) { + componentInstancesArtifacts.put(normalizedName, artifactsInfo); + } + } + + /** + * The artifacts Definition saved by their structure + */ + private class ArtifactsInfo { + //Key is the type of artifacts(Informational/Deployment) + + //Value is a map between an artifact type and a list of all artifacts of this type + private Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfoField; + + public ArtifactsInfo() { + this.artifactsInfoField = new EnumMap<>(ArtifactGroupTypeEnum.class); + } + + public Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> getArtifactsInfo() { + return artifactsInfoField; + } + + public void addArtifactsToGroup(ArtifactGroupTypeEnum artifactGroup, Map<String, List<ArtifactDefinition>> artifactsDefinition) { + if (artifactsInfoField.get(artifactGroup) == null) { + artifactsInfoField.put(artifactGroup, artifactsDefinition); + } else { + Map<String, List<ArtifactDefinition>> artifactTypeEnumListMap = artifactsInfoField.get(artifactGroup); + artifactTypeEnumListMap.putAll(artifactsDefinition); + artifactsInfoField.put(artifactGroup, artifactTypeEnumListMap); + } + } + + public boolean isEmpty() { + return artifactsInfoField.isEmpty(); + } + + public boolean isNotEmpty() { + return !isEmpty(); + } + } + + public static class ToscaErrorException extends Exception { + + ToscaErrorException(ToscaError error) { + super("Error while exporting component's interface (toscaError:" + error + ")"); + } + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ComponentCache.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ComponentCache.java index 57ebcf6822..51719236ca 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ComponentCache.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ComponentCache.java @@ -27,6 +27,7 @@ import io.vavr.collection.Stream; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import lombok.EqualsAndHashCode; +import lombok.Getter; import org.apache.commons.lang3.tuple.ImmutableTriple; import org.openecomp.sdc.be.model.Component; @@ -132,6 +133,7 @@ public final class ComponentCache { * Entry stored by the cache */ @EqualsAndHashCode + @Getter public static final class CacheEntry { final String id; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java index 6a35307b2a..35854d3570 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/CsarUtils.java @@ -19,124 +19,65 @@ */ package org.openecomp.sdc.be.tosca; -import static org.openecomp.sdc.be.dao.api.ActionStatus.ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION; -import static org.openecomp.sdc.be.dao.api.ActionStatus.ERROR_DURING_CSAR_CREATION; -import static org.openecomp.sdc.be.tosca.ComponentCache.MergeStrategy.overwriteIfSameVersions; -import static org.openecomp.sdc.be.tosca.FJToVavrHelper.Try0.fromEither; - import fj.F; import fj.data.Either; -import io.vavr.Tuple2; -import io.vavr.control.Option; -import io.vavr.control.Try; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; -import java.util.Date; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.TimeZone; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.function.Supplier; -import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import lombok.Getter; import lombok.Setter; import org.apache.commons.codec.binary.Base64; -import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; import org.apache.commons.io.output.ByteArrayOutputStream; -import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import org.apache.commons.lang3.tuple.ImmutableTriple; -import org.apache.commons.lang3.tuple.Triple; -import org.apache.commons.text.WordUtils; -import org.onap.sdc.tosca.services.YamlUtil; import org.openecomp.sdc.be.components.impl.ImportUtils; -import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException; -import org.openecomp.sdc.be.config.*; +import org.openecomp.sdc.be.config.ArtifactConfigManager; +import org.openecomp.sdc.be.config.ArtifactConfiguration; +import org.openecomp.sdc.be.config.ComponentType; +import org.openecomp.sdc.be.config.ConfigurationManager; import org.openecomp.sdc.be.dao.api.ActionStatus; -import org.openecomp.sdc.be.dao.cassandra.ArtifactCassandraDao; -import org.openecomp.sdc.be.dao.cassandra.CassandraOperationStatus; -import org.openecomp.sdc.be.dao.cassandra.SdcSchemaFilesCassandraDao; -import org.openecomp.sdc.be.data.model.ToscaImportByModel; -import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; 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.model.InterfaceDefinition; -import org.openecomp.sdc.be.model.LifecycleStateEnum; -import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.Service; -import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; -import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; -import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; -import org.openecomp.sdc.be.model.operations.impl.ModelOperation; -import org.openecomp.sdc.be.plugins.CsarEntryGenerator; -import org.openecomp.sdc.be.resources.data.DAOArtifactData; -import org.openecomp.sdc.be.tosca.utils.OperationArtifactUtil; -import org.openecomp.sdc.be.utils.TypeUtils.ToscaTagNamesEnum; import org.openecomp.sdc.common.api.ArtifactGroupTypeEnum; import org.openecomp.sdc.common.api.ArtifactTypeEnum; -import org.openecomp.sdc.common.impl.ExternalConfiguration; import org.openecomp.sdc.common.log.elements.LoggerSupportability; -import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions; import org.openecomp.sdc.common.log.enums.StatusCode; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.common.util.GeneralUtility; import org.openecomp.sdc.common.util.ValidationUtils; -import org.openecomp.sdc.common.zip.ZipUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import org.yaml.snakeyaml.Yaml; @org.springframework.stereotype.Component("csar-utils") public class CsarUtils { - public static final String NODES_YML = "nodes.yml"; public static final String ARTIFACTS_PATH = "Artifacts/"; public static final String ARTIFACTS = "Artifacts"; public static final String ARTIFACT_CREATED_FROM_CSAR = "Artifact created from csar"; private static final Logger log = Logger.getLogger(CsarUtils.class); private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(CsarUtils.class.getName()); private static final String PATH_DELIMITER = "/"; - private static final String CONFORMANCE_LEVEL = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel(); - private static final String SDC_VERSION = ExternalConfiguration.getAppVersion(); - private static final String RESOURCES_PATH = "Resources/"; - private static final String DEFINITIONS_PATH = "Definitions/"; private static final String CSAR_META_VERSION = "1.0"; private static final String CSAR_META_PATH_FILE_NAME = "csar.meta"; - private static final String TOSCA_META_PATH_FILE_NAME = "TOSCA-Metadata/TOSCA.meta"; - private static final String TOSCA_META_VERSION = "1.0"; - private static final String CSAR_VERSION = "1.1"; - // add manifest - private static final String SERVICE_MANIFEST = "NS.mf"; private static final String DEFINITION = "Definitions"; private static final String DEL_PATTERN = "([/\\\\]+)"; private static final String WORD_PATTERN = "\\w\\_\\@\\-\\.\\s]+)"; @@ -152,7 +93,6 @@ public class CsarUtils { // Service Template File Name VALID_ENGLISH_ARTIFACT_NAME; private static final String VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS = "([\\d" + WORD_PATTERN; - private static final String ARTIFACT_NAME_UNIQUE_ID = "ArtifactName {}, unique ID {}"; private static final String VFC_NODE_TYPE_ARTIFACTS_PATH_PATTERN = ARTIFACTS + DEL_PATTERN + ImportUtils.Constants.USER_DEFINED_RESOURCE_NAMESPACE_PREFIX + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN + VALID_ENGLISH_ARTIFACT_NAME_WITH_DIGITS + DEL_PATTERN @@ -160,44 +100,16 @@ public class CsarUtils { private static final String BLOCK_0_TEMPLATE = "SDC-TOSCA-Meta-File-Version: %s\nSDC-TOSCA-Definitions-Version: %s\n"; private final ToscaOperationFacade toscaOperationFacade; - private final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao; - private final ArtifactCassandraDao artifactCassandraDao; private final ComponentsUtils componentsUtils; - private final ToscaExportHandler toscaExportUtils; - private final List<CsarEntryGenerator> generators; - private final ModelOperation modelOperation; - private final String versionFirstThreeOctets; + private final MapFromModelCsarGeneratorService mapFromModelCsarGeneratorService; @Autowired - public CsarUtils(final ToscaOperationFacade toscaOperationFacade, final SdcSchemaFilesCassandraDao sdcSchemaFilesCassandraDao, - final ArtifactCassandraDao artifactCassandraDao, final ComponentsUtils componentsUtils, - final ToscaExportHandler toscaExportUtils, final List<CsarEntryGenerator> generators, final ModelOperation modelOperation) { + public CsarUtils(final ToscaOperationFacade toscaOperationFacade, + final ComponentsUtils componentsUtils, + final MapFromModelCsarGeneratorService mapFromModelCsarGeneratorService) { this.toscaOperationFacade = toscaOperationFacade; - this.sdcSchemaFilesCassandraDao = sdcSchemaFilesCassandraDao; - this.artifactCassandraDao = artifactCassandraDao; this.componentsUtils = componentsUtils; - this.toscaExportUtils = toscaExportUtils; - this.generators = generators; - this.modelOperation = modelOperation; - this.versionFirstThreeOctets = readVersionFirstThreeOctets(); - } - - private String readVersionFirstThreeOctets() { - if (StringUtils.isEmpty(SDC_VERSION)) { - return ""; - } - // change regex to avoid DoS sonar issue - Matcher matcher = Pattern.compile("(?!\\.)(\\d{1,9}(\\.\\d{1,9}){1,9})(?![\\d\\.])").matcher(SDC_VERSION); - matcher.find(); - return matcher.group(0); - } - - private static <L, R> F<L, Either<L, R>> iff(Predicate<L> p, Function<L, Either<L, R>> ifTrue) { - return l -> p.test(l) ? ifTrue.apply(l) : Either.left(l); - } - - private static <A, B> F<A, B> iff(Predicate<A> p, Supplier<B> s, Function<A, B> orElse) { - return a -> p.test(a) ? s.get() : orElse.apply(a); + this.mapFromModelCsarGeneratorService = mapFromModelCsarGeneratorService; } /** @@ -367,15 +279,11 @@ public class CsarUtils { public Either<byte[], ResponseFormat> createCsar(final Component component, final boolean getFromCS, final boolean isInCertificationRequest) { loggerSupportability .log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.STARTED, "Starting to create Csar for component {} ", component.getName()); - final String createdBy = component.getCreatorFullName(); - final Map<String, ArtifactDefinition> toscaArtifacts = component.getToscaArtifacts(); - final ArtifactDefinition artifactDefinition = toscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); - final String fileName = artifactDefinition.getArtifactName(); final String toscaConformanceLevel = ConfigurationManager.getConfigurationManager().getConfiguration().getToscaConformanceLevel(); final byte[] csarBlock0Byte = createCsarBlock0(CSAR_META_VERSION, toscaConformanceLevel).getBytes(); - final byte[] toscaBlock0Byte = createToscaBlock0(TOSCA_META_VERSION, CSAR_VERSION, createdBy, fileName, isAsdPackage(component)).getBytes(); - return generateCsarZip(csarBlock0Byte, toscaBlock0Byte, component, getFromCS, isInCertificationRequest).left().map(responseFormat -> { + return generateCsarZip(csarBlock0Byte, + isAsdPackage(component), component, getFromCS, isInCertificationRequest).left().map(responseFormat -> { loggerSupportability .log(LoggerSupportabilityActions.GENERATE_CSAR, StatusCode.COMPLETE, "Ended create Csar for component {} ", component.getName()); return responseFormat; @@ -402,21 +310,22 @@ public class CsarUtils { return false; } - private Either<byte[], ResponseFormat> generateCsarZip(byte[] csarBlock0Byte, byte[] toscaBlock0Byte, Component component, boolean getFromCS, + private Either<byte[], ResponseFormat> generateCsarZip(byte[] csarBlock0Byte, + boolean isAsdPackage, + Component component, + boolean getFromCS, boolean isInCertificationRequest) { - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out)) { + try (final ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out)) { zip.putNextEntry(new ZipEntry(CSAR_META_PATH_FILE_NAME)); zip.write(csarBlock0Byte); - zip.putNextEntry(new ZipEntry(TOSCA_META_PATH_FILE_NAME)); - zip.write(toscaBlock0Byte); - Either<ZipOutputStream, ResponseFormat> populateZip = populateZip(component, getFromCS, zip, isInCertificationRequest); + Either<ZipOutputStream, ResponseFormat> populateZip = mapFromModelCsarGeneratorService.generateCsarZip( + component, getFromCS, zip, isInCertificationRequest, isAsdPackage); if (populateZip.isRight()) { log.debug("Failed to populate CSAR zip file {}. Please fix DB table accordingly ", populateZip.right().value()); return Either.right(populateZip.right().value()); } zip.finish(); - byte[] byteArray = out.toByteArray(); - return Either.left(byteArray); + return Either.left(out.toByteArray()); } catch (IOException e) { log.debug("Failed with IOexception to create CSAR zip for component {}. Please fix DB table accordingly ", component.getUniqueId(), e); ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); @@ -424,679 +333,10 @@ public class CsarUtils { } } - private Either<ZipOutputStream, ResponseFormat> populateZip(Component component, boolean getFromCS, ZipOutputStream zip, - boolean isInCertificationRequest) throws IOException { - ArtifactDefinition artifactDef = component.getToscaArtifacts().get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); - Either<ToscaRepresentation, ResponseFormat> toscaRepresentation = fetchToscaRepresentation(component, getFromCS, artifactDef); - - // This should not be done but in order to keep the refactoring small enough we stop here. - - // TODO: Refactor the rest of this function - byte[] mainYaml; - List<Triple<String, String, Component>> dependencies; - if (toscaRepresentation.isLeft()) { - mainYaml = toscaRepresentation.left().value().getMainYaml(); - dependencies = toscaRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>()); - } else { - return Either.right(toscaRepresentation.right().value()); - } - String fileName = artifactDef.getArtifactName(); - zip.putNextEntry(new ZipEntry(DEFINITIONS_PATH + fileName)); - zip.write(mainYaml); - LifecycleStateEnum lifecycleState = component.getLifecycleState(); - addServiceMf(component, zip, lifecycleState, isInCertificationRequest, fileName, mainYaml); - //US798487 - Abstraction of complex types - if (hasToWriteComponentSubstitutionType(component)) { - log.debug("Component {} is complex - generating abstract type for it..", component.getName()); - dependencies.addAll(writeComponentInterface(component, zip, fileName)); - } - //UID <cassandraId,filename,component> - Either<ZipOutputStream, ResponseFormat> zipOutputStreamOrResponseFormat = getZipOutputStreamResponseFormatEither(zip, dependencies); - if (zipOutputStreamOrResponseFormat != null && zipOutputStreamOrResponseFormat.isRight()) { - return zipOutputStreamOrResponseFormat; - } - if (component.getModel() == null) { - //retrieve SDC.zip from Cassandra - Either<byte[], ResponseFormat> latestSchemaFiles = getLatestSchemaFilesFromCassandra(); - if (latestSchemaFiles.isRight()) { - log.error("Error retrieving SDC Schema files from cassandra"); - return Either.right(latestSchemaFiles.right().value()); - } - final byte[] schemaFileZip = latestSchemaFiles.left().value(); - final List<String> nodesFromPackage = findNonRootNodesFromPackage(dependencies); - //add files from retrieved SDC.zip to Definitions folder in CSAR - addSchemaFilesFromCassandra(zip, schemaFileZip, nodesFromPackage); - } else { - //retrieve schema files by model from Cassandra - addSchemaFilesByModel(zip, component.getModel()); - } - Either<CsarDefinition, ResponseFormat> collectedComponentCsarDefinition = collectComponentCsarDefinition(component); - if (collectedComponentCsarDefinition.isRight()) { - return Either.right(collectedComponentCsarDefinition.right().value()); - } - if (generators != null) { - for (CsarEntryGenerator generator : generators) { - log.debug("Invoking CsarEntryGenerator: {}", generator.getClass().getName()); - for (Entry<String, byte[]> pluginGeneratedFile : generator.generateCsarEntries(component).entrySet()) { - zip.putNextEntry(new ZipEntry(pluginGeneratedFile.getKey())); - zip.write(pluginGeneratedFile.getValue()); - } - } - } - return writeAllFilesToCsar(component, collectedComponentCsarDefinition.left().value(), zip, isInCertificationRequest); - } - - private void addServiceMf(Component component, ZipOutputStream zip, LifecycleStateEnum lifecycleState, boolean isInCertificationRequest, - String fileName, byte[] mainYaml) throws IOException { - // add mf - if ((component.getComponentType() == ComponentTypeEnum.SERVICE) && (lifecycleState != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT)) { - String serviceName = component.getName(); - String createdBy = component.getCreatorUserId(); - String serviceVersion; - if (isInCertificationRequest) { - int tmp = Integer.valueOf(component.getVersion().split("\\.")[0]) + 1; - serviceVersion = String.valueOf(tmp) + ".0"; - } else { - serviceVersion = component.getVersion(); - } - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'"); - format.setTimeZone(TimeZone.getTimeZone("UTC")); - Date date = new Date(); - String releaseTime = format.format(date); - if (component.getCategories() == null || component.getCategories().get(0) == null) { - return; - } - String serviceType = component.getCategories().get(0).getName(); - String description = component.getDescription(); - String serviceTemplate = DEFINITIONS_PATH + fileName; - String hash = GeneralUtility.calculateMD5Base64EncodedByByteArray(mainYaml); - String nsMfBlock0 = createNsMfBlock0(serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate, - hash); - byte[] nsMfBlock0Byte = nsMfBlock0.getBytes(); - zip.putNextEntry(new ZipEntry(SERVICE_MANIFEST)); - zip.write(nsMfBlock0Byte); - } - } - - private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(Component component, boolean getFromCS, - ArtifactDefinition artifactDef) { - LifecycleStateEnum lifecycleState = component.getLifecycleState(); - boolean shouldBeFetchedFromCassandra = - getFromCS || !(lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKIN || lifecycleState == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT); - Either<ToscaRepresentation, ResponseFormat> toscaRepresentation = - shouldBeFetchedFromCassandra ? fetchToscaRepresentation(artifactDef) : generateToscaRepresentation(component); - return toscaRepresentation.left() - .bind(iff(myd -> !myd.getDependencies().isDefined(), myd -> fetchToscaTemplateDependencies(myd.getMainYaml(), component))); - } - - private Either<ToscaRepresentation, ResponseFormat> fetchToscaTemplateDependencies(byte[] mainYml, Component component) { - return toscaExportUtils.getDependencies(component).right().map(toscaError -> { - log.debug("Failed to retrieve dependencies for component {}, error {}", component.getUniqueId(), toscaError); - return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError)); - }).left().map(tt -> ToscaRepresentation.make(mainYml, tt)); - } - - private Either<ToscaRepresentation, ResponseFormat> generateToscaRepresentation(Component component) { - return toscaExportUtils.exportComponent(component).right().map(toscaError -> { - log.debug("exportComponent failed {}", toscaError); - return componentsUtils.getResponseFormat(componentsUtils.convertFromToscaError(toscaError)); - }); - } - - private Either<ToscaRepresentation, ResponseFormat> fetchToscaRepresentation(ArtifactDefinition artifactDef) { - return getFromCassandra(artifactDef.getEsId()).right().map(as -> { - log.debug(ARTIFACT_NAME_UNIQUE_ID, artifactDef.getArtifactName(), artifactDef.getUniqueId()); - return componentsUtils.getResponseFormat(as); - }).left().map(ToscaRepresentation::make); - } - - /** - * Create a list of all derived nodes found on the package - * - * @param dependencies all node dependencies - * @return a list of nodes - */ - private List<String> findNonRootNodesFromPackage(final List<Triple<String, String, Component>> dependencies) { - final List<String> nodes = new ArrayList<>(); - if (CollectionUtils.isNotEmpty(dependencies)) { - final String NATIVE_ROOT = "tosca.nodes.Root"; - dependencies.forEach(dependency -> { - if (dependency.getRight() instanceof Resource) { - final Resource resource = (Resource) dependency.getRight(); - if (CollectionUtils.isNotEmpty(resource.getDerivedList())) { - resource.getDerivedList().stream().filter(node -> !nodes.contains(node) && !NATIVE_ROOT.equalsIgnoreCase(node)) - .forEach(node -> nodes.add(node)); - } - } - }); - } - return nodes; - } - - /** - * Writes a new zip entry - * - * @param zipInputStream the zip entry to be read - * @return a map of the given zip entry - */ - private Map<String, Object> readYamlZipEntry(final ZipInputStream zipInputStream) throws IOException { - final int initSize = 2048; - final StringBuilder zipEntry = new StringBuilder(); - final byte[] buffer = new byte[initSize]; - int read = 0; - while ((read = zipInputStream.read(buffer, 0, initSize)) >= 0) { - zipEntry.append(new String(buffer, 0, read)); - } - return (Map<String, Object>) new Yaml().load(zipEntry.toString()); - } - - /** - * Filters and removes all duplicated nodes found - * - * @param nodesFromPackage a List of all derived nodes found on the given package - * @param nodesFromArtifactFile represents the nodes.yml file stored in Cassandra - * @return a nodes Map updated - */ - private Map<String, Object> updateNodeYml(final List<String> nodesFromPackage, final Map<String, Object> nodesFromArtifactFile) { - if (MapUtils.isNotEmpty(nodesFromArtifactFile)) { - final String nodeTypeBlock = ToscaTagNamesEnum.NODE_TYPES.getElementName(); - final Map<String, Object> nodeTypes = (Map<String, Object>) nodesFromArtifactFile.get(nodeTypeBlock); - nodesFromPackage.stream().filter(nodeTypes::containsKey).forEach(nodeTypes::remove); - nodesFromArtifactFile.replace(nodeTypeBlock, nodeTypes); - } - return nodesFromArtifactFile; - } - - /** - * Updates the zip entry from the given parameters - * - * @param byteArrayOutputStream an output stream in which the data is written into a byte array. - * @param nodesYaml a Map of nodes to be written - */ - private void updateZipEntry(final ByteArrayOutputStream byteArrayOutputStream, final Map<String, Object> nodesYaml) throws IOException { - if (MapUtils.isNotEmpty(nodesYaml)) { - byteArrayOutputStream.write(new YamlUtil().objectToYaml(nodesYaml).getBytes()); - } - } - - private Either<ZipOutputStream, ResponseFormat> getZipOutputStreamResponseFormatEither(ZipOutputStream zip, - List<Triple<String, String, Component>> dependencies) - throws IOException { - ComponentCache innerComponentsCache = ComponentCache.overwritable(overwriteIfSameVersions()).onMerge((oldValue, newValue) -> { - log.warn("Overwriting component invariantID {} of version {} with a newer version {}", oldValue.id, oldValue.getComponentVersion(), - newValue.getComponentVersion()); - }); - if (dependencies != null && !dependencies.isEmpty()) { - for (Triple<String, String, Component> d : dependencies) { - String cassandraId = d.getMiddle(); - Component childComponent = d.getRight(); - Either<byte[], ResponseFormat> entryData = getEntryData(cassandraId, childComponent).right() - .map(componentsUtils::getResponseFormat); - if (entryData.isRight()) { - return Either.right(entryData.right().value()); - } - //fill innerComponentsCache - String fileName = d.getLeft(); - innerComponentsCache.put(cassandraId, fileName, childComponent); - addInnerComponentsToCache(innerComponentsCache, childComponent); - } - //add inner components to CSAR - return addInnerComponentsToCSAR(zip, innerComponentsCache); - } - return null; - } - - private Either<ZipOutputStream, ResponseFormat> addInnerComponentsToCSAR(ZipOutputStream zip, ComponentCache innerComponentsCache) - throws IOException { - for (ImmutableTriple<String, String, Component> ict : innerComponentsCache.iterable()) { - Component innerComponent = ict.getRight(); - String icFileName = ict.getMiddle(); - // add component to zip - Either<Tuple2<byte[], ZipEntry>, ResponseFormat> zipEntry = toZipEntry(ict); - // TODO: this should not be done, we should instead compose this either further, - - // but in order to keep this refactoring small, we'll stop here. - if (zipEntry.isRight()) { - return Either.right(zipEntry.right().value()); - } - Tuple2<byte[], ZipEntry> value = zipEntry.left().value(); - zip.putNextEntry(value._2); - zip.write(value._1); - // add component interface to zip - if (hasToWriteComponentSubstitutionType(innerComponent)) { - writeComponentInterface(innerComponent, zip, icFileName); - } - } - return null; - } - - private boolean hasToWriteComponentSubstitutionType(final Component component) { - final Map<String, CategoryBaseTypeConfig> serviceNodeTypesConfig = - ConfigurationManager.getConfigurationManager().getConfiguration().getServiceBaseNodeTypes(); - List<CategoryDefinition> categories = component.getCategories(); - if (CollectionUtils.isNotEmpty(categories) && MapUtils.isNotEmpty(serviceNodeTypesConfig) && serviceNodeTypesConfig.get(categories.get(0).getName()) != null) { - boolean doNotExtendBaseType = serviceNodeTypesConfig.get(categories.get(0).getName()).isDoNotExtendBaseType(); - if (doNotExtendBaseType) { - return false; - } - } - if (component instanceof Service) { - return !ModelConverter.isAtomicComponent(component) && ((Service) component).isSubstituteCandidate(); - } - return !ModelConverter.isAtomicComponent(component); - } - - private Either<Tuple2<byte[], ZipEntry>, ResponseFormat> toZipEntry(ImmutableTriple<String, String, Component> cachedEntry) { - String cassandraId = cachedEntry.getLeft(); - String fileName = cachedEntry.getMiddle(); - Component innerComponent = cachedEntry.getRight(); - return getEntryData(cassandraId, innerComponent).right().map(status -> { - log.debug("Failed adding to zip component {}, error {}", cassandraId, status); - return componentsUtils.getResponseFormat(status); - }).left().map(content -> new Tuple2<>(content, new ZipEntry(DEFINITIONS_PATH + fileName))); - } - - /** - * Writes to a CSAR zip from casandra schema data - * - * @param zipOutputStream stores the input stream content - * @param schemaFileZip zip data from Cassandra - * @param nodesFromPackage list of all nodes found on the onboarded package - */ - private void addSchemaFilesFromCassandra(final ZipOutputStream zipOutputStream, final byte[] schemaFileZip, final List<String> nodesFromPackage) { - final int initSize = 2048; - log.debug("Starting copy from Schema file zip to CSAR zip"); - try (final ZipInputStream zipInputStream = new ZipInputStream(new ByteArrayInputStream( - schemaFileZip)); final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); final BufferedOutputStream bufferedOutputStream = new BufferedOutputStream( - byteArrayOutputStream, initSize)) { - ZipEntry entry; - while ((entry = zipInputStream.getNextEntry()) != null) { - ZipUtils.checkForZipSlipInRead(entry); - final String entryName = entry.getName(); - int readSize = initSize; - final byte[] entryData = new byte[initSize]; - if (shouldZipEntryBeHandled(entryName)) { - if (NODES_YML.equalsIgnoreCase(entryName)) { - handleNode(zipInputStream, byteArrayOutputStream, nodesFromPackage); - } else { - while ((readSize = zipInputStream.read(entryData, 0, readSize)) != -1) { - bufferedOutputStream.write(entryData, 0, readSize); - } - bufferedOutputStream.flush(); - } - byteArrayOutputStream.flush(); - zipOutputStream.putNextEntry(new ZipEntry(DEFINITIONS_PATH + entryName)); - zipOutputStream.write(byteArrayOutputStream.toByteArray()); - zipOutputStream.flush(); - byteArrayOutputStream.reset(); - } - } - } catch (final Exception e) { - log.error("Error while writing the SDC schema file to the CSAR", e); - throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); - } - log.debug("Finished copy from Schema file zip to CSAR zip"); - } - - /** - * Checks if the zip entry should or should not be added to the CSAR based on the given global type list - * - * @param entryName the zip entry name - * @return true if the zip entry should be handled - */ - private boolean shouldZipEntryBeHandled(final String entryName) { - return ConfigurationManager.getConfigurationManager().getConfiguration().getGlobalCsarImports().stream() - .anyMatch(entry -> entry.contains(entryName)); - } - - /** - * Handles the nodes.yml zip entry, updating the nodes.yml to avoid duplicated nodes on it. - * - * @param zipInputStream the zip entry to be read - * @param byteArrayOutputStream an output stream in which the data is written into a byte array. - * @param nodesFromPackage list of all nodes found on the onboarded package - */ - private void handleNode(final ZipInputStream zipInputStream, final ByteArrayOutputStream byteArrayOutputStream, - final List<String> nodesFromPackage) throws IOException { - final Map<String, Object> nodesFromArtifactFile = readYamlZipEntry(zipInputStream); - final Map<String, Object> nodesYaml = updateNodeYml(nodesFromPackage, nodesFromArtifactFile); - updateZipEntry(byteArrayOutputStream, nodesYaml); - } - - private void addInnerComponentsToCache(ComponentCache componentCache, Component childComponent) { - javaListToVavrList(childComponent.getComponentInstances()).filter(ci -> componentCache.notCached(ci.getComponentUid())).forEach(ci -> { - // all resource must be only once! - Either<Resource, StorageOperationStatus> resource = toscaOperationFacade.getToscaElement(ci.getComponentUid()); - Component componentRI = checkAndAddComponent(componentCache, ci, resource); - //if not atomic - insert inner components as well - - // TODO: This could potentially create a StackOverflowException if the call stack - - // happens to be too large. Tail-recursive optimization should be used here. - if (!ModelConverter.isAtomicComponent(componentRI)) { - addInnerComponentsToCache(componentCache, componentRI); - } - }); - } - - // TODO: Move this function in FJToVavrHelper.java once Change 108540 is merged - private io.vavr.collection.List<ComponentInstance> javaListToVavrList(List<ComponentInstance> componentInstances) { - return Option.of(componentInstances).map(io.vavr.collection.List::ofAll).getOrElse(io.vavr.collection.List::empty); - } - - private Component checkAndAddComponent(ComponentCache componentCache, ComponentInstance ci, Either<Resource, StorageOperationStatus> resource) { - if (resource.isRight()) { - log.debug("Failed to fetch resource with id {} for instance {}", ci.getComponentUid(), ci.getName()); - } - Component componentRI = resource.left().value(); - Map<String, ArtifactDefinition> childToscaArtifacts = componentRI.getToscaArtifacts(); - ArtifactDefinition childArtifactDefinition = childToscaArtifacts.get(ToscaExportHandler.ASSET_TOSCA_TEMPLATE); - if (childArtifactDefinition != null) { - //add to cache - componentCache.put(childArtifactDefinition.getEsId(), childArtifactDefinition.getArtifactName(), componentRI); - } - return componentRI; - } - - private List<Triple<String, String, Component>> writeComponentInterface(final Component component, final ZipOutputStream zip, - final String fileName) { - final Either<ToscaRepresentation, ToscaError> interfaceRepresentation = toscaExportUtils.exportComponentInterface(component, false); - writeComponentInterface(interfaceRepresentation, zip, fileName); - return interfaceRepresentation.left().value().getDependencies().getOrElse(new ArrayList<>()); - } - - - private Either<ZipOutputStream, ResponseFormat> writeComponentInterface(Either<ToscaRepresentation, ToscaError> interfaceRepresentation, - ZipOutputStream zip, String fileName) { - // TODO: This should not be done but we need this to keep the refactoring small enough to be easily reviewable - return writeComponentInterface(interfaceRepresentation, fileName, ZipWriter.live(zip)) - .map(void0 -> Either.<ZipOutputStream, ResponseFormat>left(zip)).recover(th -> { - log.error("#writeComponentInterface - zip writing failed with error: ", th); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR)); - }).get(); - } - - private Try<Void> writeComponentInterface( - Either<ToscaRepresentation, ToscaError> interfaceRepresentation, String fileName, ZipWriter zw) { - Either<byte[], ToscaError> yml = interfaceRepresentation.left() - .map(ToscaRepresentation::getMainYaml); - return fromEither(yml, ToscaErrorException::new).flatMap(zw.write(DEFINITIONS_PATH + ToscaExportHandler.getInterfaceFilename(fileName))); - } - - private Either<byte[], ActionStatus> getEntryData(String cassandraId, Component childComponent) { - if (cassandraId == null || cassandraId.isEmpty()) { - return toscaExportUtils.exportComponent(childComponent).right().map(toscaErrorToActionStatus(childComponent)).left() - .map(ToscaRepresentation::getMainYaml); - } else { - return getFromCassandra(cassandraId); - } - } - - private F<ToscaError, ActionStatus> toscaErrorToActionStatus(Component childComponent) { - return toscaError -> { - log.debug("Failed to export tosca template for child component {} error {}", childComponent.getUniqueId(), toscaError); - return componentsUtils.convertFromToscaError(toscaError); - }; - } - - private Either<byte[], ResponseFormat> getLatestSchemaFilesFromCassandra() { - String fto = versionFirstThreeOctets; - return sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(fto, CONFORMANCE_LEVEL).right().map(schemaFilesFetchDBError(fto)).left() - .bind(iff(List::isEmpty, () -> schemaFileFetchError(fto), s -> Either.left(s.iterator().next().getPayloadAsArray()))); - } - - private void addSchemaFilesByModel(final ZipOutputStream zipOutputStream, final String modelName) { - try { - final List<ToscaImportByModel> modelDefaultImportList = modelOperation.findAllModelImports(modelName, true); - final Set<Path> writtenEntryPathList = new HashSet<>(); - final var definitionsPath = Path.of(DEFINITIONS_PATH); - for (final ToscaImportByModel toscaImportByModel : modelDefaultImportList) { - var importPath = Path.of(toscaImportByModel.getFullPath()); - if (writtenEntryPathList.contains(definitionsPath.resolve(importPath))) { - importPath = - ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId()); - } - final Path entryPath = definitionsPath.resolve(importPath); - final var zipEntry = new ZipEntry(entryPath.toString()); - zipOutputStream.putNextEntry(zipEntry); - writtenEntryPathList.add(entryPath); - final byte[] content = toscaImportByModel.getContent().getBytes(StandardCharsets.UTF_8); - zipOutputStream.write(content, 0, content.length); - zipOutputStream.closeEntry(); - } - } catch (final IOException e) { - log.error(EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR, CsarUtils.class.getName(), - "Error while writing the schema files by model to the CSAR", e); - throw new ByResponseFormatComponentException(componentsUtils.getResponseFormat(ActionStatus.CSAR_TOSCA_IMPORTS_ERROR)); - } - } - - private F<CassandraOperationStatus, ResponseFormat> schemaFilesFetchDBError(String firstThreeOctets) { - return cos -> { - log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}. Please fix DB table accordingly.", firstThreeOctets, - CONFORMANCE_LEVEL); - StorageOperationStatus sos = DaoStatusConverter.convertCassandraStatusToStorageStatus(cos); - return componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(sos)); - }; - } - - private Either<byte[], ResponseFormat> schemaFileFetchError(String firstThreeOctets) { - log.debug("Failed to get the schema files SDC-Version: {} Conformance-Level {}", firstThreeOctets, CONFORMANCE_LEVEL); - return Either.right(componentsUtils.getResponseFormat(ActionStatus.TOSCA_SCHEMA_FILES_NOT_FOUND, firstThreeOctets, CONFORMANCE_LEVEL)); - } - - private Either<byte[], ActionStatus> getFromCassandra(String cassandraId) { - return artifactCassandraDao.getArtifact(cassandraId).right().map(operationstatus -> { - log.info("Failed to fetch artifact from Cassandra by id {} error {}.", cassandraId, operationstatus); - StorageOperationStatus storageStatus = DaoStatusConverter.convertCassandraStatusToStorageStatus(operationstatus); - return componentsUtils.convertFromStorageResponse(storageStatus); - }).left().map(DAOArtifactData::getDataAsArray); - } - private String createCsarBlock0(String metaFileVersion, String toscaConformanceLevel) { return String.format(BLOCK_0_TEMPLATE, metaFileVersion, toscaConformanceLevel); } - private String createToscaBlock0(String metaFileVersion, String csarVersion, String createdBy, String entryDef, boolean isAsdPackage) { - final String block0template = "TOSCA-Meta-File-Version: %s\nCSAR-Version: %s\nCreated-By: %s\nEntry-Definitions: Definitions/%s\n%s\nName: csar.meta\nContent-Type: text/plain\n"; - return String.format(block0template, metaFileVersion, csarVersion, createdBy, entryDef, isAsdPackage ? "entry_definition_type: asd" : ""); - } - - private String createNsMfBlock0(String serviceName, String createdBy, String serviceVersion, String releaseTime, String serviceType, - String description, String serviceTemplate, String hash) { - final String block0template = "metadata??\n" + "ns_product_name: %s\n" + "ns_provider_id: %s\n" + "ns_package_version: %s\n" + - "ns_release_data_time: %s\n" + "ns_type: %s\n" + "ns_package_description: %s\n\n" + "Source: %s\n" + "Algorithm: MD5\n" + "Hash: %s\n\n"; - return String.format(block0template, serviceName, createdBy, serviceVersion, releaseTime, serviceType, description, serviceTemplate, hash); - } - - private Either<ZipOutputStream, ResponseFormat> writeAllFilesToCsar(Component mainComponent, CsarDefinition csarDefinition, - ZipOutputStream zipstream, boolean isInCertificationRequest) - throws IOException { - ComponentArtifacts componentArtifacts = csarDefinition.getComponentArtifacts(); - Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath = writeComponentArtifactsToSpecifiedPath(mainComponent, - componentArtifacts, zipstream, ARTIFACTS_PATH, isInCertificationRequest); - if (writeComponentArtifactsToSpecifiedPath.isRight()) { - return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); - } - ComponentTypeArtifacts mainTypeAndCIArtifacts = componentArtifacts.getMainTypeAndCIArtifacts(); - writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, mainTypeAndCIArtifacts.getComponentArtifacts(), - zipstream, ARTIFACTS_PATH, isInCertificationRequest); - if (writeComponentArtifactsToSpecifiedPath.isRight()) { - return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); - } - Map<String, ArtifactsInfo> componentInstancesArtifacts = mainTypeAndCIArtifacts.getComponentInstancesArtifacts(); - String currentPath = ARTIFACTS_PATH + RESOURCES_PATH; - for (String keyAssetName : componentInstancesArtifacts.keySet()) { - ArtifactsInfo artifactsInfo = componentInstancesArtifacts.get(keyAssetName); - String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER; - writeComponentArtifactsToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, artifactsInfo, zipstream, pathWithAssetName, - isInCertificationRequest); - if (writeComponentArtifactsToSpecifiedPath.isRight()) { - return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); - } - } - writeComponentArtifactsToSpecifiedPath = writeOperationsArtifactsToCsar(mainComponent, zipstream); - if (writeComponentArtifactsToSpecifiedPath.isRight()) { - return Either.right(writeComponentArtifactsToSpecifiedPath.right().value()); - } - return Either.left(zipstream); - } - - private Either<ZipOutputStream, ResponseFormat> writeOperationsArtifactsToCsar(Component component, ZipOutputStream zipstream) { - if (checkComponentBeforeOperation(component)) { - return Either.left(zipstream); - } - for (Map.Entry<String, InterfaceDefinition> interfaceEntry : ((Resource) component).getInterfaces().entrySet()) { - for (OperationDataDefinition operation : interfaceEntry.getValue().getOperations().values()) { - try { - if (checkComponentBeforeWrite(component, interfaceEntry, operation)) { - continue; - } - final String artifactUUID = operation.getImplementation().getArtifactUUID(); - if (artifactUUID == null) { - continue; - } - final Either<byte[], ActionStatus> artifactFromCassandra = getFromCassandra(artifactUUID); - final String artifactName = operation.getImplementation().getArtifactName(); - if (artifactFromCassandra.isRight()) { - log.error(ARTIFACT_NAME_UNIQUE_ID, artifactName, artifactUUID); - log.error("Failed to get {} payload from DB reason: {}", artifactName, artifactFromCassandra.right().value()); - return Either.right(componentsUtils.getResponseFormat( - ARTIFACT_PAYLOAD_NOT_FOUND_DURING_CSAR_CREATION, "Resource", component.getUniqueId(), artifactName, artifactUUID)); - } - zipstream.putNextEntry(new ZipEntry(OperationArtifactUtil.createOperationArtifactPath(component, null, operation, true))); - zipstream.write(artifactFromCassandra.left().value()); - } catch (IOException e) { - log.error("Component Name {}, Interface Name {}, Operation Name {}", component.getNormalizedName(), interfaceEntry.getKey(), - operation.getName()); - log.error("Error while writing the operation's artifacts to the CSAR", e); - return Either.right(componentsUtils.getResponseFormat(ERROR_DURING_CSAR_CREATION, "Resource", component.getUniqueId())); - } - } - } - return Either.left(zipstream); - } - - private boolean checkComponentBeforeWrite(Component component, Entry<String, InterfaceDefinition> interfaceEntry, - OperationDataDefinition operation) { - final ArtifactDataDefinition implementation = operation.getImplementation(); - if (Objects.isNull(implementation)) { - log.debug("Component Name {}, Interface Id {}, Operation Name {} - no Operation Implementation found", component.getNormalizedName(), - interfaceEntry.getValue().getUniqueId(), operation.getName()); - return true; - } - final String artifactName = implementation.getArtifactName(); - if (Objects.isNull(artifactName)) { - log.debug("Component Name {}, Interface Id {}, Operation Name {} - no artifact found", component.getNormalizedName(), - interfaceEntry.getValue().getUniqueId(), operation.getName()); - return true; - } - if (OperationArtifactUtil.artifactNameIsALiteralValue(artifactName)) { - log.debug("Component Name {}, Interface Id {}, Operation Name {} - artifact name is a literal value rather than an SDC artifact", - component.getNormalizedName(), interfaceEntry.getValue().getUniqueId(), operation.getName()); - return true; - } - return false; - } - - private boolean checkComponentBeforeOperation(Component component) { - if (component instanceof Service) { - return true; - } - if (Objects.isNull(((Resource) component).getInterfaces())) { - log.debug("Component Name {}- no interfaces found", component.getNormalizedName()); - return true; - } - return false; - } - - private Either<ZipOutputStream, ResponseFormat> writeComponentArtifactsToSpecifiedPath(Component mainComponent, - ComponentArtifacts componentArtifacts, - ZipOutputStream zipstream, String currentPath, - boolean isInCertificationRequest) throws IOException { - Map<String, ComponentTypeArtifacts> componentTypeArtifacts = componentArtifacts.getComponentTypeArtifacts(); - //Keys are defined: - - //<Inner Asset TOSCA name (e.g. VFC name)> folder name: <Inner Asset TOSCA name (e.g. VFC name)>_v<version>. - - //E.g. "org.openecomp.resource.vf.vipr_atm_v1.0" - Set<String> componentTypeArtifactsKeys = componentTypeArtifacts.keySet(); - for (String keyAssetName : componentTypeArtifactsKeys) { - ComponentTypeArtifacts componentInstanceArtifacts = componentTypeArtifacts.get(keyAssetName); - ArtifactsInfo componentArtifacts2 = componentInstanceArtifacts.getComponentArtifacts(); - String pathWithAssetName = currentPath + keyAssetName + PATH_DELIMITER; - Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath = writeArtifactsInfoToSpecifiedPath(mainComponent, - componentArtifacts2, zipstream, pathWithAssetName, isInCertificationRequest); - if (writeArtifactsInfoToSpecifiedPath.isRight()) { - return writeArtifactsInfoToSpecifiedPath; - } - } - return Either.left(zipstream); - } - - private Either<ZipOutputStream, ResponseFormat> writeArtifactsInfoToSpecifiedPath(final Component mainComponent, - final ArtifactsInfo currArtifactsInfo, - final ZipOutputStream zip, final String path, - final boolean isInCertificationRequest) throws IOException { - final Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactsInfo = currArtifactsInfo.getArtifactsInfo(); - for (final ArtifactGroupTypeEnum artifactGroupTypeEnum : artifactsInfo.keySet()) { - final String groupTypeFolder = path + WordUtils.capitalizeFully(artifactGroupTypeEnum.getType()) + PATH_DELIMITER; - final Map<String, List<ArtifactDefinition>> artifactTypesMap = artifactsInfo.get(artifactGroupTypeEnum); - for (final String artifactType : artifactTypesMap.keySet()) { - final List<ArtifactDefinition> artifactDefinitionList = artifactTypesMap.get(artifactType); - String artifactTypeFolder = groupTypeFolder + artifactType + PATH_DELIMITER; - if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType) && path.contains(ARTIFACTS_PATH + RESOURCES_PATH)) { - // Ignore this packaging as BPMN artifacts needs to be packaged in different manner - continue; - } - if (ArtifactTypeEnum.WORKFLOW.getType().equals(artifactType)) { - artifactTypeFolder += OperationArtifactUtil.BPMN_ARTIFACT_PATH + File.separator; - } else if (ArtifactTypeEnum.ONBOARDED_PACKAGE.getType().equals(artifactType)) { - // renaming legacy folder ONBOARDED_PACKAGE to the new folder ETSI_PACKAGE - artifactTypeFolder = artifactTypeFolder - .replace(ArtifactTypeEnum.ONBOARDED_PACKAGE.getType(), ArtifactTypeEnum.ETSI_PACKAGE.getType()); - } - // TODO: We should not do this but in order to keep this refactoring small enough, - - // we'll leave this as is for now - List<ArtifactDefinition> collect = filterArtifactDefinitionToZip(mainComponent, artifactDefinitionList, isInCertificationRequest) - .collect(Collectors.toList()); - for (ArtifactDefinition ad : collect) { - zip.putNextEntry(new ZipEntry(artifactTypeFolder + ad.getArtifactName())); - zip.write(ad.getPayloadData()); - } - } - } - return Either.left(zip); - } - - private Stream<ArtifactDefinition> filterArtifactDefinitionToZip(Component mainComponent, List<ArtifactDefinition> artifactDefinitionList, - boolean isInCertificationRequest) { - return artifactDefinitionList.stream().filter(shouldBeInZip(isInCertificationRequest, mainComponent)).map(this::fetchPayLoadData) - .filter(Either::isLeft).map(e -> e.left().value()); - } - - private Predicate<ArtifactDefinition> shouldBeInZip(boolean isInCertificationRequest, Component component) { - return artifactDefinition -> !(!isInCertificationRequest && component.isService() && artifactDefinition.isHeatEnvType() || artifactDefinition - .hasNoMandatoryEsId()); - } - - private Either<ArtifactDefinition, ActionStatus> fetchPayLoadData(ArtifactDefinition ad) { - byte[] payloadData = ad.getPayloadData(); - if (payloadData == null) { - return getFromCassandra(ad.getEsId()).left().map(pd -> { - ad.setPayload(pd); - return ad; - }).right().map(as -> { - log.debug(ARTIFACT_NAME_UNIQUE_ID, ad.getArtifactName(), ad.getUniqueId()); - log.debug("Failed to get {} payload from DB reason: {}", ad.getArtifactName(), as); - return as; - }); - } else { - return Either.left(ad); - } - } - /************************************ Artifacts Structure END******************************************************************/ private Either<CsarDefinition, ResponseFormat> collectComponentCsarDefinition(Component component) { @@ -1149,7 +389,7 @@ public class CsarUtils { ComponentTypeArtifacts componentInstanceArtifacts = componentArtifacts.getMainTypeAndCIArtifacts(); printArtifacts(componentInstanceArtifacts); result.append("Type Artifacts\n"); - for (Map.Entry<String, ComponentTypeArtifacts> typeArtifacts : componentArtifacts.getComponentTypeArtifacts().entrySet()) { + for (Entry<String, ComponentTypeArtifacts> typeArtifacts : componentArtifacts.getComponentTypeArtifacts().entrySet()) { result.append("Folder " + typeArtifacts.getKey() + "\n"); result.append(printArtifacts(typeArtifacts.getValue())); } @@ -1167,7 +407,7 @@ public class CsarUtils { Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componentArtifacts = artifactsInfo.getArtifactsInfo(); printArtifacts(componentArtifacts); result = result.append("Resources\n"); - for (Map.Entry<String, ArtifactsInfo> resourceInstance : componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()) { + for (Entry<String, ArtifactsInfo> resourceInstance : componentInstanceArtifacts.getComponentInstancesArtifacts().entrySet()) { result.append("Folder" + resourceInstance.getKey() + "\n"); result.append(printArtifacts(resourceInstance.getValue().getArtifactsInfo())); } @@ -1177,9 +417,9 @@ public class CsarUtils { private String printArtifacts(Map<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> componetArtifacts) { StringBuilder result = new StringBuilder(); - for (Map.Entry<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactGroup : componetArtifacts.entrySet()) { + for (Entry<ArtifactGroupTypeEnum, Map<String, List<ArtifactDefinition>>> artifactGroup : componetArtifacts.entrySet()) { result.append(" " + artifactGroup.getKey().getType()); - for (Map.Entry<String, List<ArtifactDefinition>> groupArtifacts : artifactGroup.getValue().entrySet()) { + for (Entry<String, List<ArtifactDefinition>> groupArtifacts : artifactGroup.getValue().entrySet()) { result.append(" " + groupArtifacts.getKey()); for (ArtifactDefinition artifact : groupArtifacts.getValue()) { result.append(" " + artifact.getArtifactDisplayName()); @@ -1323,12 +563,6 @@ public class CsarUtils { return artifactsByType; } - public static class ToscaErrorException extends Exception { - - ToscaErrorException(ToscaError error) { - super("Error while exporting component's interface (toscaError:" + error + ")"); - } - } @Getter public static final class NonMetaArtifactInfo { @@ -1348,7 +582,6 @@ public class CsarUtils { public NonMetaArtifactInfo(final String artifactName, final String path, final String artifactType, final ArtifactGroupTypeEnum artifactGroupType, final byte[] payloadData, final String artifactUniqueId, final boolean isFromCsar) { - super(); this.path = path; this.isFromCsar = isFromCsar; this.artifactName = ValidationUtils.normalizeFileName(artifactName); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/DefaultCsarGenerator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/DefaultCsarGenerator.java new file mode 100644 index 0000000000..cad5acebe0 --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/DefaultCsarGenerator.java @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2023 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.tosca; + +import fj.data.Either; +import java.io.IOException; +import java.util.zip.ZipOutputStream; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.plugins.CsarZipGenerator; +import org.openecomp.sdc.exception.ResponseFormat; + +/** + * Generates a Network Service CSAR based on a SERVICE component and wraps it in a SDC CSAR entry. + */ +@org.springframework.stereotype.Component("defaultCsarGenerator") +public class DefaultCsarGenerator implements CsarZipGenerator { + + private static final String DEFINITIONS_PATH = "Definitions/"; + private final CommonCsarGenerator commonCsarGenerator; + + public DefaultCsarGenerator(final CommonCsarGenerator commonCsarGenerator) { + this.commonCsarGenerator = commonCsarGenerator; + } + + @Override + public Either<ZipOutputStream, ResponseFormat> generateCsarZip(Component component, + boolean getFromCS, + ZipOutputStream zip, + boolean isInCertificationRequest, + boolean isAsdPackage) throws IOException { + return commonCsarGenerator.generateCsarZip(component, getFromCS, zip, isInCertificationRequest, isAsdPackage, DEFINITIONS_PATH, true, false); + } + + @Override + public String getModel() { + return null; + } + +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/FJToVavrHelper.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/FJToVavrHelper.java index 94bc279cfe..0b07506ac5 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/FJToVavrHelper.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/FJToVavrHelper.java @@ -19,8 +19,11 @@ */ package org.openecomp.sdc.be.tosca; +import io.vavr.control.Option; import io.vavr.control.Try; +import java.util.List; import java.util.function.Function; +import org.openecomp.sdc.be.model.ComponentInstance; /** * Helper class providing facilities for migrating from FJ to VAVR @@ -42,5 +45,9 @@ public final class FJToVavrHelper { static <L, R> Try<L> fromEither(fj.data.Either<L, R> e, Function<R, Throwable> onError) { return e.either(Try::success, r -> Try.failure(onError.apply(r))); } + + static io.vavr.collection.List<ComponentInstance> javaListToVavrList(List<ComponentInstance> componentInstances) { + return Option.of(componentInstances).map(io.vavr.collection.List::ofAll).getOrElse(io.vavr.collection.List::empty); + } } } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/MapFromModelCsarGeneratorService.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/MapFromModelCsarGeneratorService.java new file mode 100644 index 0000000000..8e255c707c --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/MapFromModelCsarGeneratorService.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * SDC + * ================================================================================ + * Copyright (C) 2023 Nordix Foundation. All rights reserved. + * ================================================================================ + * 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. + * ============LICENSE_END========================================================= + */ +package org.openecomp.sdc.be.tosca; + +import fj.data.Either; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.zip.ZipOutputStream; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.plugins.CsarZipGenerator; +import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class MapFromModelCsarGeneratorService { + + private final Map<String, CsarZipGenerator> servicesByModel; + + @Autowired + public MapFromModelCsarGeneratorService(List<CsarZipGenerator> modelServices) { + servicesByModel = modelServices.stream() + .collect(Collectors.toMap(CsarZipGenerator::getModel, Function.identity())); + } + + public Either<ZipOutputStream, ResponseFormat> generateCsarZip(final Component component, + boolean getFromCS, + ZipOutputStream zip, + boolean isInCertificationRequest, + boolean isAsdPackage) throws IOException { + CsarZipGenerator generatorImpl = servicesByModel.get(component.getModel()); + + if (null == generatorImpl) { + generatorImpl = servicesByModel.get(null); + } + + return generatorImpl.generateCsarZip(component, getFromCS, zip, isInCertificationRequest, isAsdPackage); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java index 4d99b4de98..0b57cfe412 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/tosca/ToscaExportHandler.java @@ -22,6 +22,7 @@ package org.openecomp.sdc.be.tosca; import static org.apache.commons.collections.CollectionUtils.isNotEmpty; import static org.apache.commons.collections.MapUtils.isNotEmpty; import static org.openecomp.sdc.be.components.utils.PropertiesUtils.resolvePropertyValueFromInput; +import static org.openecomp.sdc.common.api.Constants.ADDITIONAL_TYPE_DEFINITIONS; import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_ATTRIBUTE; import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_INPUT; import static org.openecomp.sdc.tosca.datatypes.ToscaFunctions.GET_PROPERTY; @@ -228,7 +229,11 @@ public class ToscaExportHandler { } public Either<ToscaRepresentation, ToscaError> exportComponent(Component component) { - return convertToToscaTemplate(component).left().map(this::createToscaRepresentation); + return convertToToscaTemplate(component, false).left().map(this::createToscaRepresentation); + } + + public Either<ToscaRepresentation, ToscaError> exportComponent(Component component, Boolean isSkipImports) { + return convertToToscaTemplate(component, isSkipImports).left().map(this::createToscaRepresentation); } public Either<ToscaRepresentation, ToscaError> exportDataType(DataTypeDefinition dataTypeDefinition) { @@ -236,7 +241,7 @@ public class ToscaExportHandler { } public Either<ToscaRepresentation, ToscaError> exportComponentInterface(final Component component, final boolean isAssociatedComponent) { - final List<Map<String, Map<String, String>>> imports = new ArrayList<>(getDefaultToscaImports(component.getModel())); + final List<Map<String, Map<String, String>>> imports = new ArrayList<>(getDefaultToscaImports(component.getModel(), false)); if (CollectionUtils.isEmpty(imports)) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); @@ -248,7 +253,7 @@ public class ToscaExportHandler { .getByToscaResourceNameAndVersion(component.getDerivedFromGenericType(), component.getDerivedFromGenericVersion(), component.getModel()); if (baseType.isLeft() && baseType.left().value() != null) { - addDependencies(imports, dependencies, baseType.left().value()); + addDependencies(imports, dependencies, baseType.left().value(), false); } else { log.debug("Failed to fetch derived from type {}", component.getDerivedFromGenericType()); } @@ -272,6 +277,44 @@ public class ToscaExportHandler { return Either.left(toscaRepresentation); } + public Either<ToscaRepresentation, ToscaError> exportComponentInterface(final Component component, final boolean isAssociatedComponent, + final boolean isSkipImports) { + final List<Map<String, Map<String, String>>> imports = new ArrayList<>(getDefaultToscaImports(component.getModel(), isSkipImports)); + if (CollectionUtils.isEmpty(imports)) { + log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); + return Either.right(ToscaError.GENERAL_ERROR); + } + List<Triple<String, String, Component>> dependencies = new ArrayList<>(); + if (component.getDerivedFromGenericType() != null && !component.getDerivedFromGenericType() + .startsWith("org.openecomp.resource.abstract.nodes.")) { + final Either<Component, StorageOperationStatus> baseType = toscaOperationFacade + .getByToscaResourceNameAndVersion(component.getDerivedFromGenericType(), component.getDerivedFromGenericVersion(), + component.getModel()); + if (baseType.isLeft() && baseType.left().value() != null) { + addDependencies(imports, dependencies, baseType.left().value(), isSkipImports); + } else { + log.debug("Failed to fetch derived from type {}", component.getDerivedFromGenericType()); + } + } + + String toscaVersion = null; + if (component instanceof Resource) { + toscaVersion = ((Resource) component).getToscaVersion(); + } + ToscaTemplate toscaTemplate = new ToscaTemplate(toscaVersion != null ? toscaVersion : TOSCA_VERSION); + toscaTemplate.setImports(imports); + final Map<String, ToscaNodeType> nodeTypes = new HashMap<>(); + final Either<ToscaTemplate, ToscaError> toscaTemplateRes = convertInterfaceNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes, + isAssociatedComponent); + if (toscaTemplateRes.isRight()) { + return Either.right(toscaTemplateRes.right().value()); + } + toscaTemplate = toscaTemplateRes.left().value(); + toscaTemplate.setDependencies(dependencies); + ToscaRepresentation toscaRepresentation = this.createToscaRepresentation(toscaTemplate); + return Either.left(toscaRepresentation); + } + private ToscaRepresentation createToscaRepresentation(ToscaTemplate toscaTemplate) { CustomRepresenter representer = new CustomRepresenter(); DumperOptions options = new DumperOptions(); @@ -292,15 +335,24 @@ public class ToscaExportHandler { public Either<ToscaTemplate, ToscaError> getDependencies(Component component) { ToscaTemplate toscaTemplate = new ToscaTemplate(null); - Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports = fillImports(component, toscaTemplate); + Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports = fillImports(component, toscaTemplate, false); + if (fillImports.isRight()) { + return Either.right(fillImports.right().value()); + } + return Either.left(fillImports.left().value().left); + } + + public Either<ToscaTemplate, ToscaError> getDependencies(Component component, boolean isSkipImports) { + ToscaTemplate toscaTemplate = new ToscaTemplate(null); + Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports = fillImports(component, toscaTemplate, isSkipImports); if (fillImports.isRight()) { return Either.right(fillImports.right().value()); } return Either.left(fillImports.left().value().left); } - public Either<ToscaTemplate, ToscaError> convertToToscaTemplate(final Component component) { - final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel()); + public Either<ToscaTemplate, ToscaError> convertToToscaTemplate(final Component component, final boolean isSkipImports) { + final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel(), isSkipImports); if (CollectionUtils.isEmpty(defaultToscaImportConfig)) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); @@ -319,7 +371,7 @@ public class ToscaExportHandler { return convertNodeType(new HashMap<>(), component, toscaTemplate, nodeTypes); } else { log.trace("convert component as topology template"); - return convertToscaTemplate(component, toscaTemplate); + return convertToscaTemplate(component, toscaTemplate, isSkipImports); } } @@ -357,7 +409,7 @@ public class ToscaExportHandler { return Either.left(toscaTemplate); } - private List<Map<String, Map<String, String>>> getDefaultToscaImports(final String modelId) { + private List<Map<String, Map<String, String>>> getDefaultToscaImports(final String modelId, final boolean isSkipImports) { if (StringUtils.isEmpty(modelId)) { return getDefaultToscaImportConfig(); } @@ -367,18 +419,21 @@ public class ToscaExportHandler { final Set<Path> addedPathList = new HashSet<>(); for (final ToscaImportByModel toscaImportByModel : allModelImports) { var importPath = Path.of(toscaImportByModel.getFullPath()); - if (addedPathList.contains(importPath)) { - importPath = ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId()); + if (!(isSkipImports && importPath.toString().equals(ADDITIONAL_TYPE_DEFINITIONS))) { + if (addedPathList.contains(importPath)) { + importPath = + ToscaDefaultImportHelper.addModelAsFilePrefix(importPath, toscaImportByModel.getModelId()); + } + final String fileName = FilenameUtils.getBaseName(importPath.toString()); + importList.add(Map.of(fileName, Map.of("file", importPath.toString()))); + addedPathList.add(importPath); } - final String fileName = FilenameUtils.getBaseName(importPath.toString()); - importList.add(Map.of(fileName, Map.of("file", importPath.toString()))); - addedPathList.add(importPath); } return importList; } - private Either<ToscaTemplate, ToscaError> convertToscaTemplate(Component component, ToscaTemplate toscaNode) { - Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> importsRes = fillImports(component, toscaNode); + private Either<ToscaTemplate, ToscaError> convertToscaTemplate(Component component, ToscaTemplate toscaNode, boolean isSkipImports) { + Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> importsRes = fillImports(component, toscaNode, isSkipImports); if (importsRes.isRight()) { return Either.right(importsRes.right().value()); } @@ -641,8 +696,8 @@ public class ToscaExportHandler { return jsonPresentationField.getPresentation(); } - private Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports(Component component, ToscaTemplate toscaTemplate) { - final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel()); + private Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> fillImports(Component component, ToscaTemplate toscaTemplate, boolean isSkipImports) { + final List<Map<String, Map<String, String>>> defaultToscaImportConfig = getDefaultToscaImports(component.getModel(), isSkipImports); if (CollectionUtils.isEmpty(defaultToscaImportConfig)) { log.debug(FAILED_TO_GET_DEFAULT_IMPORTS_CONFIGURATION); return Either.right(ToscaError.GENERAL_ERROR); @@ -659,7 +714,7 @@ public class ToscaExportHandler { } List<ComponentInstance> componentInstances = component.getComponentInstances(); if (componentInstances != null && !componentInstances.isEmpty()) { - componentInstances.forEach(ci -> createDependency(componentCache, additionalImports, dependencies, ci)); + componentInstances.forEach(ci -> createDependency(componentCache, additionalImports, dependencies, ci, isSkipImports)); } toscaTemplate.setDependencies(dependencies); toscaTemplate.setImports(additionalImports); @@ -695,7 +750,8 @@ public class ToscaExportHandler { } private void createDependency(final Map<String, Component> componentCache, final List<Map<String, Map<String, String>>> imports, - final List<Triple<String, String, Component>> dependencies, final ComponentInstance componentInstance) { + final List<Triple<String, String, Component>> dependencies, final ComponentInstance componentInstance, + final boolean isSkipImports) { log.debug("createDependency componentCache {}", componentCache); Component componentRI = componentCache.get(componentInstance.getComponentUid()); if (componentRI == null || componentInstance.getOriginType() == OriginTypeEnum.ServiceSubstitution) { @@ -708,7 +764,7 @@ public class ToscaExportHandler { } final Component fetchedComponent = resource.left().value(); componentRI = setComponentCache(componentCache, componentInstance, fetchedComponent); - addDependencies(imports, dependencies, componentRI); + addDependencies(imports, dependencies, componentRI, isSkipImports); } } @@ -737,9 +793,9 @@ public class ToscaExportHandler { * Retrieves all derived_from nodes and stores it in a predictable order. */ private void addDependencies(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies, - final Component fetchedComponent) { + final Component fetchedComponent, final boolean isSkipImports) { final Set<Component> componentsList = new LinkedHashSet<>(); - if (fetchedComponent instanceof Resource) { + if (fetchedComponent instanceof Resource && !isSkipImports) { log.debug("fetchedComponent is a resource {}", fetchedComponent); final Optional<Map<String, String>> derivedFromMapOfIdToName = getDerivedFromMapOfIdToName(fetchedComponent, componentsList); if (derivedFromMapOfIdToName.isPresent() && !derivedFromMapOfIdToName.get().isEmpty()) { @@ -789,7 +845,7 @@ public class ToscaExportHandler { */ private void setImports(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies, final Set<Component> componentsList) { - componentsList.forEach(component -> setImports(imports, dependencies, component)); + componentsList.forEach(component -> setImports(imports, dependencies, component)); } private void setImports(final List<Map<String, Map<String, String>>> imports, final List<Triple<String, String, Component>> dependencies, @@ -1679,8 +1735,7 @@ public class ToscaExportHandler { nodeFilter.setProperties(propertiesCopy); } nodeFilter.setTosca_id(cloneToscaId(inNodeFilter.getTosca_id())); - nodeFilter = (NodeFilter) cloneObjectFromYml(nodeFilter, NodeFilter.class); - return nodeFilter; + return cloneObjectFromYml(nodeFilter, NodeFilter.class); } private NodeFilter convertToSubstitutionFilterComponent(final SubstitutionFilterDataDefinition substitutionFilterDataDefinition) { @@ -1693,14 +1748,14 @@ public class ToscaExportHandler { nodeFilter.setProperties(propertiesCopy); } nodeFilter.setTosca_id(cloneToscaId(substitutionFilterDataDefinition.getTosca_id())); - return (NodeFilter) cloneObjectFromYml(nodeFilter, NodeFilter.class); + return cloneObjectFromYml(nodeFilter, NodeFilter.class); } private Object cloneToscaId(Object toscaId) { return Objects.isNull(toscaId) ? null : cloneObjectFromYml(toscaId, toscaId.getClass()); } - private Object cloneObjectFromYml(Object objToClone, Class classOfObj) { + private <T> T cloneObjectFromYml(Object objToClone, Class<T> classOfObj) { String objectAsYml = yamlUtil.objectToYaml(objToClone); return yamlUtil.yamlToObject(objectAsYml, classOfObj); } @@ -1884,7 +1939,6 @@ public class ToscaExportHandler { private static class CustomRepresenter extends Representer { CustomRepresenter() { - super(); this.representers.put(ToscaPropertyAssignment.class, new RepresentToscaPropertyAssignment()); this.representers.put(ToscaAttribute.class, new RepresentToscaAttribute()); // null representer is exceptional and it is stored as an instance diff --git a/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java b/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java index 5c018fc0f0..17f7a0434d 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/config/CatalogBESpringConfig.java @@ -34,6 +34,8 @@ import org.openecomp.sdc.be.ecomp.converters.AssetMetadataConverter; import org.openecomp.sdc.be.filters.FilterConfiguration; import org.openecomp.sdc.be.filters.PortalConfiguration; import org.openecomp.sdc.be.filters.ThreadLocalUtils; +import org.openecomp.sdc.be.tosca.CommonCsarGenerator; +import org.openecomp.sdc.be.tosca.DefaultCsarGenerator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @@ -132,6 +134,11 @@ public class CatalogBESpringConfig { return new PortalClient(httpClientConnectionManager(), portalConfiguration()); } + @Bean(name = "defaultCsarGenerator") + public DefaultCsarGenerator defaultCsarGenerator(CommonCsarGenerator commonCsarGenerator) { + return new DefaultCsarGenerator(commonCsarGenerator); + } + @Bean public org.openecomp.sdc.be.config.Configuration configuration() { return ConfigurationManager.getConfigurationManager().getConfiguration(); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CsarUtilsTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CsarUtilsTest.java index 373e9b1c89..b749ef68fd 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CsarUtilsTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/CsarUtilsTest.java @@ -100,7 +100,10 @@ import org.openecomp.sdc.exception.ResponseFormat; class CsarUtilsTest extends BaseConfDependent { @InjectMocks - CsarUtils testSubject; + private CsarUtils testSubject; + + @InjectMocks + private CommonCsarGenerator commonCsarGenerator; @Mock private ArtifactCassandraDao artifactCassandraDao; @@ -124,7 +127,7 @@ class CsarUtilsTest extends BaseConfDependent { private final byte[] contentData; - public CsarUtilsTest() throws IOException { + public CsarUtilsTest() throws IOException { contentData = getFileResource("yamlValidation/resource-serviceTemplate.yml"); } @@ -158,7 +161,7 @@ class CsarUtilsTest extends BaseConfDependent { } @Test - void testCreateCsar() { + void testCreateCsar() throws IOException { Component component = new Resource(); Map<String, ArtifactDefinition> artifactDefinitionHashMap = new HashMap<>(); ArtifactDefinition artifact = new ArtifactDefinition(); @@ -170,17 +173,22 @@ class CsarUtilsTest extends BaseConfDependent { component.setArtifacts(artifactDefinitionHashMap); component.setDeploymentArtifacts(artifactDefinitionHashMap); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(out); + Mockito.when(artifactCassandraDao.getArtifact(Mockito.any(String.class))) .thenReturn(Either.right(CassandraOperationStatus.GENERAL_ERROR)); Mockito.when(componentsUtils.convertFromStorageResponse(Mockito.any(StorageOperationStatus.class))) .thenReturn(ActionStatus.GENERAL_ERROR); - testSubject.createCsar(component, true, true); + assertNotNull(commonCsarGenerator.generateCsarZip(component, false, zip, + false, true, + "Definitions/", true, false).right()); } @Test - void testCreateCsarWithGenerateCsarZipResponseIsLeft() { + void testCreateCsarWithGenerateCsarZipResponseIsLeft() throws IOException { Component component = new Resource(); Map<String, ArtifactDefinition> toscaArtifacts = new HashMap<>(); ArtifactDefinition artifact = new ArtifactDefinition(); @@ -207,6 +215,9 @@ class CsarUtilsTest extends BaseConfDependent { filedata.setPayloadAsArray(data); filesData.add(filedata); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(out); + Mockito.when(artifactCassandraDao.getArtifact(Mockito.any(String.class))).thenReturn(Either.left(artifactData)); Mockito.when(componentsUtils.convertFromStorageResponse(Mockito.any(StorageOperationStatus.class))) @@ -219,7 +230,9 @@ class CsarUtilsTest extends BaseConfDependent { sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(Mockito.any(String.class), Mockito.any(String.class))) .thenReturn(Either.left(filesData)); - testSubject.createCsar(component, false, true); + assertNotNull(commonCsarGenerator.generateCsarZip(component, false, zip, + false, true, + "Definitions/", true, false).right()); } @Test @@ -253,11 +266,11 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(toscaExportUtils.getDependencies(Mockito.any(Component.class))) .thenReturn(Either.right(ToscaError.GENERAL_ERROR)); - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, false); - } catch (Exception e) { - e.printStackTrace(); - } + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, true, "Definitions/", true, false); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -285,11 +298,11 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(toscaExportUtils.exportComponent(Mockito.any(Component.class))) .thenReturn(Either.right(ToscaError.GENERAL_ERROR)); - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, false); - } catch (Exception e) { - e.printStackTrace(); - } + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, true, "Definitions/", true, false); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -357,7 +370,7 @@ class CsarUtilsTest extends BaseConfDependent { .thenReturn(Either.left(Mockito.any(ArtifactDefinition.class))); try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, true); + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, true, "/Definitions", true, false); } catch (Exception e) { e.printStackTrace(); } @@ -405,11 +418,11 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(toscaExportUtils.getDependencies(Mockito.any(Component.class))) .thenReturn(Either.left(toscaTemplate)); - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, true); - } catch (Exception e) { - e.printStackTrace(); - } + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, true, "Definitions/", true, false); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -455,11 +468,11 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(toscaExportUtils.getDependencies(Mockito.any(Component.class))) .thenReturn(Either.left(toscaTemplate)); - try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, true); - } catch (Exception e) { - e.printStackTrace(); - } + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, true, "Definitions/", true, false); + } catch (Exception e) { + e.printStackTrace(); + } } @Test @@ -509,7 +522,7 @@ class CsarUtilsTest extends BaseConfDependent { .thenReturn(Either.right(CassandraOperationStatus.GENERAL_ERROR)); try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out);) { - Deencapsulation.invoke(testSubject, "populateZip", component, getFromCS, zip, true); + Deencapsulation.invoke(commonCsarGenerator, "generateCsarZip", component, getFromCS, zip, true, "toscaMetaFileName", true, "Definitions/", true, false); } catch (Exception e) { e.printStackTrace(); } @@ -542,7 +555,7 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(toscaOperationFacade.getToscaElement(Mockito.any(String.class))) .thenReturn(Either.left(componentRI)); - Deencapsulation.invoke(testSubject, "addInnerComponentsToCache", componentCache, childComponent); + Deencapsulation.invoke(commonCsarGenerator, "addInnerComponentsToCache", componentCache, childComponent); io.vavr.collection.List<CacheEntry> expected = io.vavr.collection.List.of(entry("esId","artifactName",componentRI)); assertEquals(expected, componentCache.all().toList()); @@ -591,7 +604,8 @@ class CsarUtilsTest extends BaseConfDependent { try (ByteArrayOutputStream out = new ByteArrayOutputStream(); ZipOutputStream zip = new ZipOutputStream(out)) { - List<Triple<String, String, Component>> output = Deencapsulation.invoke(testSubject, "writeComponentInterface", new Resource(), zip, fileName); + List<Triple<String, String, Component>> output = Deencapsulation.invoke(commonCsarGenerator, "writeComponentInterface", new Resource(), + zip, fileName, "Definitions/"); assertNotNull(output); } } @@ -604,7 +618,7 @@ class CsarUtilsTest extends BaseConfDependent { Mockito.when(artifactCassandraDao.getArtifact(Mockito.any(String.class))) .thenReturn(Either.right(CassandraOperationStatus.GENERAL_ERROR)); - Either<byte[], ActionStatus> output = Deencapsulation.invoke(testSubject, "getEntryData", cassandraId, childComponent); + Either<byte[], ActionStatus> output = Deencapsulation.invoke(commonCsarGenerator, "getEntryData", cassandraId, childComponent); assertNotNull(output); assertTrue(output.isRight()); @@ -618,7 +632,7 @@ class CsarUtilsTest extends BaseConfDependent { sdcSchemaFilesCassandraDao.getSpecificSchemaFiles(Mockito.any(String.class), Mockito.any(String.class))) .thenReturn(Either.left(filesData)); - Either<byte[], ResponseFormat> output = Deencapsulation.invoke(testSubject, "getLatestSchemaFilesFromCassandra"); + Either<byte[], ResponseFormat> output = Deencapsulation.invoke(commonCsarGenerator, "getLatestSchemaFilesFromCassandra"); assertNotNull(output); assertTrue(output.isRight()); @@ -704,88 +718,6 @@ class CsarUtilsTest extends BaseConfDependent { } @Test - void testNonMetaArtifactInfoCtor() { - createNonMetaArtifactInfoTestSubject(); - } - - @Test - void testNonMetaArtifactInfoGetPath() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getPath(); - } - - @Test - void testNonMetaArtifactInfoGetArtifactName() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getArtifactName(); - } - - @Test - void testNonMetaArtifactInfoGetArtifactType() { - final NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - assertThat("The artifact type should be as expected", - testSubject.getArtifactType(), is(ArtifactTypeEnum.AAI_SERVICE_MODEL.getType())); - } - - @Test - void testNonMetaArtifactInfoGetDisplayName() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getDisplayName(); - } - - @Test - void testNonMetaArtifactInfoGetArtifactGroupType() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getArtifactGroupType(); - } - - @Test - void testNonMetaArtifactInfoGetArtifactLabel() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getArtifactLabel(); - } - - @Test - void testNonMetaArtifactInfoGetIsFromCsar() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.isFromCsar(); - } - - @Test - void testNonMetaArtifactInfoGetPayloadData() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getPayloadData(); - } - - @Test - void testNonMetaArtifactInfoGetArtifaactChecksum() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getArtifactChecksum(); - } - - @Test - void testNonMetaArtifactInfoGetArtifactUniqueId() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.getArtifactUniqueId(); - } - - @Test - void testNonMetaArtifactInfosetArtifactUniqueId() { - NonMetaArtifactInfo testSubject = createNonMetaArtifactInfoTestSubject(); - - testSubject.setArtifactUniqueId("artifactUniqueId"); - } - - @Test void testValidateNonMetaArtifactWithExceptionCaught() { CsarUtils.validateNonMetaArtifact("", new byte[0], new HashMap<>()); } @@ -950,7 +882,7 @@ class CsarUtilsTest extends BaseConfDependent { final Path path = Paths.get(rootPath + "/src/test/resources/sdc.zip"); final byte[] data = Files.readAllBytes(path); try (final ByteArrayOutputStream out = new ByteArrayOutputStream(); final ZipOutputStream zip = new ZipOutputStream(out)) { - Deencapsulation.invoke(testSubject, "addSchemaFilesFromCassandra", zip, data, nodesFromPackage); + Deencapsulation.invoke(commonCsarGenerator, "addSchemaFilesFromCassandra", zip, data, nodesFromPackage, "Definitions/"); final IOException actualException = assertThrows(IOException.class, () -> zip.putNextEntry(new ZipEntry("Definitions/nodes.yml"))); assertEquals("duplicate entry: Definitions/nodes.yml", actualException.getMessage()); } @@ -965,7 +897,7 @@ class CsarUtilsTest extends BaseConfDependent { final Triple<String, String, Component> triple = Triple.of("fileName", "cassandraId", component); dependencies.add(triple); final List<String> expectedResult = Arrays.asList("tosca.nodes.Container.Application"); - final List<String> result = Deencapsulation.invoke(testSubject, + final List<String> result = Deencapsulation.invoke(commonCsarGenerator, "findNonRootNodesFromPackage", dependencies); assertTrue(CollectionUtils.isNotEmpty(result)); assertEquals(expectedResult, result); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java index 4f267138d7..0b3796261a 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/tosca/ToscaExportHandlerTest.java @@ -386,7 +386,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { when(toscaOperationFacade.getToscaFullElement("name")).thenReturn(Either.left(resource)); Either<ImmutablePair<ToscaTemplate, Map<String, Component>>, ToscaError> result; - result = Deencapsulation.invoke(testSubject, "fillImports", resource, toscaTemplate); + result = Deencapsulation.invoke(testSubject, "fillImports", resource, toscaTemplate, false); verify(toscaOperationFacade, times(1)).getToscaFullElement("name"); assertTrue(result.isLeft()); @@ -421,7 +421,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { doReturn(map).when(outputConverter).convert(any(), any()); // default test - result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode); + result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode, false); assertNotNull(result); } @@ -471,7 +471,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { doReturn(map).when(outputConverter).convert(any(), any()); // test component contains group - final var result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode); + final var result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode, false); assertNotNull(result); } @@ -510,7 +510,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { doReturn(map).when(outputConverter).convert(any(), any()); // test component contains group - result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode); + result = Deencapsulation.invoke(testSubject, "convertToscaTemplate", component, toscaNode, false); assertNotNull(result); } @@ -561,7 +561,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { when(toscaOperationFacade.getByToscaResourceNameAndVersion("org.typeA", "1.0", null)).thenReturn(Either.left(baseType)); // default test - result = Deencapsulation.invoke(testSubject, "fillImports", component, toscaTemplate); + result = Deencapsulation.invoke(testSubject, "fillImports", component, toscaTemplate, false); assertNotNull(result); } @@ -588,7 +588,7 @@ class ToscaExportHandlerTest extends BaseConfDependent { when(toscaOperationFacade.getToscaFullElement("modelName")).thenReturn(Either.left(new Service())); // default test - Deencapsulation.invoke(testSubject, "createDependency", componentCache, imports, dependecies, ci); + Deencapsulation.invoke(testSubject, "createDependency", componentCache, imports, dependecies, ci, false); assertFalse(componentCache.isEmpty()); } |