Support setting interfaces on instances 52/135952/6
authorJvD_Ericsson <jeff.van.dam@est.tech>
Mon, 11 Sep 2023 09:56:37 +0000 (10:56 +0100)
committerMichael Morris <michael.morris@est.tech>
Mon, 25 Sep 2023 08:50:01 +0000 (08:50 +0000)
Issue-ID: SDC-4620
Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech>
Change-Id: I4f78eb5e017e79120d61870ecc3b7268f83b4206

catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogic.java
catalog-be/src/main/java/org/openecomp/sdc/be/components/utils/InterfaceOperationUtils.java
catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentInterfaceOperationServlet.java
catalog-be/src/test/java/org/openecomp/sdc/be/components/impl/ComponentInterfaceOperationBusinessLogicTest.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/NodeTemplateOperation.java
catalog-model/src/main/java/org/openecomp/sdc/be/model/jsonjanusgraph/operations/ToscaOperationFacade.java
catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
catalog-ui/src/app/ng2/services/component-services/topology-template.service.ts

index 3ac8ce3..a10bae9 100644 (file)
@@ -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)
index edbad79..ae94d98 100644 (file)
@@ -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;
index fbb7d0b..1e68b0f 100644 (file)
@@ -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<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)
index b3f6024..1dd7f40 100644 (file)
@@ -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();
index f75c7a6..0b29675 100644 (file)
@@ -17,6 +17,7 @@
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
+
 package org.openecomp.sdc.be.model.jsonjanusgraph.operations;
 
 import fj.data.Either;
