Tosca compliant vFirewall

Issue-ID: POLICY-2376
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
Change-Id: I362ebbd941c400a6ffc3e952e66ca2d624afbfdd
Signed-off-by: jhh <jorge.hernandez-herrero@att.com>
diff --git a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/VfwTest.java b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/VfwTest.java
index 202bd30..3796f0b 100644
--- a/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/VfwTest.java
+++ b/controlloop/common/controller-usecases/src/test/java/org/onap/policy/controlloop/VfwTest.java
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * ONAP
  * ================================================================================
- * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2019-2020 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -43,7 +43,8 @@
     /**
      * VFW Tosca Policy File.
      */
-    private static final String TOSCA_POLICY_VFW = "src/test/resources/vfw/tosca-vfw.json";
+    private static final String TOSCA_LEGACY_POLICY_VFW = "src/test/resources/vfw/tosca-vfw.json";
+    private static final String TOSCA_COMPLIANT_POLICY_VFW = "src/test/resources/vfw/tosca-compliant-vfw.json";
 
     /*
      * VFW Use case Messages.
@@ -85,8 +86,7 @@
     /**
      * Sunny day scenario for the VFW use case.
      */
-    @Test
-    public void sunnyDay() throws IOException {
+    private void sunnyDay() throws IOException {
 
         /* Inject an ONSET event over the DCAE topic */
         injectOnTopic(DCAE_TOPIC, Paths.get(ONSET));
@@ -119,6 +119,30 @@
     }
 
     /**
+     * Sunny Day with Legacy Tosca Policy.
+     */
+    @Test
+    public void sunnyDayLegacy() throws InterruptedException, CoderException, IOException {
+        assertEquals(0, usecases.getDrools().factCount(USECASES));
+        policy = setupPolicy(TOSCA_LEGACY_POLICY_VFW);
+        assertEquals(2, usecases.getDrools().factCount(USECASES));
+
+        sunnyDay();
+    }
+
+    /**
+     * Sunny Day with Tosca Compliant Policy.
+     */
+    @Test
+    public void sunnyDayCompliant() throws InterruptedException, CoderException, IOException {
+        assertEquals(0, usecases.getDrools().factCount(USECASES));
+        policy = setupPolicy(TOSCA_COMPLIANT_POLICY_VFW);
+        assertEquals(2, usecases.getDrools().factCount(USECASES));
+
+        sunnyDay();
+    }
+
+    /**
      * Observe Topics.
      */
     @Before
@@ -147,16 +171,6 @@
     }
 
     /**
-     * Install Policy.
-     */
-    @Before
-    public void installPolicy() throws IOException, CoderException, InterruptedException {
-        assertEquals(0, usecases.getDrools().factCount(USECASES));
-        policy = setupPolicy(TOSCA_POLICY_VFW);
-        assertEquals(2, usecases.getDrools().factCount(USECASES));
-    }
-
-    /**
      * Uninstall Policy.
      */
     @After
diff --git a/controlloop/common/controller-usecases/src/test/resources/vcpe/tosca-compliant-vcpe.json b/controlloop/common/controller-usecases/src/test/resources/vcpe/tosca-compliant-vcpe.json
index c01f689..61fb8a6 100644
--- a/controlloop/common/controller-usecases/src/test/resources/vcpe/tosca-compliant-vcpe.json
+++ b/controlloop/common/controller-usecases/src/test/resources/vcpe/tosca-compliant-vcpe.json
@@ -19,7 +19,7 @@
                     "actor": "APPC",
                     "operation": "Restart",
                     "target": {
-                        "type": "VM"
+                        "targetType": "VM"
                     }
                 },
                 "timeout": 1200,
