diff options
19 files changed, 441 insertions, 34 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml index 4f5374fa3c..9d3204b732 100644 --- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml +++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml @@ -2595,4 +2595,20 @@ errors: code: 400, message: "Invalid label name. Only the following characters are allowed in label name: '%1'", messageId: "SVC4158" + } + + #---------SVC4159----------------------------- + # %1 - The model name + COULD_NOT_DELETE_MODEL: { + code: 500, + message: "Could not delete the model '%1'.", + messageId: "SVC4159" + } + + #---------SVC4160----------------------------- + # %1 - The model name + COULD_NOT_DELETE_MODEL_ELEMENTS: { + code: 500, + message: "Could not delete the model '%1' elements.", + messageId: "SVC4160" }
\ No newline at end of file diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java index c8b50d28a6..f1ea1eef9a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/lifecycle/UndoCheckoutTransition.java @@ -106,7 +106,7 @@ public class UndoCheckoutTransition extends LifeCycleTransition { Either<? extends Component, ResponseFormat> result = null; log.debug("start performing undo-checkout for resource {}", component.getUniqueId()); try { - Either<ToscaElement, StorageOperationStatus> undoCheckoutResourceResult = lifeCycleOperation.undoCheckout(component.getUniqueId()); + Either<ToscaElement, StorageOperationStatus> undoCheckoutResourceResult = lifeCycleOperation.undoCheckout(component.getUniqueId(), component.getModel()); if (undoCheckoutResourceResult.isRight()) { log.debug("checkout failed on graph"); StorageOperationStatus response = undoCheckoutResourceResult.right().value(); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java index 18cdb424f6..2de9000145 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/servlets/ArchiveEndpointTest.java @@ -92,6 +92,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOper import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; +import org.openecomp.sdc.be.model.operations.impl.ModelElementOperation; import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.be.servlets.exception.ComponentExceptionMapper; import org.openecomp.sdc.be.servlets.exception.DefaultExceptionMapper; @@ -267,6 +268,11 @@ class ArchiveEndpointTest extends JerseyTest { return new ModelOperation(null, null, null, null); } + @Bean + ModelElementOperation modelElementOperation() { + return new ModelElementOperation(null, null, null); + } + private void initGraphForTest() { //Create Catalog Root catalogVertex = GraphTestUtils.createRootCatalogVertex(janusGraphDao); diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java index 30fcfac03e..2a71089b74 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/ActionStatus.java @@ -54,7 +54,7 @@ public enum ActionStatus { // Model related MODEL_ALREADY_EXISTS, INVALID_MODEL, MODEL_IMPORTS_IS_EMPTY, COULD_NOT_READ_MODEL_IMPORTS, MODEL_NOT_FOUND, MODEL_NAME_CANNOT_BE_EMPTY, COMPONENT_WITH_MODEL_ALREADY_EXIST, COMPONENT_WITH_VENDOR_RELEASE_ALREADY_EXISTS, COMPONENT_WITH_VENDOR_RELEASE_ALREADY_EXISTS_IN_MODEL, - UNKNOWN_MODEL_TYPE, + UNKNOWN_MODEL_TYPE, COULD_NOT_DELETE_MODEL, COULD_NOT_DELETE_MODEL_ELEMENTS, // Service API URL INVALID_SERVICE_API_URL, // Property related diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java new file mode 100644 index 0000000000..fb37b54d2e --- /dev/null +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/api/exception/JanusGraphException.java @@ -0,0 +1,36 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.dao.api.exception; + +import lombok.Getter; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; + +@Getter +public class JanusGraphException extends RuntimeException { + + private final JanusGraphOperationStatus status; + + public JanusGraphException(final JanusGraphOperationStatus status, final String message) { + super(message); + this.status = status; + } +} diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/ToscaModelImportCassandraDao.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/ToscaModelImportCassandraDao.java index c250aecdef..d21b561094 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/ToscaModelImportCassandraDao.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/cassandra/ToscaModelImportCassandraDao.java @@ -122,4 +122,9 @@ public class ToscaModelImportCassandraDao extends CassandraDao { return toscaImportByModelAccessor.findAllByModel(modelId).all(); } + public void deleteAllByModel(final String modelId) { + final List<ToscaImportByModel> allByModel = findAllByModel(modelId); + allByModel.forEach(toscaImportByModelMapper::delete); + } + } diff --git a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/janusgraph/JanusGraphGenericDao.java b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/janusgraph/JanusGraphGenericDao.java index 2116dcc27e..8382af5e8b 100644 --- a/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/janusgraph/JanusGraphGenericDao.java +++ b/catalog-dao/src/main/java/org/openecomp/sdc/be/dao/janusgraph/JanusGraphGenericDao.java @@ -48,6 +48,7 @@ import org.janusgraph.core.JanusGraphVertexQuery; import org.janusgraph.core.PropertyKey; import org.janusgraph.graphdb.query.JanusGraphPredicate; import org.openecomp.sdc.be.config.ConfigurationManager; +import org.openecomp.sdc.be.dao.api.exception.JanusGraphException; import org.openecomp.sdc.be.dao.graph.GraphElementFactory; import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge; import org.openecomp.sdc.be.dao.graph.datatype.GraphElementTypeEnum; @@ -59,6 +60,7 @@ import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.resources.data.GraphNodeLock; +import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; import org.openecomp.sdc.common.log.wrappers.Logger; import org.springframework.beans.factory.annotation.Qualifier; @@ -1318,6 +1320,58 @@ public class JanusGraphGenericDao { return Either.left(immutablePairs); } + public <T extends GraphNode> JanusGraphOperationStatus deleteAllChildrenNodes(String key, String uniqueId, GraphEdgeLabels edgeType) { + final JanusGraph janusGraph = getJanusGraph(); + final Iterable<JanusGraphVertex> vertices = janusGraph.query().has(key, uniqueId).vertices(); + if (vertices == null || !vertices.iterator().hasNext()) { + return JanusGraphOperationStatus.NOT_FOUND; + } + final Vertex rootVertex = vertices.iterator().next(); + final Iterator<Edge> outEdges = rootVertex.edges(Direction.OUT, edgeType.getProperty()); + while (outEdges.hasNext()) { + final Edge edge = outEdges.next(); + final Vertex vertexIn = edge.inVertex(); + final Iterator<Edge> outSubEdges = vertexIn.edges(Direction.OUT); + while (outSubEdges.hasNext()) { + Edge subEdge = outSubEdges.next(); + Vertex vertex = subEdge.inVertex(); + Map<String, Object> properties = getProperties(vertex); + if (properties != null) { + String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty()); + if (label.equals("property")) { + vertex.remove(); + } + } + } + Map<String, Object> properties = getProperties(vertexIn); + if (properties != null) { + String label = (String) properties.get(GraphPropertiesDictionary.LABEL.getProperty()); + GraphNode node = GraphElementFactory + .createElement(label, GraphElementTypeEnum.Node, properties, GraphNode.class); + if (node != null) { + vertexIn.remove(); + } + } + } + return JanusGraphOperationStatus.OK; + } + + /** + * Gets the JanusGraph instance. + * + * @return the JanusGraph instance + * @throws JanusGraphException when the graph was not created + */ + public JanusGraph getJanusGraph() { + final Either<JanusGraph, JanusGraphOperationStatus> graphRes = janusGraphClient.getGraph(); + if (graphRes.isRight()) { + final var errorMsg = String.format("Failed to retrieve graph. Status was '%s'", graphRes.right().value()); + log.error(EcompLoggerErrorCode.SCHEMA_ERROR, JanusGraphGenericDao.class.getName(), errorMsg); + throw new JanusGraphException(graphRes.right().value(), errorMsg); + } + return graphRes.left().value(); + } + public Either<List<ImmutablePair<JanusGraphVertex, Edge>>, JanusGraphOperationStatus> getChildrenVertecies(String key, String uniqueId, GraphEdgeLabels edgeType) { List<ImmutablePair<JanusGraphVertex, Edge>> immutablePairs = new ArrayList<>(); diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementLifecycleOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementLifecycleOperation.java index 963458b71a..d46d4a554e 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementLifecycleOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementLifecycleOperation.java @@ -60,10 +60,12 @@ import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.GraphPropertyEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; +import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; import org.openecomp.sdc.be.model.DistributionStatusEnum; import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Model; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement; @@ -71,10 +73,12 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum; import org.openecomp.sdc.be.model.jsonjanusgraph.enums.JsonConstantKeysEnum; 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.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.common.jsongraph.util.CommonUtility; import org.openecomp.sdc.common.jsongraph.util.CommonUtility.LogLevelEnum; import org.openecomp.sdc.common.log.wrappers.Logger; +import org.springframework.beans.factory.annotation.Autowired; @org.springframework.stereotype.Component("tosca-element-lifecycle-operation") /** @@ -87,6 +91,12 @@ public class ToscaElementLifecycleOperation extends BaseOperation { private static final String FAILED_TO_DELETE_LAST_STATE_EDGE_STATUS_IS = "Failed to delete last state edge. Status is {}. "; private static final String FAILED_TO_GET_VERTICES = "Failed to get vertices by id {}. Status is {}. "; private static final Logger log = Logger.getLogger(ToscaElementLifecycleOperation.class); + private final ModelOperation modelOperation; + + @Autowired + public ToscaElementLifecycleOperation(ModelOperation modelOperation) { + this.modelOperation = modelOperation; + } static StorageOperationStatus handleFailureToPrepareParameters(final JanusGraphOperationStatus status, final String toscaElementId) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); @@ -223,12 +233,12 @@ public class ToscaElementLifecycleOperation extends BaseOperation { * @param toscaElementId * @return */ - public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId) { + public Either<ToscaElement, StorageOperationStatus> undoCheckout(String toscaElementId, String model) { try { return janusGraphDao.getVertexById(toscaElementId, JsonParseFlagEnum.ParseMetadata).right().map(errorStatus -> { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, FAILED_TO_GET_VERTICES, toscaElementId); return DaoStatusConverter.convertJanusGraphStatusToStorageStatus(errorStatus); - }).left().bind(this::retrieveAndUpdatePreviousVersion).left().bind(this::updateEdgeToCatalogRootAndReturnPreVersionElement); + }).left().bind(this::retrieveAndUpdatePreviousVersion).left().bind(tuple -> updateEdgeToCatalogRootAndReturnPreVersionElement(tuple, model)); } catch (Exception e) { CommonUtility.addRecordToLog(log, LogLevelEnum.DEBUG, "Exception occurred during undo checkout tosca element {}. {}", toscaElementId, e.getMessage()); @@ -260,13 +270,17 @@ public class ToscaElementLifecycleOperation extends BaseOperation { } private Either<ToscaElement, StorageOperationStatus> updateEdgeToCatalogRootAndReturnPreVersionElement( - final P2<GraphVertex, JanusGraphVertex> tuple) { + final P2<GraphVertex, JanusGraphVertex> tuple, final String model) { final GraphVertex currVersionV = tuple._1(); final JanusGraphVertex preVersionVertex = tuple._2(); StorageOperationStatus updateCatalogRes = updateEdgeToCatalogRootByUndoCheckout(preVersionVertex, currVersionV); if (updateCatalogRes != StorageOperationStatus.OK) { return Either.right(updateCatalogRes); } else { + final Optional<Model> modelOptional = modelOperation.findModelByName(model); + if (modelOptional.isPresent() && modelOptional.get().getModelType() == ModelTypeEnum.NORMATIVE_EXTENSION) { + modelOperation.deleteModel(modelOptional.get(), false); + } final ToscaElementOperation operation = getToscaElementOperation(currVersionV.getLabel()); return operation.deleteToscaElement(currVersionV).left().bind(discarded -> getUpdatedPreVersionElement(operation, preVersionVertex)); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java index 30323af521..763151683f 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/OperationException.java @@ -35,7 +35,13 @@ public class OperationException extends BusinessException { params = new String[0]; } - public OperationException(final ActionStatus actionStatus, String... params) { + public OperationException(final ActionStatus actionStatus, final String... params) { + this.actionStatus = actionStatus; + this.params = params; + } + + public OperationException(final Throwable cause, final ActionStatus actionStatus, final String... params) { + super(cause); this.actionStatus = actionStatus; this.params = params; } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java index d6cca3f824..a0963c9030 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperation.java @@ -24,15 +24,17 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.collections4.MapUtils; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraph; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity; import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphGenericDao; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; +import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; +import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; -import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.resources.data.DataTypeData; import org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode; import org.slf4j.Logger; @@ -45,12 +47,16 @@ public class DataTypeOperation extends AbstractOperation { private static final Logger LOGGER = LoggerFactory.getLogger(DataTypeOperation.class); - private final ModelOperation modelOperation; + private ModelOperation modelOperation; @Autowired - public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao, - final ModelOperation modelOperation) { + public DataTypeOperation(final HealingJanusGraphGenericDao janusGraphGenericDao) { this.janusGraphGenericDao = janusGraphGenericDao; + } + + //circular dependency ModelOperation->ModelElementOperation->DataTypeOperation + @Autowired + public void setModelOperation(final ModelOperation modelOperation) { this.modelOperation = modelOperation; } @@ -132,4 +138,18 @@ public class DataTypeOperation extends AbstractOperation { return getDataTypes.left().value(); } + public void deleteDataTypesByModelId(final String modelId) { + final JanusGraph janusGraph = janusGraphGenericDao.getJanusGraph(); + final GraphTraversalSource traversal = janusGraph.traversal(); + final List<Vertex> dataTypeList = traversal.V() + .has(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), modelId) + .out(GraphEdgeLabels.MODEL_ELEMENT.getProperty()) + .has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.DataType.getName()) + .toList(); + dataTypeList.forEach(dataTypeVertex -> { + traversal.V(dataTypeVertex).out(GraphEdgeLabels.PROPERTY.getProperty()).drop().iterate(); + dataTypeVertex.remove(); + }); + } + } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java new file mode 100644 index 0000000000..048fbfd067 --- /dev/null +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperation.java @@ -0,0 +1,74 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.model.operations.impl; + +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao; +import org.openecomp.sdc.be.model.Model; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component("model-element-operation") +public class ModelElementOperation { + + private final JanusGraphGenericDao janusGraphGenericDao; + private final DataTypeOperation dataTypeOperation; + private final PolicyTypeOperation policyTypeOperation; + + @Autowired + public ModelElementOperation(final JanusGraphGenericDao janusGraphGenericDao, + final DataTypeOperation dataTypeOperation, + final PolicyTypeOperation policyTypeOperation) { + this.janusGraphGenericDao = janusGraphGenericDao; + this.dataTypeOperation = dataTypeOperation; + this.policyTypeOperation = policyTypeOperation; + } + + /** + * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files. + * + * @param model the model + * @param inTransaction if the operation is called in the middle of a janusgraph transaction + */ + public void deleteModelElements(final Model model, final boolean inTransaction) { + boolean rollback = false; + + try { + final String modelId = UniqueIdBuilder.buildModelUid(model.getName()); + dataTypeOperation.deleteDataTypesByModelId(modelId); + policyTypeOperation.deletePolicyTypesByModelId(modelId); + } catch (final Exception e) { + rollback = true; + throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL_ELEMENTS, model.getName()); + } finally { + if (!inTransaction) { + if (rollback) { + janusGraphGenericDao.rollback(); + } else { + janusGraphGenericDao.commit(); + } + } + } + } + +} diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java index 095b4e1cef..b5cb9d98c0 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/ModelOperation.java @@ -38,10 +38,10 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.cassandra.ToscaModelImportCassandraDao; import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge; import org.openecomp.sdc.be.dao.graph.datatype.GraphRelation; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; -import org.openecomp.sdc.be.dao.janusgraph.JanusGraphDao; import org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum; import org.openecomp.sdc.be.dao.neo4j.GraphEdgeLabels; import org.openecomp.sdc.be.data.model.ToscaImportByModel; @@ -71,6 +71,7 @@ public class ModelOperation { private final JanusGraphDao janusGraphDao; private final ToscaModelImportCassandraDao toscaModelImportCassandraDao; private final DerivedFromOperation derivedFromOperation; + private ModelElementOperation modelElementOperation; @Autowired public ModelOperation(final JanusGraphGenericDao janusGraphGenericDao, @@ -322,4 +323,54 @@ public class ModelOperation { + "description: Auto-generated file that contains package custom types or types added after system installation." + "\n"; } + /** + * Deletes the given model if it exists, along with its MODEL_ELEMENT edges and import files. + * + * @param model the model + * @param inTransaction if the operation is called in the middle of a janusgraph transaction + */ + public void deleteModel(final Model model, final boolean inTransaction) { + boolean rollback = false; + + try { + final GraphVertex modelVertexByName = findModelVertexByName(model.getName()).orElse(null); + if (modelVertexByName == null) { + return; + } + toscaModelImportCassandraDao.deleteAllByModel(model.getName()); + modelElementOperation.deleteModelElements(model, inTransaction); + deleteModel(model); + } catch (final OperationException e) { + rollback = true; + throw e; + } catch (final Exception e) { + rollback = true; + throw new OperationException(e, ActionStatus.COULD_NOT_DELETE_MODEL, model.getName()); + } finally { + if (!inTransaction) { + if (rollback) { + janusGraphGenericDao.rollback(); + } else { + janusGraphGenericDao.commit(); + } + } + } + } + + private void deleteModel(final Model model) { + final var modelData = new ModelData(model.getName(), UniqueIdBuilder.buildModelUid(model.getName()), model.getModelType()); + final Either<ModelData, JanusGraphOperationStatus> deleteParentNodeByModel = janusGraphGenericDao.deleteNode(modelData, ModelData.class); + if (deleteParentNodeByModel.isRight()) { + final var janusGraphOperationStatus = deleteParentNodeByModel.right().value(); + log.error(EcompLoggerErrorCode.DATA_ERROR, ModelOperation.class.getName(), + "Failed to delete model {} on JanusGraph with status {}", new Object[] {model.getName(), janusGraphOperationStatus}); + throw new OperationException(ActionStatus.COULD_NOT_DELETE_MODEL, model.getName()); + } + } + + @Autowired + public void setModelElementOperation(final ModelElementOperation modelElementOperation) { + this.modelElementOperation = modelElementOperation; + } + } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PolicyTypeOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PolicyTypeOperation.java index 99a284168e..db3c5574b4 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PolicyTypeOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PolicyTypeOperation.java @@ -18,8 +18,8 @@ * ============LICENSE_END========================================================= */ package org.openecomp.sdc.be.model.operations.impl; + import static org.openecomp.sdc.be.dao.janusgraph.JanusGraphUtils.buildNotInPredicate; -import static org.openecomp.sdc.common.log.enums.EcompLoggerErrorCode.BUSINESS_PROCESS_ERROR; import fj.data.Either; import java.util.ArrayList; @@ -31,6 +31,9 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource; +import org.apache.tinkerpop.gremlin.structure.Vertex; +import org.janusgraph.core.JanusGraph; import org.janusgraph.graphdb.query.JanusGraphPredicate; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.graph.datatype.GraphEdge; @@ -60,13 +63,17 @@ public class PolicyTypeOperation extends AbstractOperation implements IPolicyTyp private static final Logger log = Logger.getLogger(PolicyTypeOperation.class.getName()); private static final String CREATE_FLOW_CONTEXT = "CreatePolicyType"; private static final String GET_FLOW_CONTEXT = "GetPolicyType"; - @Autowired - private PropertyOperation propertyOperation; - @Autowired - private DerivedFromOperation derivedFromOperation; - @Autowired - private OperationUtils operationUtils; + private final PropertyOperation propertyOperation; + private final DerivedFromOperation derivedFromOperation; + private final OperationUtils operationUtils; + @Autowired + public PolicyTypeOperation(final PropertyOperation propertyOperation, final DerivedFromOperation derivedFromOperation, + final OperationUtils operationUtils) { + this.propertyOperation = propertyOperation; + this.derivedFromOperation = derivedFromOperation; + this.operationUtils = operationUtils; + } @Override public Either<PolicyTypeDefinition, StorageOperationStatus> getLatestPolicyTypeByType(String type, String model) { @@ -328,4 +335,18 @@ public class PolicyTypeOperation extends AbstractOperation implements IPolicyTyp updatedTypeDefinition.setCreationTime(currTypeDefinition.getCreationTime()); updatedTypeDefinition.setModificationTime(System.currentTimeMillis()); } + + public void deletePolicyTypesByModelId(final String modelId) { + final JanusGraph janusGraph = janusGraphGenericDao.getJanusGraph(); + final GraphTraversalSource traversal = janusGraph.traversal(); + final List<Vertex> policyTypeList = traversal.V() + .has(GraphPropertiesDictionary.UNIQUE_ID.getProperty(), modelId) + .out(GraphEdgeLabels.MODEL_ELEMENT.getProperty()) + .has(GraphPropertiesDictionary.LABEL.getProperty(), NodeTypeEnum.PolicyType.getName()) + .toList(); + policyTypeList.forEach(policyTypeVertex -> { + traversal.V(policyTypeVertex).out(GraphEdgeLabels.PROPERTY.getProperty()).drop().iterate(); + policyTypeVertex.remove(); + }); + } } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java index 01dbb07fb4..bf8d6aed15 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperation.java @@ -119,15 +119,19 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe private static final String THE_VALUE_OF_PROPERTY_FROM_TYPE_IS_INVALID = "The value {} of property from type {} is invalid"; private static final String PROPERTY = "Property"; private static final String UPDATE_DATA_TYPE = "UpdateDataType"; - private static Logger log = Logger.getLogger(PropertyOperation.class.getName()); - private DerivedFromOperation derivedFromOperation; + private static final Logger log = Logger.getLogger(PropertyOperation.class.getName()); + private final DerivedFromOperation derivedFromOperation; private DataTypeOperation dataTypeOperation; @Autowired - public PropertyOperation(HealingJanusGraphGenericDao janusGraphGenericDao, DerivedFromOperation derivedFromOperation, - DataTypeOperation dataTypeOperation) { + public PropertyOperation(final HealingJanusGraphGenericDao janusGraphGenericDao, final DerivedFromOperation derivedFromOperation) { this.janusGraphGenericDao = janusGraphGenericDao; this.derivedFromOperation = derivedFromOperation; + } + + //circular dependency DataTypeOperation->ModelOperation->ModelElementOperation->PropertyOperation + @Autowired + public void setDataTypeOperation(DataTypeOperation dataTypeOperation) { this.dataTypeOperation = dataTypeOperation; } @@ -2264,4 +2268,5 @@ public class PropertyOperation extends AbstractOperation implements IPropertyOpe return null; } } + } diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java index d93b7986f8..1580fd34b8 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/DataTypeOperationTest.java @@ -38,7 +38,6 @@ import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.Model; -import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.resources.data.DataTypeData; import org.springframework.test.context.ContextConfiguration; @@ -51,8 +50,6 @@ class DataTypeOperationTest { private ModelOperation modelOperation; @Mock private HealingJanusGraphGenericDao janusGraphGenericDao; - @Mock - private ApplicationDataTypeCache applicationDataTypeCache; private final String modelName = "ETSI-SDC-MODEL-TEST"; private final List<DataTypeData> dataTypesWithoutModel = new ArrayList<>(); @@ -61,10 +58,10 @@ class DataTypeOperationTest { final Map<String, DataTypeDefinition> allDataTypesFoundDefinitionMap = new HashMap<>(); private Model model; - @BeforeEach void beforeEachInit() { MockitoAnnotations.openMocks(this); + dataTypeOperation.setModelOperation(modelOperation); initTestData(); } diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java new file mode 100644 index 0000000000..3de1369e83 --- /dev/null +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ModelElementOperationTest.java @@ -0,0 +1,96 @@ +/* + * - + * ============LICENSE_START======================================================= + * Copyright (C) 2021 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.openecomp.sdc.be.model.operations.impl; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphGenericDao; +import org.openecomp.sdc.be.model.Model; + +class ModelElementOperationTest { + + @Mock + private JanusGraphGenericDao janusGraphGenericDao; + @Mock + private DataTypeOperation dataTypeOperation; + @Mock + private PolicyTypeOperation policyTypeOperation; + @InjectMocks + private ModelElementOperation modelElementOperation; + + @BeforeEach + void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + void deleteModelElements_noTransactionSuccessTest() { + var model = new Model("name"); + final String modelId = UniqueIdBuilder.buildModelUid(model.getName()); + modelElementOperation.deleteModelElements(model, false); + verify(dataTypeOperation).deleteDataTypesByModelId(modelId); + verify(policyTypeOperation).deletePolicyTypesByModelId(modelId); + verify(janusGraphGenericDao).commit(); + verify(janusGraphGenericDao, times(0)).rollback(); + } + + @Test + void deleteModelElements_inTransactionSuccessTest() { + var model = new Model("name"); + final String modelId = UniqueIdBuilder.buildModelUid(model.getName()); + modelElementOperation.deleteModelElements(model, true); + verify(dataTypeOperation).deleteDataTypesByModelId(modelId); + verify(policyTypeOperation).deletePolicyTypesByModelId(modelId); + verify(janusGraphGenericDao, times(0)).commit(); + verify(janusGraphGenericDao, times(0)).rollback(); + } + + @Test + void deleteModelElements_noTransactionErrorTest() { + var model = new Model("name"); + final String modelId = UniqueIdBuilder.buildModelUid(model.getName()); + doThrow(new RuntimeException()).when(dataTypeOperation).deleteDataTypesByModelId(modelId); + assertThrows(RuntimeException.class, () -> modelElementOperation.deleteModelElements(model, false)); + verify(dataTypeOperation).deleteDataTypesByModelId(modelId); + verify(janusGraphGenericDao).rollback(); + verify(janusGraphGenericDao, times(0)).commit(); + } + + @Test + void deleteModelElements_inTransactionErrorTest() { + var model = new Model("name"); + final String modelId = UniqueIdBuilder.buildModelUid(model.getName()); + doThrow(new RuntimeException()).when(dataTypeOperation).deleteDataTypesByModelId(modelId); + assertThrows(RuntimeException.class, () -> modelElementOperation.deleteModelElements(model, true)); + verify(dataTypeOperation).deleteDataTypesByModelId(modelId); + verify(janusGraphGenericDao, times(0)).commit(); + verify(janusGraphGenericDao, times(0)).rollback(); + } +}
\ No newline at end of file diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperationTest.java index 793af71bbd..a3c9bca4e5 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperationTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/PropertyOperationTest.java @@ -73,12 +73,12 @@ public class PropertyOperationTest extends ModelTestBase { final DataTypeOperation dataTypeOperation = mock(DataTypeOperation.class); - PropertyOperation propertyOperation = new PropertyOperation(janusGraphGenericDao, null, dataTypeOperation); + PropertyOperation propertyOperation = new PropertyOperation(janusGraphGenericDao, null); @Before public void setup() { + propertyOperation.setDataTypeOperation(dataTypeOperation); propertyOperation.setJanusGraphGenericDao(janusGraphGenericDao); - } private PropertyDefinition buildPropertyDefinition() { @@ -456,9 +456,11 @@ public class PropertyOperationTest extends ModelTestBase { } - private PropertyOperation createTestSubject() { - return new PropertyOperation(new HealingJanusGraphGenericDao(new JanusGraphClient()), null, dataTypeOperation); - } + private PropertyOperation createTestSubject() { + final var propertyOperation = new PropertyOperation(new HealingJanusGraphGenericDao(new JanusGraphClient()), null); + propertyOperation.setDataTypeOperation(dataTypeOperation); + return propertyOperation; + } @Test public void testConvertPropertyDataToPropertyDefinition() throws Exception { diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java index a80e44e921..b4f61563c1 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/operations/impl/ToscaElementLifecycleOperationTest.java @@ -262,7 +262,7 @@ public class ToscaElementLifecycleOperationTest extends ModelTestBase { expectedIds.add(vertex4.getUniqueId()); verifyInCatalogData(4, expectedIds); - lifecycleOperation.undoCheckout(vertex4.getUniqueId()); + lifecycleOperation.undoCheckout(vertex4.getUniqueId(), null); expectedIds.remove(vertex4.getUniqueId()); verifyInCatalogData(3, expectedIds); diff --git a/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java b/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java index 69fb00f3b5..0b1224a101 100644 --- a/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java +++ b/common-be/src/main/java/org/openecomp/sdc/be/exception/BusinessException.java @@ -28,6 +28,10 @@ public abstract class BusinessException extends RuntimeException { super(message); } + protected BusinessException(final Throwable cause) { + super(cause); + } + protected BusinessException(final String message, final Throwable cause) { super(message, cause); } |