diff options
author | JvD_Ericsson <jeff.van.dam@est.tech> | 2022-03-29 13:41:35 +0100 |
---|---|---|
committer | Vasyl Razinkov <vasyl.razinkov@est.tech> | 2022-04-25 21:55:34 +0000 |
commit | 1ff5cd3de7ccc52adf0f4cbdf9c7ab511bd5c4a5 (patch) | |
tree | c1ad607be57bbd83bf4f52d1723425853fd85d20 | |
parent | 7ce54a98719426a32e041e5bf30c950a4b226734 (diff) |
Support deletion of archived services in SDC BE
Issue-ID: SDC-3936
Change-Id: I75201007c9cf6b71b035f14864e380d78aace12b
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
13 files changed, 465 insertions, 21 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 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 @@ -2636,6 +2636,21 @@ errors: } #---------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 CANNOT_DELETE_SYSTEM_DEPLOYED_RESOURCES: { 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<Service, StorageOperationStatus> 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<String> deletedServiceList = new ArrayList<>(); + try { + String model = service.getModel(); + final Optional<Model> 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<Service, StorageOperationStatus> 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<Component, StorageOperationStatus> 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<String> deletedServcies= new ArrayList<>(); + deletedServcies.add("54321"); + Model normativeExtensionModel = new Model("normativeExtensionModel", ModelTypeEnum.NORMATIVE_EXTENSION); + Either<Component, StorageOperationStatus> 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 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 922853e8f0..3b5c9955d2 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 @@ -62,7 +62,7 @@ public enum ActionStatus { // Attribute related ATTRIBUTE_ALREADY_EXIST, ATTRIBUTE_NOT_FOUND, INVALID_ATTRIBUTE, // State related - INVALID_SERVICE_STATE, COMPONENT_IN_CHECKOUT_STATE, ILLEGAL_COMPONENT_STATE, COMPONENT_IN_CERT_IN_PROGRESS_STATE, COMPONENT_SENT_FOR_CERTIFICATION, COMPONENT_VERSION_ALREADY_EXIST, COMPONENT_ALREADY_CHECKED_IN, COMPONENT_CHECKOUT_BY_ANOTHER_USER, COMPONENT_IN_USE, COMPONENT_HAS_NEWER_VERSION, COMPONENT_ALREADY_CERTIFIED, COMPONENT_NOT_READY_FOR_CERTIFICATION, COMPONENT_ARTIFACT_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, SERVICE_NOT_FOUND, SERVICE_CATEGORY_CANNOT_BE_CHANGED, SERVICE_NAME_CANNOT_BE_CHANGED, SERVICE_ICON_CANNOT_BE_CHANGED, COMPONENT_TOO_MUCH_CATEGORIES, SERVICE_CANNOT_CONTAIN_SUBCATEGORY, RESOURCE_CATEGORY_CANNOT_BE_CHANGED, RESOURCE_NAME_CANNOT_BE_CHANGED, RESOURCE_ICON_CANNOT_BE_CHANGED, RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED, RESOURCE_TOO_MUCH_SUBCATEGORIES, SERVICE_ICON_EXCEEDS_LIMIT, RESOURCE_INSTANCE_NOT_FOUND, RESOURCE_INSTANCE_BAD_REQUEST, RESOURCE_INSTANCE_MATCH_NOT_FOUND, RESOURCE_INSTANCE_ALREADY_EXIST, RESOURCE_INSTANCE_RELATION_NOT_FOUND, COMPONENT_MISSING_SUBCATEGORY, COMPONENT_INVALID_SUBCATEGORY, ARTIFACT_TYPE_NOT_SUPPORTED, MISSING_ARTIFACT_TYPE, ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED, ARTIFACT_EXIST, ARTIFACT_NOT_FOUND, ARTIFACT_INVALID_MD5, MISSING_ARTIFACT_NAME, MISSING_PROJECT_CODE, INVALID_PROJECT_CODE, COMPONENT_MISSING_MANDATORY_ARTIFACTS, LIFECYCLE_TYPE_ALREADY_EXIST, SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, MISSING_LIFECYCLE_TYPE, RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID, + INVALID_SERVICE_STATE, COMPONENT_IN_CHECKOUT_STATE, ILLEGAL_COMPONENT_STATE, COMPONENT_IN_CERT_IN_PROGRESS_STATE, COMPONENT_SENT_FOR_CERTIFICATION, COMPONENT_VERSION_ALREADY_EXIST, COMPONENT_ALREADY_CHECKED_IN, COMPONENT_CHECKOUT_BY_ANOTHER_USER, COMPONENT_IN_USE, COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, COMPONENT_HAS_NEWER_VERSION, COMPONENT_ALREADY_CERTIFIED, COMPONENT_NOT_READY_FOR_CERTIFICATION, COMPONENT_ARTIFACT_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND, COMPONENT_INSTANCE_NOT_FOUND_ON_CONTAINER, SERVICE_NOT_FOUND, SERVICE_CATEGORY_CANNOT_BE_CHANGED, SERVICE_NAME_CANNOT_BE_CHANGED, SERVICE_ICON_CANNOT_BE_CHANGED, COMPONENT_TOO_MUCH_CATEGORIES, SERVICE_CANNOT_CONTAIN_SUBCATEGORY, RESOURCE_CATEGORY_CANNOT_BE_CHANGED, RESOURCE_NAME_CANNOT_BE_CHANGED, RESOURCE_ICON_CANNOT_BE_CHANGED, RESOURCE_VENDOR_NAME_CANNOT_BE_CHANGED, RESOURCE_TOO_MUCH_SUBCATEGORIES, SERVICE_ICON_EXCEEDS_LIMIT, RESOURCE_INSTANCE_NOT_FOUND, RESOURCE_INSTANCE_BAD_REQUEST, RESOURCE_INSTANCE_MATCH_NOT_FOUND, RESOURCE_INSTANCE_ALREADY_EXIST, RESOURCE_INSTANCE_RELATION_NOT_FOUND, COMPONENT_MISSING_SUBCATEGORY, COMPONENT_INVALID_SUBCATEGORY, ARTIFACT_TYPE_NOT_SUPPORTED, MISSING_ARTIFACT_TYPE, ARTIFACT_LOGICAL_NAME_CANNOT_BE_CHANGED, ARTIFACT_EXIST, ARTIFACT_NOT_FOUND, ARTIFACT_INVALID_MD5, MISSING_ARTIFACT_NAME, MISSING_PROJECT_CODE, INVALID_PROJECT_CODE, COMPONENT_MISSING_MANDATORY_ARTIFACTS, LIFECYCLE_TYPE_ALREADY_EXIST, SERVICE_NOT_AVAILABLE_FOR_DISTRIBUTION, MISSING_LIFECYCLE_TYPE, RESOURCE_VFCMT_LIFECYCLE_STATE_NOT_VALID, // Distribution BAD_REQUEST_MISSING_RESOURCE, MISSING_USER_ID, MISSING_X_ECOMP_INSTANCE_ID, MISSING_PUBLIC_KEY, MISSING_ENV_NAME, DISTRIBUTION_ENV_DOES_NOT_EXIST, MISSING_BODY, ECOMP_RESEND_WITH_BASIC_AUTHENTICATION_CREDENTIALS, ECOMP_COMPONENT_NOT_AUTHORIZED, METHOD_NOT_ALLOWED_TO_DOWNLOAD_ARTIFACT, REGISTRATION_FAILED, DISTRIBUTION_ENVIRONMENT_NOT_AVAILABLE, DISTRIBUTION_ENVIRONMENT_NOT_FOUND, DISTRIBUTION_ENVIRONMENT_INVALID, DISTRIBUTION_REQUESTED_NOT_FOUND, DISTRIBUTION_REQUESTED_FAILED, DISTRIBUTION_NOT_FOUND, ADDITIONAL_INFORMATION_ALREADY_EXISTS, COMPONENT_VERSION_NOT_FOUND, ADDITIONAL_INFORMATION_MAX_NUMBER_REACHED, ADDITIONAL_INFORMATION_EMPTY_STRING_NOT_ALLOWED, ADDITIONAL_INFORMATION_EXCEEDS_LIMIT, ADDITIONAL_INFORMATION_KEY_NOT_ALLOWED_CHARACTERS, ADDITIONAL_INFORMATION_VALUE_NOT_ALLOWED_CHARACTERS, ADDITIONAL_INFORMATION_NOT_FOUND, ASDC_VERSION_NOT_FOUND, MISSING_DATA, EXCEEDS_LIMIT, UNSUPPORTED_ERROR, ARTIFACT_INVALID_TIMEOUT, SERVICE_IS_VNF_CANNOT_BE_CHANGED, RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, WRONG_ARTIFACT_FILE_EXTENSION, INVALID_YAML, INVALID_XML, INVALID_JSON, INVALID_DEPLOYMENT_ARTIFACT_HEAT, INVALID_HEAT_PARAMETER_TYPE, INVALID_HEAT_PARAMETER_VALUE, DEPLOYMENT_ARTIFACT_OF_TYPE_ALREADY_EXISTS, DEPLOYMENT_ARTIFACT_NAME_ALREADY_EXISTS, MISSING_HEAT, MISMATCH_HEAT_VS_HEAT_ENV, CORRUPTED_FORMAT, MISMATCH_BETWEEN_ARTIFACT_TYPE_AND_COMPONENT_TYPE, INVALID_PARAMS_IN_HEAT_ENV_FILE, API_RESOURCE_NOT_FOUND, //UEB @@ -100,7 +100,7 @@ public enum ActionStatus { //policies RESOURCE_CANNOT_CONTAIN_POLICIES, POLICY_NOT_FOUND_ON_CONTAINER, INVALID_POLICY_NAME, POLICY_NAME_ALREADY_EXIST, EXCLUDED_POLICY_TYPE, POLICY_MISSING_POLICY_TYPE, POLICY_TYPE_IS_INVALID, //External References Statuses - EXT_REF_ALREADY_EXIST, EXT_REF_NOT_FOUND, POLICY_TARGET_DOES_NOT_EXIST, POLICY_TARGET_TYPE_DOES_NOT_EXIST, INPUTS_NOT_FOUND, RESOURCE_LIFECYCLE_STATE_NOT_VALID, COMPONENT_IS_ARCHIVED, + EXT_REF_ALREADY_EXIST, EXT_REF_NOT_FOUND, POLICY_TARGET_DOES_NOT_EXIST, POLICY_TARGET_TYPE_DOES_NOT_EXIST, INPUTS_NOT_FOUND, RESOURCE_LIFECYCLE_STATE_NOT_VALID, COMPONENT_IS_ARCHIVED, COMPONENT_NOT_ARCHIVED, //Automated upgrade COMPONENT_IS_NOT_HIHGEST_CERTIFIED, NO_INSTANCES_TO_UPGRADE, ARCHIVED_ORIGINS_FOUND, UPDATE_CATALOG_FAILED, //Interface diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java index 9e9b944fae..caedbeeb62 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaElementOperation.java @@ -150,6 +150,17 @@ public abstract class ToscaElementOperation extends BaseOperation { return Either.left(vertexG); } + protected GraphVertex getHighestVersionFrom(GraphVertex v) { + Either<GraphVertex, JanusGraphOperationStatus> childVertexE = janusGraphDao + .getChildVertex(v, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); + GraphVertex highestVersionVertex = v; + while (childVertexE.isLeft()) { + highestVersionVertex = childVertexE.left().value(); + childVertexE = janusGraphDao.getChildVertex(highestVersionVertex, EdgeLabelEnum.VERSION, JsonParseFlagEnum.NoParse); + } + return highestVersionVertex; + } + public Either<ToscaElement, StorageOperationStatus> getToscaElement(String uniqueId) { return getToscaElement(uniqueId, new ComponentParametersView()); } diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java index 496fd0fe08..0546a91369 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java @@ -31,6 +31,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Comparator; import java.util.EnumMap; import java.util.HashMap; import java.util.HashSet; @@ -42,6 +43,7 @@ import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.TreeSet; import java.util.function.BiPredicate; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; @@ -79,6 +81,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; 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.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; @@ -114,8 +117,11 @@ import org.openecomp.sdc.be.model.catalog.CatalogComponent; import org.openecomp.sdc.be.model.jsonjanusgraph.config.ContainerInstanceTypesData; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement; +import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.ToscaOperationExceptionSupplier; import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter; import org.openecomp.sdc.be.model.operations.StorageException; +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.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder; @@ -144,6 +150,8 @@ public class ToscaOperationFacade { private static final String COULDNT_FETCH_COMPONENT_WITH_AND_UNIQUE_ID_ERROR = "Couldn't fetch component with and unique id {}, error: {}"; private static final Logger log = Logger.getLogger(ToscaOperationFacade.class.getName()); @Autowired + private IGraphLockOperation graphLockOperation; + @Autowired private NodeTypeOperation nodeTypeOperation; @Autowired private TopologyTemplateOperation topologyTemplateOperation; @@ -992,21 +1000,122 @@ public class ToscaOperationFacade { return Either.left(checkIfInUseAndDelete(allMarked)); } - private List<String> checkIfInUseAndDelete(List<GraphVertex> allMarked) { + public List<String> deleteService(String invariantUUID, final boolean inTransaction) { + List<GraphVertex> allServiceVerticesToDelete = getVerticesForAllVersions(invariantUUID, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE); + List<String> affectedComponentIds = new ArrayList<>(); + try { + checkNotUsed( allServiceVerticesToDelete); + lockAllVerticesByNodeType(allServiceVerticesToDelete, NodeTypeEnum.Service); + for (GraphVertex elementV : allServiceVerticesToDelete) { + Either<ToscaElement, StorageOperationStatus> deleteToscaElement = deleteToscaElement(elementV); + if (deleteToscaElement.isRight()) { + log.debug("Failed to delete element UniqueID {}, Name {}, error {}", elementV.getUniqueId(), + elementV.getMetadataProperties().get(GraphPropertyEnum.NAME), deleteToscaElement.right().value()); + throwStorageException(deleteToscaElement.right().value()); + } + affectedComponentIds.add(elementV.getUniqueId()); + } + if (!inTransaction) { + janusGraphDao.commit(); + } + } catch (Exception exception) { + if (!inTransaction) { + janusGraphDao.rollback(); + } + throw exception; + } finally { + unlockAllVerticesByNodeType(allServiceVerticesToDelete, NodeTypeEnum.Service); + } + return affectedComponentIds; + } + + private void checkNotUsed(List<GraphVertex> vertices) { + boolean isInUse = isAnyComponentInUse(vertices); + if (isInUse) { + Set<GraphVertex> listOfVertices = getComponentsUsingComponents(vertices); + List<String> listOfStringComponents = new ArrayList<>(); + for (GraphVertex componentVertex : listOfVertices) { + listOfStringComponents.add( + componentVertex.getMetadataJson().get(GraphPropertyEnum.COMPONENT_TYPE.getProperty()) + " " + + componentVertex.getMetadataJson().get(GraphPropertyEnum.NAME.getProperty()) + ); + } + String stringOfComponents = String.join(", ", listOfStringComponents); + throw ToscaOperationExceptionSupplier.componentInUse(stringOfComponents).get(); + } + } + + private List<GraphVertex> getVerticesForAllVersions(String invariantUUID, ToscaElementTypeEnum componentType){ + Either<List<Component>, StorageOperationStatus> allComponents = + getComponentListByInvariantUuid(invariantUUID, null); + if (allComponents.isRight()) { + throwStorageException(allComponents.right().value()); + } + List<GraphVertex> allComponentVertices = new ArrayList<>(); + for (Component component : allComponents.left().value()) { + Either<GraphVertex, StorageOperationStatus> componentGraphVertex = topologyTemplateOperation + .getComponentByLabelAndId(component.getUniqueId(), componentType, JsonParseFlagEnum.ParseAll); + if (componentGraphVertex.isRight()) { + throwStorageException(componentGraphVertex.right().value()); + } + allComponentVertices.add(componentGraphVertex.left().value()); + } + return allComponentVertices; + } + + public void commitAndCheck(String componentId) { + JanusGraphOperationStatus status = janusGraphDao.commit(); + if (!status.equals(JanusGraphOperationStatus.OK)) { + log.debug("error occurred when trying to DELETE {}. Return code is: {}", componentId, status); + throwStorageException(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status)); + } + } + + private Set<GraphVertex> getComponentsUsingComponents(List<GraphVertex> componentVertices) { + Set<GraphVertex> inUseBy = new TreeSet<>(Comparator.comparing(GraphVertex::getUniqueId)); + for (final GraphVertex elementV : componentVertices) { + List<GraphVertex> inUseByVertex = isInUse(elementV); + if (!inUseByVertex.isEmpty()) { + inUseBy.addAll(inUseByVertex); + } + } + return inUseBy; + } + + private boolean isAnyComponentInUse(List<GraphVertex> componentVertices) { + boolean isComponentInUse = false; + if (log.isDebugEnabled()) { + for (final GraphVertex graphVertex : componentVertices) { + if (!isInUse(graphVertex).isEmpty()) { + isComponentInUse = true; + } + } + } else { + isComponentInUse = componentVertices.stream().anyMatch(vertex -> !isInUse(vertex).isEmpty()); + } + return isComponentInUse; + } + + private List<GraphVertex> isInUse(GraphVertex elementV) { final List<EdgeLabelEnum> forbiddenEdgeLabelEnums = Arrays - .asList(EdgeLabelEnum.INSTANCE_OF, EdgeLabelEnum.PROXY_OF, EdgeLabelEnum.ALLOTTED_OF); - List<String> deleted = new ArrayList<>(); - for (GraphVertex elementV : allMarked) { - boolean isAllowedToDelete = true; - for (EdgeLabelEnum edgeLabelEnum : forbiddenEdgeLabelEnums) { - Either<Edge, JanusGraphOperationStatus> belongingEdgeByCriteria = janusGraphDao - .getBelongingEdgeByCriteria(elementV, edgeLabelEnum, null); - if (belongingEdgeByCriteria.isLeft()) { - log.debug("Marked element {} in use. don't delete it", elementV.getUniqueId()); - isAllowedToDelete = false; - break; + .asList(EdgeLabelEnum.INSTANCE_OF, EdgeLabelEnum.PROXY_OF, EdgeLabelEnum.ALLOTTED_OF); + for (EdgeLabelEnum edgeLabelEnum : forbiddenEdgeLabelEnums) { + Either<List<GraphVertex>, JanusGraphOperationStatus> inUseBy = + janusGraphDao.getParentVertices(elementV, edgeLabelEnum, JsonParseFlagEnum.ParseAll); + if (inUseBy.isLeft()) { + if (log.isDebugEnabled()) { + log.debug("Element {} in use.", elementV.getUniqueId()); } + return inUseBy.left().value(); } + } + return Collections.emptyList(); + } + + private List<String> checkIfInUseAndDelete(List<GraphVertex> allMarked) { + List<String> deleted = new ArrayList<>(); + for (GraphVertex elementV : allMarked) { + boolean isAllowedToDelete = !isInUse(elementV).isEmpty(); if (isAllowedToDelete) { Either<ToscaElement, StorageOperationStatus> deleteToscaElement = deleteToscaElement(elementV); if (deleteToscaElement.isRight()) { @@ -1020,6 +1129,21 @@ public class ToscaOperationFacade { return deleted; } + private void lockAllVerticesByNodeType(List<GraphVertex> allVerticesToLock, NodeTypeEnum nodeType) { + for (GraphVertex graphVertex : allVerticesToLock) { + StorageOperationStatus storageOperationStatus = graphLockOperation.lockComponent(graphVertex.getUniqueId(), nodeType); + if (!storageOperationStatus.equals(StorageOperationStatus.OK)) { + throwStorageException(storageOperationStatus); + } + } + } + + private void unlockAllVerticesByNodeType(List<GraphVertex> allVerticesToUnlock, NodeTypeEnum nodeType) { + for (GraphVertex graphVertex : allVerticesToUnlock) { + graphLockOperation.unlockComponent(graphVertex.getUniqueId(), nodeType); + } + } + public Either<List<String>, StorageOperationStatus> getAllComponentsMarkedForDeletion(ComponentTypeEnum componentType) { Either<List<GraphVertex>, StorageOperationStatus> allComponentsMarkedForDeletion; switch (componentType) { diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java new file mode 100644 index 0000000000..62d7e29b48 --- /dev/null +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/exception/ToscaOperationExceptionSupplier.java @@ -0,0 +1,37 @@ +/* + * ============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.jsonjanusgraph.operations.exception; + +import java.util.function.Supplier; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; + +public class ToscaOperationExceptionSupplier { + + private ToscaOperationExceptionSupplier() { + + } + + public static Supplier<OperationException> componentInUse(final String stringOfServices) { + return () -> new OperationException(ActionStatus.COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, stringOfServices); + } + +} diff --git a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java index 4fbb5fbef3..491603081f 100644 --- a/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java +++ b/catalog-model/src/main/java/org/openecomp/sdc/be/model/operations/api/StorageOperationStatus.java @@ -64,6 +64,8 @@ public enum StorageOperationStatus { PROPERTY_NAME_ALREADY_EXISTS, INVALID_PROPERTY, COMPONENT_IS_ARCHIVED, + COMPONENT_NOT_ARCHIVED, + COMPONENT_IN_USE_BY_ANOTHER_COMPONENT, DECLARED_INPUT_USED_BY_OPERATION; // @formatter:on diff --git a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java index c0c417a324..625ec39837 100644 --- a/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java +++ b/catalog-model/src/test/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacadeTest.java @@ -36,6 +36,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyMap; @@ -70,6 +71,8 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.mockito.junit.MockitoJUnitRunner; +import org.openecomp.sdc.be.config.ComponentType; +import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus; import org.openecomp.sdc.be.dao.jsongraph.GraphVertex; import org.openecomp.sdc.be.dao.janusgraph.HealingJanusGraphDao; @@ -84,6 +87,7 @@ import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; 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.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum; import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; @@ -106,7 +110,10 @@ import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.NodeType; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.TopologyTemplate; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement; import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElementTypeEnum; +import org.openecomp.sdc.be.model.jsonjanusgraph.operations.exception.OperationException; import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter; +import org.openecomp.sdc.be.model.operations.StorageException; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; @RunWith(MockitoJUnitRunner.class) @@ -137,6 +144,9 @@ public class ToscaOperationFacadeTest { @Mock private NodeTemplateOperation nodeTemplateOperationMock; + @Mock + private IGraphLockOperation graphLockOperationMock; + @Before public void setUp() throws Exception { testInstance = new ToscaOperationFacade(); @@ -408,6 +418,153 @@ public class ToscaOperationFacadeTest { } @Test + public void testDeleteService_ServiceInUse() { + String invariantUUID = "12345"; + String serviceUid = "1"; + GraphVertex service1 = getTopologyTemplateVertex(); + service1.setUniqueId(serviceUid); + List<GraphVertex> allResourcesToDelete = new ArrayList<>(); + allResourcesToDelete.add(service1); + Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID); + ToscaElement toscaElement = getToscaElementForTest(); + toscaElement.setUniqueId(serviceUid); + String service2Name = "service2Name"; + Map<String, Object> service2MetadataJson = new HashMap<>(); + service2MetadataJson.put(GraphPropertyEnum.COMPONENT_TYPE.getProperty(), ComponentType.SERVICE); + service2MetadataJson.put(GraphPropertyEnum.NAME.getProperty(), service2Name); + String service2Uid = "2"; + GraphVertex usingService = getTopologyTemplateVertex(); + usingService.setUniqueId(service2Uid); + usingService.setMetadataJson(service2MetadataJson); + List<GraphVertex> inUseBy = new ArrayList<>(); + inUseBy.add(usingService); + + when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)). + thenReturn(Either.left(allResourcesToDelete)); + doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service1), any(ComponentParametersView.class)); + when(topologyTemplateOperationMock. + getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)). + thenReturn(Either.left(service1)); + when(janusGraphDaoMock.getParentVertices(any(GraphVertex.class), any(), eq(JsonParseFlagEnum.ParseAll))). + thenReturn(Either.left(inUseBy)).thenReturn(Either.left(inUseBy)); + final OperationException actualException = assertThrows(OperationException.class, () -> testInstance.deleteService(invariantUUID, true)); + assertEquals(actualException.getActionStatus(), ActionStatus.COMPONENT_IN_USE_BY_ANOTHER_COMPONENT); + assertEquals(actualException.getParams()[0], ComponentType.SERVICE + " " + service2Name); + } + + @Test + public void testDeleteService_WithOneVersion() { + String invariantUUID = "12345"; + String serviceUid = "1"; + Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID); + GraphVertex service1 = getTopologyTemplateVertex(); + service1.setUniqueId(serviceUid); + List<GraphVertex> allResourcesToDelete = new ArrayList<>(); + allResourcesToDelete.add(service1); + ToscaElement toscaElement = getToscaElementForTest(); + toscaElement.setUniqueId(serviceUid); + List<String> affectedComponentIds = new ArrayList<>(); + affectedComponentIds.add(service1.getUniqueId()); + + when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)). + thenReturn(Either.left(allResourcesToDelete)); + doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service1), any(ComponentParametersView.class)); + when(topologyTemplateOperationMock. + getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)). + thenReturn(Either.left(service1)); + when(janusGraphDaoMock.getParentVertices(eq(service1), any(), eq(JsonParseFlagEnum.ParseAll))). + thenReturn(Either.right(JanusGraphOperationStatus.OK)); + when(graphLockOperationMock.lockComponent(service1.getUniqueId(), NodeTypeEnum.Service)). + thenReturn(StorageOperationStatus.OK); + when(topologyTemplateOperationMock.deleteToscaElement(service1)).thenReturn(Either.left(toscaElement)); + assertEquals(affectedComponentIds, testInstance.deleteService(invariantUUID, true)); + } + + @Test + public void testDeleteService_WithTwoVersions() { + String invariantUUID = "12345"; + String serviceUid = "1"; + String service2Uid = "2"; + GraphVertex service = getTopologyTemplateVertex(); + service.setUniqueId(serviceUid); + GraphVertex serviceV2 = getTopologyTemplateVertex(); + serviceV2.setUniqueId(service2Uid); + ToscaElement toscaElement = getToscaElementForTest(); + toscaElement.setUniqueId(serviceUid); + ToscaElement toscaElement2 = getToscaElementForTest(); + toscaElement2.setUniqueId(service2Uid); + List<String> affectedComponentIds = new ArrayList<>(); + affectedComponentIds.add(service.getUniqueId()); + affectedComponentIds.add(serviceV2.getUniqueId()); + List<GraphVertex> allResourcesToDelete = new ArrayList<>(); + allResourcesToDelete.add(service); + allResourcesToDelete.add(serviceV2); + Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID); + + when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)). + thenReturn(Either.left(allResourcesToDelete)); + doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock). + getToscaElement(eq(service), any(ComponentParametersView.class)); + doReturn(Either.left(toscaElement2)).when(topologyTemplateOperationMock). + getToscaElement(eq(serviceV2), any(ComponentParametersView.class)); + when(topologyTemplateOperationMock. + getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)). + thenReturn(Either.left(service)); + when(topologyTemplateOperationMock. + getComponentByLabelAndId(service2Uid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)). + thenReturn(Either.left(serviceV2)); + when(janusGraphDaoMock.getParentVertices(any(GraphVertex.class), any(), eq(JsonParseFlagEnum.ParseAll))). + thenReturn(Either.right(JanusGraphOperationStatus.OK)); + when(graphLockOperationMock.lockComponent(service.getUniqueId(), NodeTypeEnum.Service)). + thenReturn(StorageOperationStatus.OK); + when(graphLockOperationMock.lockComponent(serviceV2.getUniqueId(), NodeTypeEnum.Service)). + thenReturn(StorageOperationStatus.OK); + when(topologyTemplateOperationMock.deleteToscaElement(service)).thenReturn(Either.left(toscaElement)); + when(topologyTemplateOperationMock.deleteToscaElement(serviceV2)).thenReturn(Either.left(toscaElement)); + assertEquals(affectedComponentIds, testInstance.deleteService(invariantUUID, true)); + } + + @Test + public void testDeleteService_FailDelete() { + String invariantUUID = "12345"; + String serviceUid = "1"; + GraphVertex service = getTopologyTemplateVertex(); + service.setUniqueId(serviceUid); + ToscaElement toscaElement = getToscaElementForTest(); + toscaElement.setUniqueId(serviceUid); + List<GraphVertex> allResourcesToDelete = new ArrayList<>(); + allResourcesToDelete.add(service); + Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID); + + when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)). + thenReturn(Either.left(allResourcesToDelete)); + doReturn(Either.left(toscaElement)).when(topologyTemplateOperationMock).getToscaElement(eq(service), any(ComponentParametersView.class)); + when(topologyTemplateOperationMock.getComponentByLabelAndId(serviceUid, ToscaElementTypeEnum.TOPOLOGY_TEMPLATE, JsonParseFlagEnum.ParseAll)). + thenReturn(Either.left(service)); + when(janusGraphDaoMock.getParentVertices(eq(service), any(), eq(JsonParseFlagEnum.ParseAll))). + thenReturn(Either.right(JanusGraphOperationStatus.OK)); + when(graphLockOperationMock.lockComponent(service.getUniqueId(), NodeTypeEnum.Service)). + thenReturn(StorageOperationStatus.OK); + when(topologyTemplateOperationMock.deleteToscaElement(service)) + .thenReturn(Either.right(StorageOperationStatus.NOT_FOUND)); + assertThrows(StorageException.class, () -> testInstance.deleteService(invariantUUID, true)); + } + + @Test + public void testDeleteService_NotFound() { + String invariantUUID = "12345"; + Map<GraphPropertyEnum, Object> propertiesToMatch = new EnumMap<>(GraphPropertyEnum.class); + propertiesToMatch.put(GraphPropertyEnum.INVARIANT_UUID, invariantUUID); + when(janusGraphDaoMock.getByCriteria(null, propertiesToMatch, JsonParseFlagEnum.ParseMetadata)). + thenReturn(Either.right(JanusGraphOperationStatus.NOT_FOUND)); + assertThrows(StorageException.class, () -> testInstance.deleteService(invariantUUID, true)); + } + + @Test public void testMarkComponentToDelete() { StorageOperationStatus result; Component component = new Resource(); |