@@ -134,7 +135,8 @@ public class NodeTemplateOperation extends BaseOperation {
     static final String HEAT_VF_ENV_NAME = "VfHeatEnv";
     static final String HEAT_ENV_SUFFIX = "env";
     private static final String FAILED_TO_FETCH_CONTAINER_VERTEX_ERROR = "Failed to fetch container vertex {} error {}";
-    private static final String FAILED_TO_UPDATE_TOPOLOGY_TEMPLATE_WITH_NEW_COMPONENT_INSTANCE = "Failed to update topology template {} with new component instance {}. ";
+    private static final String FAILED_TO_UPDATE_TOPOLOGY_TEMPLATE_WITH_NEW_COMPONENT_INSTANCE =
+        "Failed to update topology template {} with new component instance {}. ";
     private static final String ARTIFACT_PLACEHOLDER_TYPE = "type";
     private static final String ARTIFACT_PLACEHOLDER_DISPLAY_NAME = "displayName";
     private static final Object ARTIFACT_PLACEHOLDER_DESCRIPTION = "description";
@@ -669,31 +671,35 @@ public class NodeTemplateOperation extends BaseOperation {
         if (composition != null) {
             Map<String, RelationshipInstDataDefinition> relations = composition.getRelations();
             if (MapUtils.isNotEmpty(relations)) {
-                Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability(
-                    containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+                Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult =
+                    fetchContainerCalculatedCapability(
+                        containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
                 if (capResult.isRight()) {
                     return capResult.right().value();
 
                 }
                 Map<String, MapListCapabilityDataDefinition> calculatedCapabilty = capResult.left().value().getRight();
 
-                Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability(
-                    containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
+                Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult =
+                    fetchContainerCalculatedCapability(
+                        containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
                 if (capFullResult.isRight()) {
                     return capFullResult.right().value();
 
                 }
                 Map<String, MapListCapabilityDataDefinition> fullFilledCapabilty = capFullResult.left().value().getRight();
 
-                Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement(
-                    containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
+                Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult =
+                    fetchContainerCalculatedRequirement(
+                        containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
                 if (reqResult.isRight()) {
                     return reqResult.right().value();
                 }
                 Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight();
 
-                Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement(
-                    containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
+                Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult =
+                    fetchContainerCalculatedRequirement(
+                        containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
                 if (reqResult.isRight()) {
                     return reqResult.right().value();
                 }
@@ -1588,26 +1594,30 @@ public class NodeTemplateOperation extends BaseOperation {
             return Either.right(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(error));
         }
         GraphVertex containerV = containerVEither.left().value();
-        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability(
-            containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult =
+            fetchContainerCalculatedCapability(
+                containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
         if (capResult.isRight()) {
             return Either.right(capResult.right().value());
         }
         Map<String, MapListCapabilityDataDefinition> calculatedCapabilty = capResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability(
-            containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
+        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult =
+            fetchContainerCalculatedCapability(
+                containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
         if (capResult.isRight()) {
             return Either.right(capResult.right().value());
         }
         Map<String, MapListCapabilityDataDefinition> fullFilledCapabilty = capFullResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement(
-            containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
+        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult =
+            fetchContainerCalculatedRequirement(
+                containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
         if (reqResult.isRight()) {
             return Either.right(reqResult.right().value());
         }
         Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement(
-            containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
+        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult =
+            fetchContainerCalculatedRequirement(
+                containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
         if (reqResult.isRight()) {
             return Either.right(reqResult.right().value());
         }
@@ -1823,26 +1833,30 @@ public class NodeTemplateOperation extends BaseOperation {
         }
         Map<String, RelationshipInstDataDefinition> relations = compositionDataDefinition.getRelations();
         List<CapabilityRequirementRelationship> relationPairList = requirementDef.getRelationships();
-        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult = fetchContainerCalculatedCapability(
-            containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
+        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capResult =
+            fetchContainerCalculatedCapability(
+                containerV, EdgeLabelEnum.CALCULATED_CAPABILITIES);
         if (capResult.isRight()) {
             return Either.right(capResult.right().value());
         }
         Map<String, MapListCapabilityDataDefinition> calculatedCapability = capResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult = fetchContainerCalculatedCapability(
-            containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
+        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> capFullResult =
+            fetchContainerCalculatedCapability(
+                containerV, EdgeLabelEnum.FULLFILLED_CAPABILITIES);
         if (capResult.isRight()) {
             return Either.right(capResult.right().value());
         }
         Map<String, MapListCapabilityDataDefinition> fulfilledCapability = capFullResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult = fetchContainerCalculatedRequirement(
-            containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
+        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqResult =
+            fetchContainerCalculatedRequirement(
+                containerV, EdgeLabelEnum.CALCULATED_REQUIREMENTS);
         if (reqResult.isRight()) {
             return Either.right(reqResult.right().value());
         }
         Map<String, MapListRequirementDataDefinition> calculatedRequirement = reqResult.left().value().getRight();
-        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult = fetchContainerCalculatedRequirement(
-            containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
+        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> reqFullResult =
+            fetchContainerCalculatedRequirement(
+                containerV, EdgeLabelEnum.FULLFILLED_REQUIREMENTS);
         if (reqResult.isRight()) {
             return Either.right(reqResult.right().value());
         }
@@ -2237,8 +2251,9 @@ public class NodeTemplateOperation extends BaseOperation {
 
     private Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, StorageOperationStatus> fetchContainerCalculatedCapability(
         GraphVertex containerV, EdgeLabelEnum capLabel) {
-        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, JanusGraphOperationStatus> calculatedCapabiltyEither = getDataAndVertexFromGraph(
-            containerV, capLabel);
+        Either<Pair<GraphVertex, Map<String, MapListCapabilityDataDefinition>>, JanusGraphOperationStatus> calculatedCapabiltyEither =
+            getDataAndVertexFromGraph(
+                containerV, capLabel);
         if (calculatedCapabiltyEither.isRight()) {
             JanusGraphOperationStatus error = calculatedCapabiltyEither.right().value();
             CommonUtility
@@ -2251,8 +2266,9 @@ public class NodeTemplateOperation extends BaseOperation {
 
     private Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, StorageOperationStatus> fetchContainerCalculatedRequirement(
         GraphVertex containerV, EdgeLabelEnum reqLabel) {
-        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, JanusGraphOperationStatus> calculatedRequirementEither = getDataAndVertexFromGraph(
-            containerV, reqLabel);
+        Either<Pair<GraphVertex, Map<String, MapListRequirementDataDefinition>>, JanusGraphOperationStatus> calculatedRequirementEither =
+            getDataAndVertexFromGraph(
+                containerV, reqLabel);
         if (calculatedRequirementEither.isRight()) {
             JanusGraphOperationStatus error = calculatedRequirementEither.right().value();
             CommonUtility
index 951dc5a..b6339e8 100644 (file)
  * limitations under the License.
  * ============LICENSE_END=========================================================
  */
+
 package org.openecomp.sdc.be.model.jsonjanusgraph.operations;
 
+import static java.util.Objects.requireNonNull;
+import static org.apache.commons.collections.CollectionUtils.isEmpty;
+import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
+import static org.janusgraph.core.attribute.Text.REGEX;
+import static org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum.TOPOLOGY_TEMPLATE;
+
 import com.vdurmont.semver4j.Semver;
 import com.vdurmont.semver4j.Semver.SemverType;
 import fj.data.Either;
+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;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+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.regex.Matcher;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
 import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.collections.MapUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -113,32 +139,6 @@ import org.openecomp.sdc.common.log.wrappers.Logger;
 import org.openecomp.sdc.common.util.ValidationUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
-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;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-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 static java.util.Objects.requireNonNull;
-import static org.apache.commons.collections.CollectionUtils.isEmpty;
-import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
-import static org.janusgraph.core.attribute.Text.REGEX;
-import static org.openecomp.sdc.be.dao.jsongraph.types.VertexTypeEnum.TOPOLOGY_TEMPLATE;
-
 @org.springframework.stereotype.Component("tosca-operation-facade")
 public class ToscaOperationFacade {
 
@@ -146,9 +146,11 @@ public class ToscaOperationFacade {
     public static final String PROXY_SUFFIX = "_proxy";
     // region - Fields
     private static final String COULDNT_FETCH_A_COMPONENT_WITH_AND_UNIQUE_ID_ERROR = "Couldn't fetch a component with and UniqueId {}, error: {}";
-    private static final String FAILED_TO_FIND_RECENTLY_ADDED_PROPERTY_ON_THE_RESOURCE_STATUS_IS = "Failed to find recently added property {} on the resource {}. Status is {}. ";
+    private static final String FAILED_TO_FIND_RECENTLY_ADDED_PROPERTY_ON_THE_RESOURCE_STATUS_IS =
+        "Failed to find recently added property {} on the resource {}. Status is {}. ";
     private static final String FAILED_TO_GET_UPDATED_RESOURCE_STATUS_IS = "Failed to get updated resource {}. Status is {}. ";
-    private static final String FAILED_TO_ADD_THE_PROPERTY_TO_THE_RESOURCE_STATUS_IS = "Failed to add the property {} to the resource {}. Status is {}. ";
+    private static final String FAILED_TO_ADD_THE_PROPERTY_TO_THE_RESOURCE_STATUS_IS =
+        "Failed to add the property {} to the resource {}. Status is {}. ";
     private static final String SERVICE = "service";
     private static final String VF = "VF";
     private static final String NOT_SUPPORTED_COMPONENT_TYPE = "Not supported component type {}";
@@ -2532,7 +2534,7 @@ public class ToscaOperationFacade {
         }
         Component component = latestVersionList.size() == 1 ? latestVersionList.get(0)
             : latestVersionList.stream().max((c1, c2) -> Double.compare(Double.parseDouble(c1.getVersion()), Double.parseDouble(c2.getVersion())))
-                .get();
+            .get();
         return Either.left(component);
     }
 
index 82afb0a..4ada629 100644 (file)
@@ -26,7 +26,7 @@ import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
 import {TranslateService} from "app/ng2/shared/translator/translate.service";
 import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular';
 import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
-
+import {ResourceType, ComponentType} from "app/utils";
 import {ModalService} from 'app/ng2/services/modal.service';
 import {
     ArtifactModel,
@@ -238,9 +238,13 @@ export class InterfaceDefinitionComponent {
     }
 
     onInstanceSelectedUpdate = (instance: any) => {
+        this.interfaces = [];
         this.selectedInstanceData = instance;
         if (instance.name != "SELF") {
-            this.disableFlag = true;
+            this.disableFlag = !this.isAllowAddOperation(instance.originType);
+            if (!instance.interfaces) {
+                return;
+            }
             let newInterfaces : InterfaceModel[] = [];
             if (instance.interfaces instanceof Array) {
                 instance.interfaces.forEach(result => {
@@ -252,6 +256,8 @@ export class InterfaceDefinitionComponent {
                     } else if (!_.isEmpty(result.operations)) {
                         interfaceObj.operations = [];
                         Object.keys(result.operations).forEach(name => {
+                            result.operations[name].interfaceId = result.type;
+                            result.operations[name].interfaceType = result.type;
                             interfaceObj.operations.push(result.operations[name]);
                         });
                     }
@@ -268,6 +274,8 @@ export class InterfaceDefinitionComponent {
                     } else if (!_.isEmpty(obj.operations)) {
                         interfaceObj.operations = [];
                         Object.keys(obj.operations).forEach(name => {
+                            obj.operations[name].interfaceId = key;
+                            obj.operations[name].interfaceType = key;
                             interfaceObj.operations.push(obj.operations[name]);
                         });
                     }
@@ -276,11 +284,19 @@ export class InterfaceDefinitionComponent {
             }
             this.interfaces = newInterfaces.map((interf) => new UIInterfaceModel(interf));
         } else {
+            this.disableFlag = true;
             this.interfaces = this.serviceInterfaces.map((interf) => new UIInterfaceModel(interf));
         }
         this.sortInterfaces();
     }
 
+    isAllowAddOperation(originType: string): boolean {
+        if (originType && (originType === ResourceType.VFC || originType === ResourceType.CP || originType === ResourceType.VL)){
+            return true;
+        }
+        return false;
+    }
+
     initInterfaces(interfaces: InterfaceModel[]): void {
         if (interfaces) {
             this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf));
@@ -296,9 +312,6 @@ export class InterfaceDefinitionComponent {
         if(this.readonly) {
             return disable;
         }
-        if (this.component.isService()) {
-            return disable;
-        }
         const validMilestoneActivities = this.modalInstance.instance.dynamicContent.instance.validMilestoneActivities;
         const validMilestoneFilters = this.modalInstance.instance.dynamicContent.instance.validMilestoneFilters;
         if (!validMilestoneActivities || !validMilestoneFilters) {
@@ -376,53 +389,106 @@ export class InterfaceDefinitionComponent {
         if (timeout != null) {
             operationToUpdate.implementation.timeout = timeout;
         }
-        this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate)
-        .subscribe((newOperation: InterfaceOperationModel) => {
-            let oldOpIndex;
-            let oldInterf;
-            this.interfaces.forEach(interf => {
-                interf.operations.forEach(op => {
-                    if (op.uniqueId === newOperation.uniqueId) {
-                        oldInterf = interf;
-                        oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId);
-                    }
+        if (this.component.componentType === ComponentType.SERVICE) {
+            this.topologyTemplateService.updateComponentInstanceInterfaceOperation(this.component.uniqueId, this.component.componentType, this.selectedInstanceData.uniqueId, operationToUpdate)
+            .subscribe((res) => {
+                const interf: InterfaceModel = _.find(res.interfaces, interf => interf.type === operationToUpdate.interfaceType);
+                const newOp: OperationModel = _.find(interf.operations, op => op.name === operationToUpdate.name);
+                let newOperation = new InterfaceOperationModel({
+                    ...newOp,
+                    interfaceType: interf.type,
+                    interfaceId: interf.uniqueId,
+                })
+                let oldOpIndex;
+                let oldInterf;
+                this.interfaces.forEach(interf => {
+                    interf.operations.forEach(op => {
+                        if (op.uniqueId === newOperation.uniqueId) {
+                            oldInterf = interf;
+                            oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId);
+                        }
+                    });
                 });
+                oldInterf.operations.splice(oldOpIndex, 1);
+                oldInterf.operations.push(new InterfaceOperationModel(newOperation));
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+            }, () => {
+                this.sortInterfaces();
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
             });
-            oldInterf.operations.splice(oldOpIndex, 1);
-            oldInterf.operations.push(new InterfaceOperationModel(newOperation));
-        }, error => {
-            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
-        }, () => {
-            this.sortInterfaces();
-            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
-            this.modalServiceNg2.closeCurrentModal();
-        });
+        } else {
+            this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate)
+            .subscribe((newOperation: InterfaceOperationModel) => {
+                let oldOpIndex;
+                let oldInterf;
+                this.interfaces.forEach(interf => {
+                    interf.operations.forEach(op => {
+                        if (op.uniqueId === newOperation.uniqueId) {
+                            oldInterf = interf;
+                            oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId);
+                        }
+                    });
+                });
+                oldInterf.operations.splice(oldOpIndex, 1);
+                oldInterf.operations.push(new InterfaceOperationModel(newOperation));
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+            }, () => {
+                this.sortInterfaces();
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
+            });
+        }
     }
 
     private createOperationCallback(): void {
         this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true;
         const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
-        console.log('createOperationCallback', operationToUpdate);
-        console.log('this.component', this.component);
-        this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate)
-        .subscribe((newOperation: InterfaceOperationModel) => {
-            const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
-            if (foundInterface) {
-                foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
-            } else {
-                const uiInterfaceModel = new UIInterfaceModel();
-                uiInterfaceModel.type = newOperation.interfaceType;
-                uiInterfaceModel.uniqueId = newOperation.interfaceType;
-                uiInterfaceModel.operations = [];
-                uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
-                this.interfaces.push(uiInterfaceModel);
-            }
-        }, error => {
-            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
-        }, () => {
-            this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
-            this.modalServiceNg2.closeCurrentModal();
-        });
+        if (this.component.componentType === ComponentType.SERVICE) {
+            this.topologyTemplateService.createComponentInstanceInterfaceOperation(this.component.uniqueId, this.selectedInstanceData.uniqueId, operationToUpdate)
+            .subscribe((newOperation: InterfaceOperationModel) => {
+                const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
+                if (foundInterface) {
+                    foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+                } else {
+                    const uiInterfaceModel = new UIInterfaceModel();
+                    uiInterfaceModel.type = newOperation.interfaceType;
+                    uiInterfaceModel.uniqueId = newOperation.interfaceType;
+                    uiInterfaceModel.operations = [];
+                    uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+                    this.interfaces.push(uiInterfaceModel);
+                }
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
+            });
+        } else {
+            this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate)
+            .subscribe((newOperation: InterfaceOperationModel) => {
+                const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
+                if (foundInterface) {
+                    foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+                } else {
+                    const uiInterfaceModel = new UIInterfaceModel();
+                    uiInterfaceModel.type = newOperation.interfaceType;
+                    uiInterfaceModel.uniqueId = newOperation.interfaceType;
+                    uiInterfaceModel.operations = [];
+                    uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
+                    this.interfaces.push(uiInterfaceModel);
+                }
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
+            }, () => {
+                this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
+                this.modalServiceNg2.closeCurrentModal();
+            });
+        }
     }
 
     private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => {
index 0af8c73..405d2bb 100644 (file)
@@ -36,6 +36,7 @@ import {
     IFileDownload,
     InputBEModel,
     InstancePropertiesAPIMap,
+    InterfaceModel,
     OperationModel,
     PropertyModel,
     Requirement
@@ -672,4 +673,29 @@ export class TopologyTemplateService {
         .pipe(map(response => response && response.defaultCustomToscaFunction  ? response.defaultCustomToscaFunction : []));
     }
 
+    createComponentInstanceInterfaceOperation(componentMetaDataId: string, componentInstanceId: string,
+        operation: InterfaceOperationModel): Observable<InterfaceOperationModel> {
+        const operationList = {
+            interfaces: {
+                [operation.interfaceType]: {
+                    type: operation.interfaceType,
+                    operations: {
+                        [operation.name]: new BEInterfaceOperationModel(operation)
+                    }
+                }
+            }
+        };
+        return this.http.post<any>(this.baseUrl + 'services/' + componentMetaDataId + '/componentInstance/' + componentInstanceId + '/interfaceOperation', operationList)
+        .map((res: any) => {
+            const interf: InterfaceModel = _.find(res.interfaces, interf => interf.type === operation.interfaceType);
+            const newOperation: OperationModel = _.find(interf.operations, op => op.name === operation.name);
+
+            return new InterfaceOperationModel({
+                ...newOperation,
+                interfaceType: interf.type,
+                interfaceId: interf.uniqueId,
+            });
+        });
+    }
+
 }