Added Edit Instance Properties Functionality 19/129319/3
authorbrunomilitzer <bruno.militzer@est.tech>
Thu, 5 May 2022 14:20:30 +0000 (15:20 +0100)
committerbrunomilitzer <bruno.militzer@est.tech>
Wed, 25 May 2022 14:01:02 +0000 (15:01 +0100)
Issue-ID: POLICY-4094
Change-Id: Id52dba3c0912486fa551697be170c05542a0ee22
Signed-off-by: brunomilitzer <bruno.militzer@est.tech>
12 files changed:
models/src/main/java/org/onap/policy/clamp/models/acm/persistence/provider/ServiceTemplateProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProvider.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/CommissioningController.java
runtime-acm/src/main/java/org/onap/policy/clamp/acm/runtime/main/rest/InstantiationController.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/commissioning/CommissioningProviderTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/commissioning/rest/CommissioningControllerTest.java
runtime-acm/src/test/java/org/onap/policy/clamp/acm/runtime/instantiation/AutomationCompositionInstantiationProviderTest.java
runtime/extra/sql/bulkload/create-db.sql
runtime/src/main/resources/clds/camel/rest/clamp-api-v2.xml
runtime/src/main/resources/clds/camel/routes/acm-flows.xml
runtime/src/test/resources/http-cache/third_party_proxy.py

