From ceaf83e0f29c10e4521321abcd6dd17080d2db60 Mon Sep 17 00:00:00 2001 From: JvD_Ericsson Date: Mon, 11 Sep 2023 10:56:37 +0100 Subject: Support setting interfaces on instances Issue-ID: SDC-4620 Signed-off-by: JvD_Ericsson Change-Id: I4f78eb5e017e79120d61870ecc3b7268f83b4206 --- .../ComponentInterfaceOperationBusinessLogic.java | 79 ++++++++++++++ .../components/utils/InterfaceOperationUtils.java | 2 + .../ComponentInterfaceOperationServlet.java | 60 +++++++++- ...mponentInterfaceOperationBusinessLogicTest.java | 121 +++++++++++++++++++++ 4 files changed, 261 insertions(+), 1 deletion(-) (limited to 'catalog-be') diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java index 3ac8ce3562..a10bae9c1e 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java @@ -37,6 +37,7 @@ import java.util.Optional; import java.util.UUID; import java.util.stream.Collectors; import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.collections.ListUtils; import org.apache.commons.collections.MapUtils; import org.openecomp.sdc.be.components.impl.exceptions.BusinessLogicException; import org.openecomp.sdc.be.components.validation.ComponentValidations; @@ -306,6 +307,84 @@ public class ComponentInterfaceOperationBusinessLogic extends BaseBusinessLogic return Optional.of(component); } + public Optional createComponentInstanceInterfaceOperation(String componentId, String componentInstanceId, + InterfaceDefinition interfaceDefinition, + ComponentTypeEnum componentTypeEnum, + Wrapper errorWrapper, final boolean shouldLock) + throws BusinessLogicException { + ResponseFormat responseFormat; + final Component component = getComponent(componentId); + final Optional componentInstanceOptional = componentValidations.getComponentInstance(component, componentInstanceId); + if (componentInstanceOptional.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_INSTANCE_NOT_FOUND); + LOGGER.debug("Failed to find component instance with id {}, error: {}", componentInstanceId, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + Map> componentInstancesInterfaceMap = component.getComponentInstancesInterfaces(); + if (MapUtils.isEmpty(componentInstancesInterfaceMap)) { + componentInstancesInterfaceMap = new HashMap<>(); + component.setComponentInstancesInterfaces(componentInstancesInterfaceMap); + } + final String interfaceKey = interfaceDefinition.getType(); + interfaceDefinition.setUniqueId(interfaceKey); + interfaceDefinition.setToscaResourceName(interfaceKey); + interfaceDefinition.setUserCreated(true); + + final Optional optionalOperationDataDefinition = interfaceDefinition.getOperations().values().stream().findFirst(); + if (optionalOperationDataDefinition.isEmpty()) { + responseFormat = componentsUtils.getResponseFormat(ActionStatus.INTERFACE_OPERATION_NOT_FOUND, interfaceKey); + LOGGER.debug("Failed to find interface operation on interface being added {}, error: {}", interfaceKey, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + + final OperationDataDefinition updatedOperationDataDefinition = optionalOperationDataDefinition.get(); + updatedOperationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + updatedOperationDataDefinition.getImplementation() + .setArtifactName(generateArtifactName(updatedOperationDataDefinition.getImplementation().getArtifactName())); + + List componentInstanceInterfaceList = componentInstancesInterfaceMap.get(componentInstanceId); + componentInstanceInterfaceList = CollectionUtils.isEmpty(componentInstanceInterfaceList) ? new ArrayList<>() : componentInstanceInterfaceList; + Optional componentInstanceInterface = + componentInstanceInterfaceList.stream().filter(instInterface -> instInterface.getInterfaceId().equals(interfaceKey)).findFirst(); + + if (componentInstanceInterface.isEmpty()) { + componentInstanceInterfaceList.add(new ComponentInstanceInterface(interfaceKey, interfaceDefinition)); + componentInstanceOptional.get().addInterface(interfaceKey, interfaceDefinition); + } else { + componentInstanceInterface.get().getOperations().put(updatedOperationDataDefinition.getName(), updatedOperationDataDefinition); + } + + boolean wasLocked = false; + try { + if (shouldLock) { + lockComponent(componentId, component, UPDATE_INTERFACE_OPERATION_ON_COMPONENT_INSTANCE); + wasLocked = true; + } + StorageOperationStatus status = toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId); + if (status != StorageOperationStatus.OK) { + janusGraphDao.rollback(); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + LOGGER.error(EXCEPTION_OCCURRED_WHEN_UPDATING_COMPONENT_INSTANCE_INTERFACES, responseFormat); + errorWrapper.setInnerElement(responseFormat); + return Optional.empty(); + } + janusGraphDao.commit(); + } catch (final Exception e) { + janusGraphDao.rollback(); + LOGGER.error("Exception occurred when updating Interface Operation on Component Instance: {}", e.getMessage(), e); + responseFormat = componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR); + errorWrapper.setInnerElement(responseFormat); + throw new BusinessLogicException(responseFormat); + } finally { + if (wasLocked) { + unlockComponent(component.getUniqueId(), componentTypeEnum); + } + } + return componentInstanceOptional; + } + public Optional createInterfaceOperationInResource(final String componentId, final InterfaceDefinition interfaceDefinition, final ComponentTypeEnum componentTypeEnum, final Wrapper errorWrapper, final boolean shouldLock) diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java index edbad79e14..ae94d9803d 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java @@ -13,6 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + package org.openecomp.sdc.be.components.utils; import java.util.ArrayList; @@ -31,6 +32,7 @@ import org.openecomp.sdc.be.datatypes.elements.OperationDataDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition; import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; import org.openecomp.sdc.be.model.InputDefinition; import org.openecomp.sdc.be.model.InterfaceDefinition; import org.openecomp.sdc.be.model.Operation; diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java index fbb7d0b0ac..1e68b0f431 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java @@ -18,6 +18,7 @@ * SPDX-License-Identifier: Apache-2.0 * ============LICENSE_END========================================================= */ + package org.openecomp.sdc.be.servlets; import static org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum.RESOURCE; @@ -87,7 +88,8 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl private static final String FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR = "Failed to update Interface Operation with an error"; private static final String INTERFACE_OPERATION_CONTENT_INVALID = "Interface Operation content is invalid - {}"; private static final String UNSUPPORTED_COMPONENT_TYPE = "Unsupported component type {}"; - private static final String INTERFACE_OPERATION_SUCCESSFULLY_UPDATED = "Interface Operation successfully updated on component instance with id {}"; + private static final String INTERFACE_OPERATION_SUCCESSFULLY_UPDATED = + "Interface Operation successfully updated on component instance with id {}"; private final ComponentInterfaceOperationBusinessLogic componentInterfaceOperationBusinessLogic; @Autowired @@ -205,6 +207,62 @@ public class ComponentInterfaceOperationServlet extends AbstractValidationsServl } } + @POST + @Path("/{componentType}/{componentId}/componentInstance/{componentInstanceId}/interfaceOperation") + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_JSON) + @Operation(description = "Create Interface Operation", method = "POST", summary = "Create Interface Operation on ComponentInstance", responses = { + @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = Response.class)))), + @ApiResponse(responseCode = "201", description = "Create Interface Operation"), + @ApiResponse(responseCode = "403", description = "Restricted operation"), + @ApiResponse(responseCode = "400", description = "Invalid content / Missing content")}) + @PermissionAllowed(AafPermission.PermNames.INTERNAL_ALL_VALUE) + public Response createComponentInstanceInterfaceOperation( + @Parameter(description = "valid values: resources / services", schema = @Schema(allowableValues = {ComponentTypeEnum.RESOURCE_PARAM_NAME, + ComponentTypeEnum.SERVICE_PARAM_NAME})) @PathParam("componentType") String componentType, + @Parameter(description = "Component Id") @PathParam("componentId") String componentId, + @Parameter(description = "Component Instance Id") @PathParam("componentInstanceId") String componentInstanceId, + @Context final HttpServletRequest request, @HeaderParam(value = Constants.USER_ID_HEADER) String userId) throws IOException { + LOGGER.debug(START_HANDLE_REQUEST_OF, request.getMethod(), request.getRequestURI()); + userId = ValidationUtils.sanitizeInputString(userId); + componentType = ValidationUtils.sanitizeInputString(componentType); + componentInstanceId = ValidationUtils.sanitizeInputString(componentInstanceId); + LOGGER.debug(MODIFIER_ID_IS, userId); + final User userModifier = componentInterfaceOperationBusinessLogic.validateUser(userId); + final ComponentTypeEnum componentTypeEnum = ComponentTypeEnum.findByParamName(componentType); + if (componentTypeEnum == null) { + LOGGER.debug(UNSUPPORTED_COMPONENT_TYPE, componentType); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.UNSUPPORTED_ERROR, componentType)); + } + final byte[] bytes = IOUtils.toByteArray(request.getInputStream()); + if (bytes == null || bytes.length == 0) { + LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, "content is empty"); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + final String data = new String(bytes); + final Optional mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentTypeEnum); + if (mappedInterfaceOperationData.isEmpty()) { + LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, data); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + final Wrapper errorWrapper = new Wrapper<>(); + try { + final Optional actionResponse = componentInterfaceOperationBusinessLogic.createComponentInstanceInterfaceOperation( + componentId, componentInstanceId, mappedInterfaceOperationData.get(), componentTypeEnum, errorWrapper, true); + if (actionResponse.isEmpty()) { + LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION, componentInstanceId); + return buildErrorResponse(errorWrapper.getInnerElement()); + } else { + LOGGER.debug(INTERFACE_OPERATION_SUCCESSFULLY_UPDATED, componentInstanceId); + return buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.CREATED), actionResponse.get()); + } + } catch (final Exception e) { + BeEcompErrorManager.getInstance().logBeRestApiGeneralError(UPDATE_INTERFACE_OPERATION); + LOGGER.error(FAILED_TO_UPDATE_INTERFACE_OPERATION_WITH_ERROR, e); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR)); + } + } + @POST @Path("/{componentType}/{componentId}/resource/interfaceOperation") @Consumes(MediaType.APPLICATION_JSON) diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java index b3f6024a9b..1dd7f40730 100644 --- a/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import fj.data.Either; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -418,6 +419,126 @@ class ComponentInterfaceOperationBusinessLogicTest extends BaseBusinessLogicMock assertThat(result).isPresent(); } + @Test + void createComponentInstanceInterfaceOperationTest() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(graphLockOperation.lockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.OK); + when(janusGraphDao.commit()).thenReturn(JanusGraphOperationStatus.OK); + when(graphLockOperation.unlockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + + final Optional result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isPresent(); + } + + @Test + void createComponentInstanceInterfaceOperationTestUpdateFail() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + final Map operations = new HashMap<>(); + final OperationDataDefinition operationDataDefinition = new OperationDataDefinition(); + operationDataDefinition.setUniqueId(UUID.randomUUID().toString()); + final ArtifactDataDefinition artifactDataDefinition = new ArtifactDataDefinition(); + artifactDataDefinition.setArtifactName("EO Implementation info"); + operationDataDefinition.setImplementation(artifactDataDefinition); + operations.put("configure", operationDataDefinition); + interfaceDefinition.setOperations(operations ); + + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + when(graphLockOperation.lockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + when(toscaOperationFacade.updateComponentInstanceInterfaces(component, componentInstanceId)) + .thenReturn(StorageOperationStatus.GENERAL_ERROR); + when(janusGraphDao.rollback()).thenReturn(JanusGraphOperationStatus.OK); + when(graphLockOperation.unlockComponent(componentId, NodeTypeEnum.Service)) + .thenReturn(StorageOperationStatus.OK); + + final Optional result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + + @Test + void createComponentInstanceInterfaceOperationTestNoInstances() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + + final Optional result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + + @Test + void createComponentInstanceInterfaceOperationTestNoOperations() throws BusinessLogicException { + final String componentId = component.getUniqueId(); + final String componentInstanceId = componentInstance.getUniqueId(); + final InterfaceDefinition interfaceDefinition = new InterfaceDefinition(); + interfaceDefinition.setUniqueId(UUID.randomUUID().toString()); + interfaceDefinition.setType("tosca.interfaces.node.lifecycle.Standard"); + + Map> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map) new HashMap<>().put(componentInstanceId, interfaceDefinition)); + component.setComponentInstances(Collections.singletonList(componentInstance)); + + when(toscaOperationFacade.getToscaElement(componentId)).thenReturn(Either.left(component)); + when(componentValidations.getComponentInstance(component, componentInstanceId)) + .thenReturn(Optional.of(componentInstance)); + + final Optional result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + private void initComponentData() { try { component = new Service(); -- cgit