diff --git a/controlloop/common/controller-usecases/src/test/resources/vfw/tosca-compliant-vfw.json b/controlloop/common/controller-usecases/src/test/resources/vfw/tosca-compliant-vfw.json
new file mode 100644
index 0000000..c96b49c
--- /dev/null
+++ b/controlloop/common/controller-usecases/src/test/resources/vfw/tosca-compliant-vfw.json
@@ -0,0 +1,40 @@
+{
+    "type": "onap.policies.controlloop.operational.common.Drools",
+    "type_version": "1.0.0",
+    "name": "operational.modifyconfig",
+    "version": "1.0.0",
+    "metadata": {
+        "policy-id": "operational.modifyconfig"
+    },
+    "properties": {
+        "id": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
+        "timeout": 60,
+        "abatement": false,
+        "trigger": "unique-policy-id-1-modifyConfig",
+        "operations": [
+            {
+                "id": "unique-policy-id-1-modifyConfig",
+                "description": "Modify the packet generator",
+                "operation": {
+                    "actor": "APPC",
+                    "operation": "ModifyConfig",
+                    "target": {
+                        "targetType": "VNF",
+                        "entityIds": {
+                            "resourceID": "bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38"
+                        }
+                    }
+                },
+                "timeout": 300,
+                "retries": 0,
+                "success": "final_success",
+                "failure": "final_failure",
+                "failure_timeout": "final_failure_timeout",
+                "failure_retries": "final_failure_retries",
+                "failure_exception": "final_failure_exception",
+                "failure_guard": "final_failure_guard"
+            }
+        ],
+        "controllerName": "usecases"
+    }
+}
diff --git a/controlloop/common/domains/src/main/java/org/onap/policy/drools/models/domain/operational/OperationalTarget.java b/controlloop/common/domains/src/main/java/org/onap/policy/drools/models/domain/operational/OperationalTarget.java
index 9e570ba..66ae337 100644
--- a/controlloop/common/domains/src/main/java/org/onap/policy/drools/models/domain/operational/OperationalTarget.java
+++ b/controlloop/common/domains/src/main/java/org/onap/policy/drools/models/domain/operational/OperationalTarget.java
@@ -20,8 +20,9 @@
 
 package org.onap.policy.drools.models.domain.operational;
 
-import com.google.gson.annotations.SerializedName;
 import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
 import lombok.Builder;
 import lombok.Data;
 
@@ -38,11 +39,11 @@
     /**
      * Target Type.
      */
-    private String type;
+    private String targetType;
 
     /**
-     * Resource ID.
+     * Payload.
      */
-    @SerializedName("resourceID")
-    private String resourceId;
+    @Builder.Default
+    private Map<String, String> entityIds = new HashMap<>();
 }
diff --git a/controlloop/common/domains/src/main/resources/schemas/onap.policies.controlloop.operational.common.Drools-1.0.0.schema.json b/controlloop/common/domains/src/main/resources/schemas/onap.policies.controlloop.operational.common.Drools-1.0.0.schema.json
index e3569f1..5d032f0 100644
--- a/controlloop/common/domains/src/main/resources/schemas/onap.policies.controlloop.operational.common.Drools-1.0.0.schema.json
+++ b/controlloop/common/domains/src/main/resources/schemas/onap.policies.controlloop.operational.common.Drools-1.0.0.schema.json
@@ -190,11 +190,11 @@
                                         "type": "object",
                                         "title": "Target",
                                         "required": [
-                                            "type"
+                                            "targetType"
                                         ],
                                         "properties": {
-                                            "type": {
-                                                "$id": "#/properties/properties/properties/operations/items/properties/operation/properties/target/properties/type",
+                                            "targetType": {
+                                                "$id": "#/properties/properties/properties/operations/items/properties/operation/properties/target/properties/targetType",
                                                 "type": "string",
                                                 "title": "Target Type",
                                                 "examples": [
@@ -202,14 +202,17 @@
                                                 ],
                                                 "pattern": "^(.+)$"
                                             },
-                                            "resourceID": {
-                                                "$id": "#/properties/properties/properties/operations/items/properties/operation/properties/target/properties/resourceID",
-                                                "type": "string",
-                                                "title": "Resource ID",
+                                            "entityIds": {
+                                                "$id": "#/properties/properties/properties/operations/items/properties/operation/properties/target/properties/entityIds",
+                                                "type": "object",
+                                                "title": "Arbitrary Resource Identities",
                                                 "examples": [
                                                     "Eace933104d443b496b8.nodes.heat.vpg"
                                                 ],
-                                                "pattern": "^(.+)$"
+                                                "additionalProperties": {
+                                                    "type": "string",
+                                                    "pattern": "^(.+)$"
+                                                }
                                             }
                                         }
                                     },
@@ -218,7 +221,8 @@
                                         "type": "object",
                                         "title": "Payload",
                                         "additionalProperties": {
-                                            "type": "string"
+                                            "type": "string",
+                                            "pattern": "^(.+)$"
                                         }
                                     }
                                 }
diff --git a/controlloop/common/domains/src/test/java/org/onap/policy/drools/models/domain/operational/OperationalPolicyTest.java b/controlloop/common/domains/src/test/java/org/onap/policy/drools/models/domain/operational/OperationalPolicyTest.java
index bab22d9..7fc60f2 100644
--- a/controlloop/common/domains/src/test/java/org/onap/policy/drools/models/domain/operational/OperationalPolicyTest.java
+++ b/controlloop/common/domains/src/test/java/org/onap/policy/drools/models/domain/operational/OperationalPolicyTest.java
@@ -86,7 +86,7 @@
     }
 
     @Test
