From 1ff5cd3de7ccc52adf0f4cbdf9c7ab511bd5c4a5 Mon Sep 17 00:00:00 2001 From: JvD_Ericsson Date: Tue, 29 Mar 2022 13:41:35 +0100 Subject: Support deletion of archived services in SDC BE Issue-ID: SDC-3936 Change-Id: I75201007c9cf6b71b035f14864e380d78aace12b Signed-off-by: JvD_Ericsson --- .../files/default/error-configuration.yaml | 15 ++++++++ .../be/components/impl/ServiceBusinessLogic.java | 41 ++++++++++++++++++++-- .../openecomp/sdc/be/servlets/ServiceServlet.java | 18 ++++++++-- .../components/BaseServiceBusinessLogicTest.java | 5 ++- .../be/components/ServiceDistributionBLTest.java | 4 ++- .../impl/ServiceBusinessLogicBaseTestSetup.java | 4 ++- .../components/impl/ServiceBusinessLogicTest.java | 40 +++++++++++++++++++++ 7 files changed, 120 insertions(+), 7 deletions(-) (limited to 'catalog-be/src') 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 10cc6f6712..9e7939d58b 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 @@ -2635,6 +2635,21 @@ errors: messageId: "SVC4163" } + #---------SVC4164----------------------------- + # %1 - Component name + COMPONENT_NOT_ARCHIVED: { + code: 403, + message: "Component '%1' is not archived", + messageId: "SVC4692" + } + + #---------SVC4165----------------------------- + # %1 - List of services + COMPONENT_IN_USE_BY_ANOTHER_COMPONENT: { + code: 403, + message: "Component is in use by '%1'", + messageId: "SVC4693" + } #---------SVC4164----------------------------- # %1 - componentType # %2 - component name diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java index aa011e91f4..8dac6ffc08 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java @@ -102,6 +102,7 @@ import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceDistributionReqInfo; import org.openecomp.sdc.be.impl.ForwardingPathUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; @@ -123,6 +124,7 @@ import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.Resource; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.Model; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ForwardingPathOperation; @@ -133,6 +135,7 @@ import org.openecomp.sdc.be.model.operations.api.IGroupOperation; import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; +import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; import org.openecomp.sdc.be.plugins.ServiceCreationPlugin; @@ -194,6 +197,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { private ServiceCategoryValidator serviceCategoryValidator; @Autowired private ServiceValidator serviceValidator; + private final ModelOperation modelOperation; @Autowired public ServiceBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation, @@ -205,7 +209,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { ComponentContactIdValidator componentContactIdValidator, ComponentNameValidator componentNameValidator, ComponentTagsValidator componentTagsValidator, ComponentValidator componentValidator, ComponentIconValidator componentIconValidator, ComponentProjectCodeValidator componentProjectCodeValidator, - ComponentDescriptionValidator componentDescriptionValidator) { + ComponentDescriptionValidator componentDescriptionValidator, ModelOperation modelOperation) { super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation, interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator, componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator); @@ -214,6 +218,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { this.serviceDistributionValidation = serviceDistributionValidation; this.forwardingPathValidator = forwardingPathValidator; this.uiComponentDataConverter = uiComponentDataConverter; + this.modelOperation = modelOperation; } @Autowired @@ -1301,7 +1306,39 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { return Either.left(serviceRelations); } - public ResponseFormat deleteService(String serviceId, User user) { + public void deleteServiceAllVersions(String serviceId, User user) { + validateUserExists(user); + Either serviceStatus = toscaOperationFacade.getToscaElement(serviceId); + if (serviceStatus.isRight()) { + log.debug("Failed to get service {}", serviceId); + componentException(serviceStatus.right().value()); + } + Service service = serviceStatus.left().value(); + if (Boolean.FALSE.equals(service.isArchived())) { + log.debug("The service, {}, requested for delete has not been archived.", serviceId); + throw new ComponentException(ActionStatus.COMPONENT_NOT_ARCHIVED, serviceId); + } + List deletedServiceList = new ArrayList<>(); + try { + String model = service.getModel(); + final Optional modelOptional = modelOperation.findModelByName(model); + deletedServiceList = toscaOperationFacade.deleteService(service.getInvariantUUID(), true); + if (log.isDebugEnabled()) { + deletedServiceList.forEach(deletedS -> log.debug("Component {} was deleted.", deletedS)); + } + if (modelOptional.isPresent() && modelOptional.get().getModelType() == ModelTypeEnum.NORMATIVE_EXTENSION) { + modelOperation.deleteModel(modelOptional.get(), false); + } + toscaOperationFacade.commitAndCheck(service.getUniqueId()); + updateCatalog(service, ChangeTypeEnum.DELETE); + } catch (ComponentException exception) { + log.debug("Failed to delete service, {}, in ServiceServlet", serviceId); + janusGraphDao.rollback(); + throw exception; + } + } + + public ResponseFormat markServiceForDeletion(String serviceId, User user) { ResponseFormat responseFormat; validateUserExists(user); Either serviceStatus = toscaOperationFacade.getToscaElement(serviceId); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java index bf171c2042..bcedc60d40 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceServlet.java @@ -52,6 +52,7 @@ import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; +import javax.ws.rs.QueryParam; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; @@ -109,6 +110,8 @@ public class ServiceServlet extends AbstractValidationsServlet { private final ElementBusinessLogic elementBusinessLogic; private final ServiceBusinessLogic serviceBusinessLogic; + public enum Action {DELETE, MARK_AS_DELETE} + @Inject public ServiceServlet(UserBusinessLogic userBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBL, ComponentsUtils componentsUtils, ServletUtils servletUtils, ResourceImportManager resourceImportManager, ServiceBusinessLogic serviceBusinessLogic, @@ -269,7 +272,12 @@ public class ServiceServlet extends AbstractValidationsServlet { @ApiResponse(responseCode = "400", description = "Invalid content / Missing content"), @ApiResponse(responseCode = "404", description = "Service not found")}) @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) - public Response deleteService(@PathParam("serviceId") final String serviceId, @Context final HttpServletRequest request) { + public Response deleteService(@PathParam("serviceId") final String serviceId, + @Parameter(description = "Optional parameter to determine the delete action: " + + "DELETE, which will permanently delete theService from the system or " + + "MARK_AS_DELETE, which will logically mark the service as deleted. Default action is to MARK_AS_DELETE") + @QueryParam("deleteAction") final Action deleteAction, + @Context final HttpServletRequest request) { ServletContext context = request.getSession().getServletContext(); String url = request.getMethod() + " " + request.getRequestURI(); log.debug(START_HANDLE_REQUEST_OF, url); @@ -284,7 +292,13 @@ public class ServiceServlet extends AbstractValidationsServlet { .log(LoggerSupportabilityActions.DELETE_SERVICE, StatusCode.STARTED, "Starting to delete service {} by user {} ", serviceIdLower, userId); ServiceBusinessLogic businessLogic = getServiceBL(context); - ResponseFormat actionResponse = businessLogic.deleteService(serviceIdLower, modifier); + ResponseFormat actionResponse; + if (Action.DELETE.equals(deleteAction)) { + businessLogic.deleteServiceAllVersions(serviceIdLower, modifier); + actionResponse = componentsUtils.getResponseFormat(ActionStatus.NO_CONTENT); + } else { + actionResponse = businessLogic.markServiceForDeletion(serviceIdLower, modifier); + } if (actionResponse.getStatus() != HttpStatus.SC_NO_CONTENT) { log.debug("failed to delete service"); return buildErrorResponse(actionResponse); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/BaseServiceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/BaseServiceBusinessLogicTest.java index ee37ea130d..692e8cce50 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/BaseServiceBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/BaseServiceBusinessLogicTest.java @@ -67,6 +67,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation; +import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent; import org.openecomp.sdc.be.user.Role; import org.openecomp.sdc.be.user.UserBusinessLogic; @@ -98,6 +99,7 @@ public abstract class BaseServiceBusinessLogicTest extends ComponentBusinessLogi private ToscaOperationFacade toscaOperationFacade = Mockito.mock(ToscaOperationFacade.class); private GenericTypeBusinessLogic genericTypeBusinessLogic = Mockito.mock(GenericTypeBusinessLogic.class); private ForwardingPathOperation forwardingPathOperation = Mockito.mock(ForwardingPathOperation.class); + private final ModelOperation modelOperation = Mockito.mock(ModelOperation.class); User user = null; Service serviceResponse = null; @@ -165,7 +167,8 @@ public abstract class BaseServiceBusinessLogicTest extends ComponentBusinessLogi artifactsBusinessLogic, distributionEngine, componentInstanceBusinessLogic, serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter, artifactToscaOperation, componentContactIdValidator, componentNameValidator, - componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator); + componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator, + modelOperation); bl.setUserAdmin(mockUserAdmin); bl.setGraphLockOperation(graphLockOperation); bl.setJanusGraphDao(mockJanusGraphDao); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/ServiceDistributionBLTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/ServiceDistributionBLTest.java index 72cb51676b..0b3973e584 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/ServiceDistributionBLTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/ServiceDistributionBLTest.java @@ -53,6 +53,7 @@ import org.openecomp.sdc.be.model.DistributionStatusEnum; import org.openecomp.sdc.be.model.Service; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.common.impl.ExternalConfiguration; import org.openecomp.sdc.common.util.ThreadLocalsHolder; import org.openecomp.sdc.exception.ResponseFormat; @@ -66,6 +67,7 @@ class ServiceDistributionBLTest extends ComponentBusinessLogicMock { private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic = Mockito.mock(ComponentInstanceBusinessLogic.class); private final ForwardingPathValidator forwardingPathValidator = Mockito.mock(ForwardingPathValidator.class); private final UiComponentDataConverter uiComponentDataConverter = Mockito.mock(UiComponentDataConverter.class); + private final ModelOperation modelOperation = Mockito.mock(ModelOperation.class); @InjectMocks private final ServiceBusinessLogic bl = new ServiceBusinessLogic(elementDao, groupOperation, groupInstanceOperation, @@ -74,7 +76,7 @@ class ServiceDistributionBLTest extends ComponentBusinessLogicMock { serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter, artifactToscaOperation, componentContactIdValidator, componentNameValidator, componentTagsValidator, componentValidator, componentIconValidator, - componentProjectCodeValidator, componentDescriptionValidator); + componentProjectCodeValidator, componentDescriptionValidator, modelOperation); private Service serviceToActivate; private ActivationRequestInformation activationRequestInformation; diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicBaseTestSetup.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicBaseTestSetup.java index 44daa34aeb..5b4585136f 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicBaseTestSetup.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicBaseTestSetup.java @@ -78,6 +78,7 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade import org.openecomp.sdc.be.model.operations.api.IElementOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.GraphLockOperation; +import org.openecomp.sdc.be.model.operations.impl.ModelOperation; import org.openecomp.sdc.be.resources.data.auditing.DistributionDeployEvent; import org.openecomp.sdc.be.resources.data.auditing.DistributionNotificationEvent; import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent; @@ -110,6 +111,7 @@ class ServiceBusinessLogicBaseTestSetup extends BaseBusinessLogicMock { protected CatalogOperation catalogOperation = Mockito.mock(CatalogOperation.class); protected ResourceAdminEvent auditArchive2 = Mockito.mock(ResourceAdminEvent.class); protected ResourceAdminEvent auditRestore = Mockito.mock(ResourceAdminEvent.class); + protected ModelOperation modelOperation = Mockito.mock(ModelOperation.class); IElementOperation mockElementDao = new ElementOperationMock(); DistributionEngine distributionEngine = Mockito.mock(DistributionEngine.class); ServiceDistributionValidation serviceDistributionValidation = Mockito.mock(ServiceDistributionValidation.class); @@ -209,7 +211,7 @@ class ServiceBusinessLogicBaseTestSetup extends BaseBusinessLogicMock { serviceDistributionValidation, forwardingPathValidator, uiComponentDataConverter, artifactToscaOperation, componentContactIdValidator, componentNameValidator, componentTagsValidator, componentValidator, - componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator); + componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator, modelOperation); bl.setComponentContactIdValidator(componentContactIdValidator); bl.setComponentIconValidator(componentIconValidator); bl.setComponentTagsValidator(componentTagsValidator); diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java index 5c074b0599..69938cd527 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogicTest.java @@ -28,6 +28,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.Mockito.when; @@ -41,7 +42,9 @@ import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.UUID; + import org.apache.commons.lang3.tuple.ImmutablePair; import org.junit.jupiter.api.Test; import org.mockito.Mockito; @@ -51,16 +54,20 @@ import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition; import org.openecomp.sdc.be.datatypes.elements.InterfaceInstanceDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ModelTypeEnum; 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.ComponentInstanceInterface; import org.openecomp.sdc.be.model.GroupInstance; +import org.openecomp.sdc.be.model.Model; import org.openecomp.sdc.be.model.Operation; import org.openecomp.sdc.be.model.PropertyDefinition; 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.exception.ToscaOperationException; +import org.openecomp.sdc.be.model.operations.StorageException; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.plugins.ServiceCreationPlugin; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; @@ -659,6 +666,39 @@ class ServiceBusinessLogicTest extends ServiceBusinessLogicBaseTestSetup { assertFalse(resourceIdList.contains(resourceInUse)); } + @Test + void testDeleteArchivedService_NotFound() { + Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(Either.right(StorageOperationStatus.NOT_FOUND)); + assertThrows(StorageException.class, () -> bl.deleteServiceAllVersions("1", user)); + } + + @Test + void testDeleteArchivedService_NotArchived() { + String serviceId = "12345"; + Either eitherService = Either.left(createNewService()); + eitherService.left().value().setArchived(false); + Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(eitherService); + final ComponentException actualException = assertThrows(ComponentException.class, () -> bl.deleteServiceAllVersions(serviceId, user)); + assertEquals(actualException.getActionStatus(), ActionStatus.COMPONENT_NOT_ARCHIVED); + assertEquals(actualException.getParams()[0], serviceId); + } + + @Test + void testDeleteArchivedService_DeleteServiceSpecificModel() throws ToscaOperationException { + String serviceId = "12345"; + String model = "serviceSpecificModel"; + List deletedServcies= new ArrayList<>(); + deletedServcies.add("54321"); + Model normativeExtensionModel = new Model("normativeExtensionModel", ModelTypeEnum.NORMATIVE_EXTENSION); + Either eitherService = Either.left(createNewService()); + eitherService.left().value().setArchived(true); + eitherService.left().value().setModel(model); + Mockito.when(toscaOperationFacade.getToscaElement(Mockito.anyString())).thenReturn(eitherService); + Mockito.when(toscaOperationFacade.deleteService(Mockito.anyString(), Mockito.eq(true))).thenReturn(deletedServcies); + Mockito.when(modelOperation.findModelByName(model)).thenReturn(Optional.of(normativeExtensionModel)); + bl.deleteServiceAllVersions(serviceId, user); + Mockito.verify(modelOperation, Mockito.times(1)).deleteModel(normativeExtensionModel, false); + } @SuppressWarnings({ "unchecked", "rawtypes" }) @Test -- cgit 1.2.3-korg