diff options
Diffstat (limited to 'catalog-be')
4 files changed, 261 insertions, 1 deletions
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<ComponentInstance> createComponentInstanceInterfaceOperation(String componentId, String componentInstanceId, + InterfaceDefinition interfaceDefinition, + ComponentTypeEnum componentTypeEnum, + Wrapper<ResponseFormat> errorWrapper, final boolean shouldLock) + throws BusinessLogicException { + ResponseFormat responseFormat; + final Component component = getComponent(componentId); + final Optional<ComponentInstance> 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<String, List<ComponentInstanceInterface>> 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<OperationDataDefinition> 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<ComponentInstanceInterface> componentInstanceInterfaceList = componentInstancesInterfaceMap.get(componentInstanceId); + componentInstanceInterfaceList = CollectionUtils.isEmpty(componentInstanceInterfaceList) ? new ArrayList<>() : componentInstanceInterfaceList; + Optional<ComponentInstanceInterface> 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<Component> createInterfaceOperationInResource(final String componentId, final InterfaceDefinition interfaceDefinition, final ComponentTypeEnum componentTypeEnum, final Wrapper<ResponseFormat> 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 @@ -206,6 +208,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<InterfaceDefinition> mappedInterfaceOperationData = getMappedInterfaceData(data, userModifier, componentTypeEnum); + if (mappedInterfaceOperationData.isEmpty()) { + LOGGER.error(INTERFACE_OPERATION_CONTENT_INVALID, data); + return buildErrorResponse(getComponentsUtils().getResponseFormat(ActionStatus.INVALID_CONTENT)); + } + final Wrapper<ResponseFormat> errorWrapper = new Wrapper<>(); + try { + final Optional<ComponentInstance> 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) @Produces(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<String, OperationDataDefinition> 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<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) 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<ComponentInstance> 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<String, OperationDataDefinition> 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<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) 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<ComponentInstance> 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<ComponentInstance> 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<String, List<ComponentInstanceInterface>> componentInstancesInterfacesMap = new HashMap<>(); + componentInstancesInterfacesMap.put(componentInstanceId, new ArrayList<>()); + componentInstance.setInterfaces( + (Map<String, Object>) 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<ComponentInstance> result = componentInterfaceOperationBusinessLogic + .createComponentInstanceInterfaceOperation(componentId, componentInstanceId, interfaceDefinition, + ComponentTypeEnum.SERVICE, new Wrapper<>(), true); + assertThat(result).isEmpty(); + } + private void initComponentData() { try { component = new Service(); |