-    public void testToscaLegacyOperationalPolicyType() throws CoderException, IOException {
+    public void testToscaLegacyOperationalPolicyType() throws IOException {
         String rawVcpeToscaPolicy = getJsonFromFile(VCPE_OPERATIONAL_LEGACY_POLICY_JSON);
 
         // valid "known" policy type with implicit schema
@@ -119,7 +119,7 @@
                                                     .actorOperation(ActorOperation.builder()
                                                         .operation("Restart")
                                                         .actor("APPC")
-                                                        .target(OperationalTarget.builder().type("VNF").build())
+                                                        .target(OperationalTarget.builder().targetType("VNF").build())
                                                         .build())
                                                     .build()))
                                     .controllerName("usecases")
diff --git a/controlloop/common/eventmanager/pom.xml b/controlloop/common/eventmanager/pom.xml
index 23ac4a2..4f9bfb7 100644
--- a/controlloop/common/eventmanager/pom.xml
+++ b/controlloop/common/eventmanager/pom.xml
@@ -45,6 +45,11 @@
             <scope>provided</scope>
         </dependency>
         <dependency>
+            <!-- less than 1.9.4 has security vulnerabilities -->
+            <groupId>commons-beanutils</groupId>
+            <artifactId>commons-beanutils</artifactId>
+        </dependency>
+        <dependency>
             <groupId>org.onap.policy.models.policy-models-interactions.model-actors</groupId>
             <artifactId>actorServiceProvider</artifactId>
             <version>${policy.models.version}</version>
diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/processor/ControlLoopProcessor.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/processor/ControlLoopProcessor.java
index 4cff616..0015e4d 100644
--- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/processor/ControlLoopProcessor.java
+++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/processor/ControlLoopProcessor.java
@@ -22,9 +22,11 @@
 
 import java.io.Serializable;
 import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
 import java.net.URLDecoder;
 import java.util.stream.Collectors;
 import lombok.Getter;
+import org.apache.commons.beanutils.BeanUtils;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.controlloop.ControlLoopException;
 import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
@@ -39,13 +41,17 @@
 import org.onap.policy.drools.domain.models.DroolsPolicy;
 import org.onap.policy.drools.models.domain.legacy.LegacyPolicy;
 import org.onap.policy.drools.models.domain.operational.OperationalPolicy;
+import org.onap.policy.drools.models.domain.operational.OperationalTarget;
 import org.onap.policy.drools.system.PolicyEngineConstants;
 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.CustomClassLoaderConstructor;
 
 public class ControlLoopProcessor implements Serializable {
     private static final long serialVersionUID = 1L;
+    private static final Logger logger = LoggerFactory.getLogger(ControlLoopProcessor.class);
 
     private final ControlLoopPolicy policy;
     private String currentNestedPolicyId = null;
@@ -107,6 +113,16 @@
                         ControlLoopPolicy.class, ControlLoopPolicy.class.getClassLoader())).load(decodedPolicy);
     }
 
+    private Target toStandardTarget(OperationalTarget opTarget) {
+        Target target = new Target(TargetType.valueOf(opTarget.getTargetType()));
+        try {
+            BeanUtils.populate(target, opTarget.getEntityIds());
+        } catch (IllegalAccessException | InvocationTargetException e) {
+            logger.warn("target entityIds cannot be mapped (unexpected): {}", opTarget, e);
+        }
+        return target;
+    }
+
     protected ControlLoopPolicy buildPolicyFromToscaCompliant(ToscaPolicy policy) throws CoderException {
         OperationalPolicy domainPolicy =
                 PolicyEngineConstants.getManager().getDomainMaker().convertTo(policy, OperationalPolicy.class);
@@ -116,17 +132,17 @@
         // @formatter:off
         backwardsCompatiblePolicy.setPolicies(
             domainPolicy.getProperties().getOperations().stream().map(operation -> new Policy(
-                    PolicyParam.builder()
-                            .id(operation.getId())
-                            .name(operation.getActorOperation().getOperation())
-                            .description(operation.getDescription())
-                            .actor(operation.getActorOperation().getActor())
-                            .payload(operation.getActorOperation().getPayload())
-                            .recipe(operation.getActorOperation().getOperation())
-                            .retries(operation.getRetries())
-                            .timeout(operation.getTimeout())
-                            .target(new Target(TargetType.valueOf(operation.getActorOperation().getTarget().getType()),
-                                    operation.getActorOperation().getTarget().getResourceId())).build()))
+                        PolicyParam.builder()
+                                .id(operation.getId())
+                                .name(operation.getActorOperation().getOperation())
+                                .description(operation.getDescription())
+                                .actor(operation.getActorOperation().getActor())
+                                .payload(operation.getActorOperation().getPayload())
+                                .recipe(operation.getActorOperation().getOperation())
+                                .retries(operation.getRetries())
+                                .timeout(operation.getTimeout())
+                                .target(toStandardTarget(operation.getActorOperation().getTarget()))
+                                .build()))
                     .collect(Collectors.toList()));
         // @formatter:on
 