index 0de5f48..942fe8d 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation.
+ *  Copyright (C) 2021-2022 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -133,7 +133,6 @@ public class ServiceTemplateProvider {
      * @param fullNodeTypes map of all the node types in the specified template
      * @param common boolean to indicate whether common or instance properties are required
      * @return node types map that only has common properties
-     * @throws PfModelException on errors getting node type with common properties
      */
     private Map<String, ToscaNodeType> getInitialNodeTypesMap(Map<String, ToscaNodeType> fullNodeTypes,
             boolean common) {
@@ -214,6 +213,56 @@ public class ServiceTemplateProvider {
         return filteredNodeTypes;
     }
 
+    /**
+     * Get the node types derived from those that have been saved by instantiation.
+     *
+     * @param initialNodeTypes map of all the node types in the specified template
+     * @param filteredNodeTypes map of all the node types that have common or instance properties
+     * @param instanceName automation composition name
+     * @return all node types that have common properties including their children
+     */
+    private Map<String, ToscaNodeType> getFinalSavedInstanceNodeTypesMap(
+            Map<String, ToscaNodeType> initialNodeTypes,
+            Map<String, ToscaNodeType> filteredNodeTypes, String instanceName) {
+
+        for (var i = 0; i < initialNodeTypes.size(); i++) {
+            initialNodeTypes.forEach((key, nodeType) -> {
+                var tempToscaNodeType = new ToscaNodeType();
+                tempToscaNodeType.setName(key);
+
+                if (filteredNodeTypes.get(nodeType.getDerivedFrom()) != null) {
+                    tempToscaNodeType.setName(key);
+
+                    var finalProps = new HashMap<String, ToscaProperty>(
+                            filteredNodeTypes.get(nodeType.getDerivedFrom()).getProperties());
+
+                    tempToscaNodeType.setProperties(finalProps);
+                } else {
+                    return;
+                }
+                filteredNodeTypes.putIfAbsent(key, tempToscaNodeType);
+
+            });
+        }
+        return filteredNodeTypes;
+    }
+
+    /**
+     * Get the requested node types by automation composition.
+     *
+     * @param instanceName automation composition name
+     * @param serviceTemplate the ToscaServiceTemplate
+     * @return the node types with common or instance properties
+     */
+    public Map<String, ToscaNodeType> getSavedInstanceInstancePropertiesFromNodeTypes(
+            String instanceName, ToscaServiceTemplate serviceTemplate) {
+        var tempNodeTypesMap =
+                this.getInitialNodeTypesMap(serviceTemplate.getNodeTypes(), false);
+
+        return this.getFinalSavedInstanceNodeTypesMap(serviceTemplate.getNodeTypes(), tempNodeTypesMap, instanceName);
+
+    }
+
     /**
      * Get the requested node types with common or instance properties.
      *
index 726fcba..7d2d4f3 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- * Copyright (C) 2021 Nordix Foundation.
+ * Copyright (C) 2021-2022 Nordix Foundation.
  * Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,6 +35,7 @@ import java.util.stream.Collectors;
 import javax.ws.rs.core.Response.Status;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
 import org.onap.policy.clamp.acm.runtime.supervision.SupervisionHandler;
 import org.onap.policy.clamp.models.acm.concepts.Participant;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
@@ -237,15 +238,17 @@ public class CommissioningProvider {
     /**
      * Get node templates with common properties added.
      *
-     * @param common boolean indicating common or instance properties to be used
      * @param name the name of the definition to use, null for all definitions
      * @param version the version of the definition to use, null for all definitions
+     * @param instanceName automation composition name
+     * @param common boolean indicating common or instance properties to be used
      * @return the nodes templates with common or instance properties
      * @throws PfModelException on errors getting common or instance properties from node_templates
      */
     @Transactional(readOnly = true)
-    public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(boolean common, String name,
-            String version) throws PfModelException {
+    public Map<String, ToscaNodeTemplate> getNodeTemplatesWithCommonOrInstanceProperties(
+            final String name, final String version, final String instanceName, final boolean common)
+            throws PfModelException {
 
         if (common && verifyIfInstancePropertiesExists()) {
             throw new PfModelException(Status.BAD_REQUEST,
@@ -253,11 +256,17 @@ public class CommissioningProvider {
         }
 
         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
+
+        if (serviceTemplateList.isEmpty()) {
+            throw new PfModelException(Status.BAD_REQUEST,
+                    "Tosca service template has to be commissioned before saving instance properties");
+        }
+
         var commonOrInstanceNodeTypeProps =
                 serviceTemplateProvider.getCommonOrInstancePropertiesFromNodeTypes(common, serviceTemplateList.get(0));
 
         var serviceTemplates = new ToscaServiceTemplates();
-        serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList));
+        serviceTemplates.setServiceTemplates(filterToscaNodeTemplateInstance(serviceTemplateList, instanceName));
 
         return serviceTemplateProvider.getDerivedCommonOrInstanceNodeTemplates(
                 serviceTemplates.getServiceTemplates().get(0).getToscaTopologyTemplate().getNodeTemplates(),
@@ -293,14 +302,19 @@ public class CommissioningProvider {
      *
      * @param name the name of the template to get, null for all definitions
      * @param version the version of the template to get, null for all definitions
+     * @param instanceName automation composition name
      * @return the tosca service template
      * @throws PfModelException on errors getting tosca service template
      */
     @Transactional(readOnly = true)
-    public String getToscaServiceTemplateReduced(String name, String version) throws PfModelException {
+    public String getToscaServiceTemplateReduced(
+            final String name, final String version, final String instanceName)
+            throws PfModelException {
+
         var serviceTemplateList = serviceTemplateProvider.getServiceTemplateList(name, version);
 
-        List<ToscaServiceTemplate> filteredServiceTemplateList = filterToscaNodeTemplateInstance(serviceTemplateList);
+        List<ToscaServiceTemplate> filteredServiceTemplateList =
+                filterToscaNodeTemplateInstance(serviceTemplateList, instanceName);
 
         if (filteredServiceTemplateList.isEmpty()) {
             throw new PfModelException(Status.BAD_REQUEST, "Invalid Service Template");
@@ -342,16 +356,26 @@ public class CommissioningProvider {
         }
     }
 
-    private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(List<ToscaServiceTemplate> serviceTemplates) {
+    /**
+     * Filters service templates if is not an instantiation type.
+     *
+     * @param serviceTemplates tosca service template
+     * @param instanceName     automation composition name
+     * @return List of tosca service templates
+     */
+    private List<ToscaServiceTemplate> filterToscaNodeTemplateInstance(
+            List<ToscaServiceTemplate> serviceTemplates, String instanceName) {
 
         List<ToscaServiceTemplate> toscaServiceTemplates = new ArrayList<>();
 
-        serviceTemplates.stream().forEach(serviceTemplate -> {
+        serviceTemplates.forEach(serviceTemplate -> {
 
             Map<String, ToscaNodeTemplate> toscaNodeTemplates = new HashMap<>();
 
             serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().forEach((key, nodeTemplate) -> {
-                if (!nodeTemplate.getName().contains(HYPHEN)) {
+                if (StringUtils.isNotEmpty(instanceName) && nodeTemplate.getName().contains(instanceName)) {
+                    toscaNodeTemplates.put(key, nodeTemplate);
+                } else if (!nodeTemplate.getName().contains(HYPHEN)) {
                     toscaNodeTemplates.put(key, nodeTemplate);
                 }
             });
index 40d4c5a..98b59ae 100644 (file)
@@ -141,6 +141,61 @@ public class AutomationCompositionInstantiationProvider {
         return saveInstancePropertiesAndAutomationComposition(serviceTemplate, automationCompositions);
     }
 
+    /**
+     * Updates Instance Properties and Automation Composition Instance.
+     *
+     * @param name the name of the automation composition to update
+     * @param version the version of the automation composition to update
+     * @param serviceTemplate tosca service template body
+     * @return InstancePropertiesResponse response from updating instance properties
+     * @throws PfModelException exception if incorrect instance name
+     */
+    public InstancePropertiesResponse updatesInstanceProperties(
+            String name, String version, ToscaServiceTemplate serviceTemplate) throws PfModelException {
+
+        if (name.length() < 3) {
+            throw new PfModelException(Status.BAD_REQUEST, "Instance Name cannot be empty or less than 3 characters!");
+        }
+
+        Map<String, ToscaNodeTemplate> nodeTemplates = deepCloneNodeTemplate(serviceTemplate);
+        Map<String, ToscaNodeTemplate> updatedNodeTemplates = new HashMap<>();
+
+        String instanceName = serviceTemplate.getName();
+
+        nodeTemplates.forEach((key, template) -> {
+            ToscaNodeTemplate toscaNodeTemplate = new ToscaNodeTemplate();
+
+            String updatedName = updateInstanceNameDescription(instanceName, name, key);
+            String updatedDescription = updateInstanceNameDescription(
+                    instanceName, name, template.getDescription());
+
+            toscaNodeTemplate.setName(updatedName);
+            toscaNodeTemplate.setDescription(updatedDescription);
+            toscaNodeTemplate.setCapabilities(template.getCapabilities());
+            toscaNodeTemplate.setRequirements(template.getRequirements());
+            toscaNodeTemplate.setMetadata(template.getMetadata());
+            toscaNodeTemplate.setProperties(template.getProperties());
+            toscaNodeTemplate.setDerivedFrom(template.getDerivedFrom());
+            toscaNodeTemplate.setVersion(template.getVersion());
+            toscaNodeTemplate.setType(template.getType());
+            toscaNodeTemplate.setTypeVersion(template.getTypeVersion());
+
+            String updatedKey = updateInstanceNameDescription(instanceName, name, key);
+
+            updatedNodeTemplates.put(updatedKey, toscaNodeTemplate);
+        });
+
+        serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().clear();
+        serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().putAll(updatedNodeTemplates);
+
+        AutomationCompositions automationCompositions = updateAutomationComposition(
+                name, instanceName);
+
+        deleteInstanceProperties(name, version);
+
+        return saveInstancePropertiesAndAutomationComposition(serviceTemplate, automationCompositions);
+    }
+
     /**
      * Deletes Instance Properties.
      *
@@ -616,4 +671,64 @@ public class AutomationCompositionInstantiationProvider {
         Type type = new TypeToken<HashMap<String, ToscaNodeTemplate>>() {}.getType();
         return GSON.fromJson(jsonString, type);
     }
+
+    /**
+     * Updates Automation composition instance name.
+     *
+     * @param oldInstanceName previous saved instance name
+     * @param newInstanceName new instance name to replace the previous one
+     * @return AutomationCompositions updated
+     * @throws PfModelException exception to compositions is not defined
+     */
+    private AutomationCompositions updateAutomationComposition(
+            String oldInstanceName, String newInstanceName) throws PfModelException {
+
+        List<AutomationComposition> filteredAcmList = automationCompositionProvider.getAutomationCompositions()
+                .stream().filter(acm -> acm.getName().contains(oldInstanceName)).collect(Collectors.toList());
+
+        if (filteredAcmList.isEmpty()) {
+            throw new PfModelException(Status.BAD_REQUEST, "Automation compositions not defined!");
+        }
+
+        AutomationComposition automationComposition = filteredAcmList.get(0);
+
+        automationComposition.getDefinition()
+                .setName(updateInstanceNameDescription(newInstanceName, oldInstanceName,
+                        automationComposition.getDefinition().getName()));
+
+        automationComposition.setName(newInstanceName);
+
+        automationComposition.setDescription(
+                updateInstanceNameDescription(newInstanceName, oldInstanceName,
+                        automationComposition.getDescription()));
+
+        automationComposition.getElements().forEach((uuid, automationCompositionElement) -> {
+            automationCompositionElement.getDefinition()
+                    .setName(updateInstanceNameDescription(newInstanceName, oldInstanceName,
+                            automationCompositionElement.getDefinition().getName()));
+        });
+
+        AutomationCompositions automationCompositions = new AutomationCompositions();
+        automationCompositions.getAutomationCompositionList().add(automationComposition);
+
+        return automationCompositions;
+
+    }
+
+    /**
+     * Updates instance and description.
+     *
+     * @param newInstanceName new instance name to replace the previous one
+     * @param oldInstanceName previous saved instance name
+     * @param value to be updated
+     * @return String updated instance name or description
+     */
+    private String updateInstanceNameDescription(
+            String newInstanceName, String oldInstanceName, String value) {
+        String toBeReplaced = value.substring(value.indexOf(oldInstanceName));
+
+        String replace = value.replace(toBeReplaced, newInstanceName);
+
+        return replace;
+    }
 }
index 0fd8661..0458b07 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation.
+ *  Copyright (C) 2021-2022 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,7 +35,6 @@ import javax.ws.rs.core.Response.Status;
 import lombok.RequiredArgsConstructor;
 import org.onap.policy.clamp.acm.runtime.commissioning.CommissioningProvider;
 import org.onap.policy.clamp.acm.runtime.main.web.AbstractRestController;
-import org.onap.policy.clamp.common.acm.exception.AutomationCompositionException;
 import org.onap.policy.clamp.models.acm.messages.rest.commissioning.CommissioningResponse;
 import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
@@ -305,10 +304,13 @@ public class CommissioningController extends AbstractRestController {
             required = false) String name,
         @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
             value = "version",
-            required = false) String version)
+            required = false) String version,
+        @ApiParam(value = "Automation composition name", required = false) @RequestParam(
+                value = "instanceName",
+                required = false) String instanceName)
         throws PfModelException {
 
-        return ResponseEntity.ok().body(provider.getToscaServiceTemplateReduced(name, version));
+        return ResponseEntity.ok().body(provider.getToscaServiceTemplateReduced(name, version, instanceName));
     }
 
     /**
@@ -376,7 +378,6 @@ public class CommissioningController extends AbstractRestController {
      * @param version the version of the tosca service template to get
      * @return the specified tosca service template or section Json Schema
      * @throws PfModelException on errors getting the Common or Instance Properties
-     * @throws AutomationCompositionException on error getting the Common or Instance Properties
      */
     // @formatter:off
     @GetMapping(value = "/commission/getCommonOrInstanceProperties",
@@ -418,18 +419,23 @@ public class CommissioningController extends AbstractRestController {
     // @formatter:on
     public ResponseEntity<Map<String, ToscaNodeTemplate>> queryToscaServiceCommonOrInstanceProperties(
         @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-        @ApiParam(
-            value = "Flag, true for common properties, false for instance",
-            required = false) @RequestParam(value = "common", defaultValue = "false", required = false) boolean common,
         @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
             value = "name",
             required = false) String name,
         @ApiParam(value = "Tosca service template version", required = false) @RequestParam(
             value = "version",
-            required = false) String version)
+            required = false) String version,
+        @ApiParam(value = "Automation composition name", required = false) @RequestParam(
+                value = "instanceName",
+                required = false) String instanceName,
+        @ApiParam(
+                value = "Flag, true for common properties, false for instance",
+                required = false)
+            @RequestParam(value = "common", defaultValue = "false", required = false) boolean common)
         throws PfModelException {
 
-        return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(common, name, version));
+        return ResponseEntity.ok().body(provider
+                .getNodeTemplatesWithCommonOrInstanceProperties(name, version, instanceName, common));
     }
 
     /**
index dc56c77..b4d978d 100644 (file)
@@ -1,6 +1,6 @@
 /*-
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation.
+ *  Copyright (C) 2021-2022 Nordix Foundation.
  *  Modifications Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -192,6 +192,74 @@ public class InstantiationController extends AbstractRestController {
         return ResponseEntity.ok().body(provider.createInstanceProperties(body));
     }
 
+    /**
+     * Updates instance properties.
+     *
+     * @param name the name of the automation composition to update
+     * @param version the version of the automation composition to update
+     * @param body the body of automation composition following TOSCA definition
+     * @return a response
+     */
+    // @formatter:off
+    @PutMapping(value = "/instanceProperties",
+            consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
+            produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
+    @ApiOperation(
+            value = "Updates instance properties",
+            notes = "Updates instance properties, returning the saved instances properties and it's version",
+            response = InstancePropertiesResponse.class,
+            tags = {TAGS},
+            authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+            responseHeaders = {
+                @ResponseHeader(
+                    name = VERSION_MINOR_NAME,
+                    description = VERSION_MINOR_DESCRIPTION,
+                    response = String.class),
+                @ResponseHeader(
+                    name = VERSION_PATCH_NAME,
+                    description = VERSION_PATCH_DESCRIPTION,
+                    response = String.class),
+                @ResponseHeader(
+                    name = VERSION_LATEST_NAME,
+                    description = VERSION_LATEST_DESCRIPTION,
+                    response = String.class),
+                @ResponseHeader(
+                    name = REQUEST_ID_NAME,
+                    description = REQUEST_ID_HDR_DESCRIPTION,
+                    response = UUID.class)
+            },
+            extensions = {
+                @Extension
+                    (
+                        name = EXTENSION_NAME,
+                        properties = {
+                            @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+                            @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
+                        }
+                    )
+            }
+    )
+    @ApiResponses(
+        value = {
+            @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+            @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+            @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
+        }
+    )
+    // @formatter:on
+    public ResponseEntity<InstancePropertiesResponse> updatesInstanceProperties(
+            @RequestHeader(name = REQUEST_ID_NAME, required = false)
+            @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
+            @ApiParam(value = "Automation composition definition name", required = true)
+                @RequestParam("name") String name,
+            @ApiParam(value = "Automation composition definition version", required = true)
+                @RequestParam("version") String version,
+            @ApiParam(value = "Body of instance properties", required = true) @RequestBody ToscaServiceTemplate body)
+            throws PfModelException {
+
+        return ResponseEntity.ok().body(provider.updatesInstanceProperties(name, version, body));
+    }
+
     /**
      * Deletes a automation composition definition and instance properties.
      *
@@ -248,8 +316,8 @@ public class InstantiationController extends AbstractRestController {
 
     public ResponseEntity<InstantiationResponse> deleteInstanceProperties(
         @RequestHeader(name = REQUEST_ID_NAME, required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
-        @ApiParam(value = "Automation composition  definition name", required = true) @RequestParam("name") String name,
-        @ApiParam(value = "Automation composition  definition version") @RequestParam(
+        @ApiParam(value = "Automation composition definition name", required = true) @RequestParam("name") String name,
+        @ApiParam(value = "Automation composition definition version") @RequestParam(
             value = "version",
             required = true) String version)
         throws PfModelException {
index 71aadcc..152171f 100644 (file)
@@ -163,7 +163,8 @@ class CommissioningProviderTest {
         when(serviceTemplateProvider.getServiceTemplateList(any(), any()))
                 .thenReturn(List.of(Objects.requireNonNull(serviceTemplate)));
 
-        String returnedServiceTemplate = provider.getToscaServiceTemplateReduced(null, null);
+        String returnedServiceTemplate = provider
+                .getToscaServiceTemplateReduced(null, null, null);
         assertThat(returnedServiceTemplate).isNotNull();
         ToscaServiceTemplate parsedServiceTemplate = CODER.decode(returnedServiceTemplate, ToscaServiceTemplate.class);
 
index 87633df..a0f1a75 100644 (file)
@@ -158,7 +158,7 @@ class CommissioningControllerTest extends CommonRestController {
         createFullEntryInDbWithCommonProps();
 
         Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT
-                + "/getCommonOrInstanceProperties" + "?common=true&name=ToscaServiceTemplateSimple&version=1.0.0");
+                + "/getCommonOrInstanceProperties?common=true");
         Response rawresp = invocationBuilder.buildGet().invoke();
         assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus());
 
index 248b045..b826eeb 100644 (file)
@@ -120,6 +120,11 @@ class AutomationCompositionInstantiationProviderTest {
         automationComposition.setVersion(ID_VERSION);
         when(acProvider.getAutomationCompositions(ID_NAME, ID_VERSION)).thenReturn(List.of(automationComposition));
 
+        var updatedInstancePropertyList = instantiationProvider.createInstanceProperties(serviceTemplate);
+        assertNull(updatedInstancePropertyList.getErrorDetails());
+        var updatedId = new ToscaConceptIdentifier(ID_NAME, ID_VERSION);
+        assertEquals(updatedId, instancePropertyList.getAffectedInstanceProperties().get(0));
+
         var instanceOrderState = instantiationProvider.getInstantiationOrderState(ID_NAME, ID_VERSION);
         assertEquals(AutomationCompositionOrderedState.UNINITIALISED, instanceOrderState.getOrderedState());
         assertEquals(ID_NAME, instanceOrderState.getAutomationCompositionIdentifierList().get(0).getName());
index 5fa34ca..a9d81d7 100644 (file)
@@ -7,9 +7,9 @@ USE `cldsdb4`;
 DROP USER 'clds';
 CREATE USER 'clds';
 GRANT ALL on cldsdb4.* to 'clds' identified by 'sidnnd83K' with GRANT OPTION;
-CREATE DATABASE `controlloop`;
-USE `controlloop`;
+CREATE DATABASE `clampacm`;
+USE `clampacm`;
 DROP USER 'policy';
 CREATE USER 'policy';
-GRANT ALL on controlloop.* to 'policy' identified by 'P01icY' with GRANT OPTION;
+GRANT ALL on clampacm.* to 'policy' identified by 'P01icY' with GRANT OPTION;
 FLUSH PRIVILEGES;
index 8ad20a8..7db4680 100644 (file)
              produces="application/json">
             <route>
                 <removeHeaders pattern="*"
-                               excludePattern="name|version"/>
+                               excludePattern="name|version|instanceName"/>
                 <doTry>
                     <to
                             uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Tosca Service Template ')"/>
                 </doTry>
             </route>
         </post>
+
+        <put uri="/v2/acm/putToscaInstanceProperties"
+              type="java.lang.String"
+              consumes="plain/text"
+              outType="java.lang.String"
+              produces="application/json"
+              bindingMode="off">
+            <route>
+                <removeHeaders pattern="*" excludePattern="name|version"/>
+                <setProperty name="raiseHttpExceptionFlag">
+                    <simple resultType="java.lang.Boolean">false</simple>
+                </setProperty>
+                <setHeader name="Content-Type">
+                    <constant>application/json</constant>
+                </setHeader>
+                <doTry>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'Update the global properties')"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','update')"/>
+                    <to uri="direct:put-tosca-instance-properties"/>
+                    <to
+                            uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=endLog()"/>
+                    <doCatch>
+                        <exception>java.lang.Exception</exception>
+                        <handled>
+                            <constant>true</constant>
+                        </handled>
+                        <to
+                                uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=errorLog()"/>
+                        <log loggingLevel="ERROR"
+                             message="Updating Instance Properties FAILED"/>
+
+                        <setHeader name="CamelHttpResponseCode">
+                            <constant>500</constant>
+                        </setHeader>
+                        <setBody>
+                            <simple>Updating Instance Properties FAILED</simple>
+                        </setBody>
+                    </doCatch>
+                </doTry>
+            </route>
+        </put>
+
         <delete uri="/v2/acm/deleteToscaInstanceProperties"
                 type="java.lang.String"
                 consumes="plain/text"
         <get uri="/v2/acm/getCommonOrInstanceProperties" outType="java.lang.String" bindingMode="off" produces="application/json">
             <route>
                 <removeHeaders pattern="*"
-                               excludePattern="name|version|requestId|common"/>
+                               excludePattern="name|version|instanceName|requestId|common"/>
                 <doTry>
                     <to uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=startLog(*, 'GET Common Properties ')"/>
                     <to uri="bean:org.onap.policy.clamp.authorization.AuthorizationController?method=authorize(*,'cl','','read')"/>
                             <constant>500</constant>
                         </setHeader>
                         <setBody>
-                            <simple>GET Common Properties FAILED</simple>
+                            <simple>GET Common or Instance Properties FAILED</simple>
                         </setBody>
                     </doCatch>
                 </doTry>
index c304c53..9150a23 100644 (file)
             <setProperty name="version">
                 <simple>${header.version}</simple>
             </setProperty>
+            <setProperty name="instanceName">
+                <simple>${header.instanceName}</simple>
+            </setProperty>
             <log loggingLevel="INFO"
                  message="Endpoint to get Tosca Service Template: {{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/toscaservicetemplate"></log>
-            <toD uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/toscaservicetemplate?name=${exchangeProperty[name]}&amp;version=${exchangeProperty[version]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+            <toD uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/toscaservicetemplate?name=${exchangeProperty[name]}&amp;version=${exchangeProperty[version]}&amp;instanceName=${exchangeProperty[instanceName]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
             <convertBodyTo type="java.lang.String"/>
             <doFinally>
                 <to uri="direct:reset-raise-http-exception-flag"/>
             </doFinally>
         </doTry>
     </route>
+    <route id="put-tosca-instance-properties">
+        <from uri="direct:put-tosca-instance-properties"/>
+        <doTry>
+            <log loggingLevel="INFO"
+                 message="Updating the tosca instance properties"/>
+            <to
+                    uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('AutomationComposition', 'Updating the tosca instance properties')"/>
+            <setHeader name="CamelHttpMethod">
+                <constant>PUT</constant>
+            </setHeader>
+            <setHeader name="Content-Type">
+                <constant>application/json</constant>
+            </setHeader>
+            <setProperty name="name">
+                <simple>${header.name}</simple>
+            </setProperty>
+            <setProperty name="version">
+                <simple>${header.version}</simple>
+            </setProperty>
+            <log loggingLevel="INFO"
+                 message="Endpoint to send Tosca Instance Properties: {{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/instanceProperties"></log>
+            <toD
+                    uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/instanceProperties?name=${exchangeProperty[name]}&amp;version=${exchangeProperty[version]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+            <convertBodyTo type="java.lang.String"/>
+            <doFinally>
+                <to uri="direct:reset-raise-http-exception-flag"/>
+                <to
+                        uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+            </doFinally>
+        </doTry>
+    </route>
     <route id="delete-tosca-instance-properties">
         <from uri="direct:delete-tosca-instance-properties"/>
         <doTry>
             <setHeader name="Content-Type">
                 <constant>application/json</constant>
             </setHeader>
+            <setProperty name="name">
+                <simple>${header.name}</simple>
+            </setProperty>
+            <setProperty name="version">
+                <simple>${header.version}</simple>
+            </setProperty>
+            <setProperty name="instanceName">
+                <simple>${header.instanceName}</simple>
+            </setProperty>
             <setProperty name="common">
                 <simple>${header.common}</simple>
             </setProperty>
             <log loggingLevel="INFO"
                  message="Endpoint to get Common Or Instance Properties: {{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/getCommonOrInstanceProperties"></log>
             <toD
-                    uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/getCommonOrInstanceProperties?common=${exchangeProperty[common]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+                    uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/getCommonOrInstanceProperties?name=${exchangeProperty[name]}&amp;version=${exchangeProperty[version]}&amp;instanceName=${exchangeProperty[instanceName]}&amp;common=${exchangeProperty[common]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
+            <convertBodyTo type="java.lang.String"/>
+            <doFinally>
+                <to uri="direct:reset-raise-http-exception-flag"/>
+                <to
+                        uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeReturnLog()"/>
+            </doFinally>
+        </doTry>
+    </route>
+    <route id="get-saved-instance-name-instance-properties">
+        <from uri="direct:get-saved-instance-name-instance-properties"/>
+        <doTry>
+            <log loggingLevel="INFO"
+                 message="Getting Common Or Instance Properties"/>
+            <to
+                    uri="bean:org.onap.policy.clamp.flow.log.FlowLogOperation?method=invokeLog('AutomationComposition', 'Getting Saved Instance Name Instance Properties')"/>
+            <setHeader name="CamelHttpMethod">
+                <constant>GET</constant>
+            </setHeader>
+            <setHeader name="Content-Type">
+                <constant>application/json</constant>
+            </setHeader>
+            <setProperty name="name">
+                <simple>${header.name}</simple>
+            </setProperty>
+            <setProperty name="version">
+                <simple>${header.version}</simple>
+            </setProperty>
+            <setProperty name="instanceName">
+                <simple>${header.instanceName}</simple>
+            </setProperty>
+            <log loggingLevel="INFO"
+                 message="Endpoint to get Common Or Instance Properties: {{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/getSavedInstanceNameInstanceProperties"></log>
+            <toD
+                    uri="{{clamp.config.acm.runtime.url}}/onap/policy/clamp/acm/v2/commission/getSavedInstanceNameInstanceProperties?name=${exchangeProperty[name]}&amp;version=${exchangeProperty[version]}&amp;instanceName=${exchangeProperty[instanceName]}&amp;bridgeEndpoint=true&amp;useSystemProperties=true&amp;throwExceptionOnFailure=${exchangeProperty[raiseHttpExceptionFlag]}&amp;authMethod=Basic&amp;authUsername={{clamp.config.acm.runtime.userName}}&amp;authPassword={{clamp.config.acm.runtime.password}}&amp;authenticationPreemptive=true&amp;connectionClose=true"/>
             <convertBodyTo type="java.lang.String"/>
             <doFinally>
                 <to uri="direct:reset-raise-http-exception-flag"/>
index 9c22f3f..e116c92 100644 (file)
@@ -5,7 +5,7 @@
 # ================================================================================
 # Copyright (C) 2018 AT&T Intellectual Property. All rights
 #                             reserved.
-# Modifications Copyright (C) 2021 Nordix Foundation.
+# Modifications Copyright (C) 2021-2022 Nordix Foundation.
 # ================================================================================
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -340,6 +340,15 @@ class Proxy(SimpleHTTPServer.SimpleHTTPRequestHandler):
          with open(cached_file_content, 'w+') as f:
              f.write(self.data_string)
          return True
+     elif (self.path.startswith("/onap/policy/clamp/acm/v2/instanceProperties")) and http_type == "PUT":
+             print("self.path start with PUT /onap/policy/clamp/acm/v2/instanceProperties, updating body to response ...")
+             if not os.path.exists(cached_file_folder):
+                 os.makedirs(cached_file_folder, 0o777)
+             with open(cached_file_header, 'w+') as f:
+                 f.write("{\"Content-Length\": \"" + str(len(self.data_string)) + "\", \"Content-Type\": \""+str(self.headers['Content-Type'])+"\"}")
+             with open(cached_file_content, 'w+') as f:
+                 f.write(self.data_string)
+             return True
      elif (self.path.startswith("/onap/policy/clamp/acm/v2/instanceProperties")) and http_type == "DELETE":
          print("self.path start with /instanceProperties Deleting instance properties, generating response json...")
          jsonGenerated = "{\"errorDetails\": null,\"affectedControlLoopDefinitions\": [{ \"name\": \"PMSH_Instance1\", \"version\": \"2.3.1\" }]}"