diff --git a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/processor/ControlLoopProcessorTest.java b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/processor/ControlLoopProcessorTest.java
index f76c006..a309147 100644
--- a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/processor/ControlLoopProcessorTest.java
+++ b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/processor/ControlLoopProcessorTest.java
@@ -45,6 +45,7 @@
 
 public class ControlLoopProcessorTest {
     private static final Logger logger = LoggerFactory.getLogger(ControlLoopProcessorTest.class);
+    private static final StandardCoder coder = new StandardCoder();
 
     @Test
     public void testControlLoopProcessor() throws IOException, ControlLoopException {
@@ -59,22 +60,27 @@
         String policy =
                 new String(Files.readAllBytes(Paths.get("src/test/resources/tosca-policy-legacy-vcpe.json")));
         assertNotNull(
-                new ControlLoopProcessor(new StandardCoder().decode(policy, ToscaPolicy.class)).getCurrentPolicy());
+                new ControlLoopProcessor(coder.decode(policy, ToscaPolicy.class)).getCurrentPolicy());
     }
 
     @Test
     public void testControlLoopFromToscaCompliant() throws IOException, CoderException, ControlLoopException {
         String policy =
-                new String(Files.readAllBytes(Paths.get("src/test/resources/tosca-policy-compliant-vcpe.json")));
+                  new String(Files.readAllBytes(Paths.get("src/test/resources/tosca-policy-compliant-vcpe.json")));
         assertNotNull(
-                new ControlLoopProcessor(new StandardCoder().decode(policy, ToscaPolicy.class)).getCurrentPolicy());
+                  new ControlLoopProcessor(coder.decode(policy, ToscaPolicy.class)).getCurrentPolicy());
+
+        policy =
+                new String(Files.readAllBytes(Paths.get("src/test/resources/tosca-policy-compliant-vfw.json")));
+        assertNotNull(
+                new ControlLoopProcessor(coder.decode(policy, ToscaPolicy.class)).getCurrentPolicy());
     }
 
     @Test
     public void testControlLoopFromToscaCompliantBad() throws IOException, CoderException, ControlLoopException {
         String policy =
                 new String(Files.readAllBytes(Paths.get("src/test/resources/tosca-policy-compliant-vcpe.json")));
-        ToscaPolicy toscaPolicy = new StandardCoder().decode(policy, ToscaPolicy.class);
+        ToscaPolicy toscaPolicy = coder.decode(policy, ToscaPolicy.class);
         toscaPolicy.setType("onap.policies.controlloop.Operational");
         assertThatThrownBy(() -> new ControlLoopProcessor(toscaPolicy)).hasCauseInstanceOf(CoderException.class);
     }
diff --git a/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vcpe.json b/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vcpe.json
index c01f689..61fb8a6 100644
--- a/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vcpe.json
+++ b/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vcpe.json
@@ -19,7 +19,7 @@
                     "actor": "APPC",
                     "operation": "Restart",
                     "target": {
-                        "type": "VM"
+                        "targetType": "VM"
                     }
                 },
                 "timeout": 1200,
diff --git a/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vfw.json b/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vfw.json
new file mode 100644
index 0000000..c96b49c
--- /dev/null
+++ b/controlloop/common/eventmanager/src/test/resources/tosca-policy-compliant-vfw.json
@@ -0,0 +1,40 @@
+{
+    "type": "onap.policies.controlloop.operational.common.Drools",
+    "type_version": "1.0.0",
+    "name": "operational.modifyconfig",
+    "version": "1.0.0",
+    "metadata": {
+        "policy-id": "operational.modifyconfig"
+    },
+    "properties": {
+        "id": "ControlLoop-vFirewall-d0a1dfc6-94f5-4fd4-a5b5-4630b438850a",
+        "timeout": 60,
+        "abatement": false,
+        "trigger": "unique-policy-id-1-modifyConfig",
+        "operations": [
+            {
+                "id": "unique-policy-id-1-modifyConfig",
+                "description": "Modify the packet generator",
+                "operation": {
+                    "actor": "APPC",
+                    "operation": "ModifyConfig",
+                    "target": {
+                        "targetType": "VNF",
+                        "entityIds": {
+                            "resourceID": "bbb3cefd-01c8-413c-9bdd-2b92f9ca3d38"
+                        }
+                    }
+                },
+                "timeout": 300,
+                "retries": 0,
+                "success": "final_success",
+                "failure": "final_failure",
+                "failure_timeout": "final_failure_timeout",
+                "failure_retries": "final_failure_retries",
+                "failure_exception": "final_failure_exception",
+                "failure_guard": "final_failure_guard"
+            }
+        ],
+        "controllerName": "usecases"
+    }
+}