Add new guard filter policy type feature 46/111346/2
authorPamela Dragosh <pdragosh@research.att.com>
Mon, 17 Aug 2020 20:45:30 +0000 (16:45 -0400)
committerPamela Dragosh <pdragosh@research.att.com>
Mon, 17 Aug 2020 23:41:07 +0000 (19:41 -0400)
* Added new Policy Guard filter Policy type.

* Enhanced translator tests to ensure bad filter policies
are detected.

* Added new filter application test to ensure new guard
propertly creates xacml policies.

Issue-ID: POLICY-2590
Change-Id: Ifc047a33084ce45b67be98a61f660d7a8c9d8615
Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
12 files changed:
applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java
applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPolicyRequest.java
applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardTranslator.java
applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplicationTest.java
applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPolicyRequestTest.java
applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardTranslatorTest.java
applications/guard/src/test/resources/requests/guard.filter.json [new file with mode: 0644]
applications/guard/src/test/resources/requests/guard.vfCount.json
applications/guard/src/test/resources/test-bad-policies.yaml
applications/guard/src/test/resources/test-policies.yaml
applications/guard/src/test/resources/test.policy.guard.filters.yaml [new file with mode: 0644]
main/src/test/java/org/onap/policy/pdpx/main/rest/XacmlPdpApplicationManagerTest.java

index 9f95476..982c14b 100644 (file)
@@ -58,6 +58,9 @@ public class GuardPdpApplication extends StdXacmlApplicationServiceProvider {
         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(
                 GuardTranslator.POLICYTYPE_BLACKLIST,
                 STRING_VERSION100));
+        this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(
+                GuardTranslator.POLICYTYPE_FILTER,
+                STRING_VERSION100));
         this.supportedPolicyTypes.add(new ToscaPolicyTypeIdentifier(
                 "onap.policies.controlloop.guard.coordination.FirstBlocksSecond",
                 STRING_VERSION100));
index c516877..72c8ddd 100644 (file)
@@ -70,6 +70,26 @@ public class GuardPolicyRequest {
     @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:vf-count")
     private Integer vfCount;
 
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:generic-vnf.vnf-name")
+    private String vnfName;
+
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:generic-vnf.vnf-id")
+    private String vnfId;
+
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:generic-vnf.vnf-type")
+    private String vnfType;
+
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:generic-vnf.nf-naming-code")
+    private String vnfNfNamingCode;
+
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:vserver.vserver-id")
+    private String vserverId;
+
+    @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:cloud-region.cloud-region-id")
+    private String cloudRegionId;
+
+    public static final String PREFIX_RESOURCE_ATTRIBUTE_ID = "urn:org:onap:guard:target:";
+
     public GuardPolicyRequest() {
         super();
     }
@@ -138,6 +158,24 @@ public class GuardPolicyRequest {
                 throw new ToscaPolicyConversionException("Failed to decode vfCount", e);
             }
         }
+        if (guard.containsKey("generic-vnf.vnf-name")) {
+            request.vnfName = guard.get("generic-vnf.vnf-name").toString();
+        }
+        if (guard.containsKey("generic-vnf.vnf-id")) {
+            request.vnfId = guard.get("generic-vnf.vnf-id").toString();
+        }
+        if (guard.containsKey("generic-vnf.vnf-type")) {
+            request.vnfType = guard.get("generic-vnf.vnf-type").toString();
+        }
+        if (guard.containsKey("generic-vnf.nf-naming-code")) {
+            request.vnfNfNamingCode = guard.get("generic-vnf.nf-naming-code").toString();
+        }
+        if (guard.containsKey("vserver.vserver-id")) {
+            request.vserverId = guard.get("vserver.vserver-id").toString();
+        }
+        if (guard.containsKey("cloud-region.cloud-region-id")) {
+            request.cloudRegionId = guard.get("cloud-region.cloud-region-id").toString();
+        }
 
         return request;
     }
index 8699fec..b3ee36b 100644 (file)
@@ -29,6 +29,7 @@ import com.att.research.xacml.api.Request;
 import com.att.research.xacml.api.Response;
 import com.att.research.xacml.api.Result;
 import com.att.research.xacml.api.XACML3;
+import com.att.research.xacml.std.IdentifierImpl;
 import com.att.research.xacml.std.annotations.RequestParser;
 import java.util.Collection;
 import java.util.Map;
@@ -85,9 +86,21 @@ public class GuardTranslator implements ToscaPolicyTranslator {
     //
     public static final String FIELD_BLACKLIST = "blacklist";
 
+    //
+    // filter property fields
+    //
+    public static final String FIELD_FILTER_WHITELIST = "whitelist";
+    public static final String FIELD_FILTER_ALGORITHM = "algorithm";
+    public static final String FIELD_FILTER_FILTERS = "filters";
+    public static final String FIELD_FILTER_FIELD = "field";
+    public static final String FIELD_FILTER_FUNCTION = "function";
+    public static final String FIELD_FILTER_FILTER = "filter";
+    public static final String FIELD_FILTER_BLACKLIST = "blacklist";
+
     public static final String POLICYTYPE_FREQUENCY = "onap.policies.controlloop.guard.common.FrequencyLimiter";
     public static final String POLICYTYPE_MINMAX = "onap.policies.controlloop.guard.common.MinMax";
     public static final String POLICYTYPE_BLACKLIST = "onap.policies.controlloop.guard.common.Blacklist";
+    public static final String POLICYTYPE_FILTER = "onap.policies.controlloop.guard.common.Filter";
 
     public GuardTranslator() {
         super();
@@ -132,6 +145,9 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         } else if (POLICYTYPE_BLACKLIST.equals(toscaPolicy.getType())) {
             newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
             generateBlacklistRules(toscaPolicy, policyName, newPolicyType);
+        } else if (POLICYTYPE_FILTER.equals(toscaPolicy.getType())) {
+            newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_UNLESS_DENY.stringValue());
+            generateFilterRules(toscaPolicy, policyName, newPolicyType);
         } else {
             throw new ToscaPolicyConversionException("Unknown guard policy type " + toscaPolicy.getType());
         }
@@ -513,4 +529,169 @@ public class GuardTranslator implements ToscaPolicyTranslator {
         newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(blacklistRule);
     }
 
-}
+    @SuppressWarnings("unchecked")
+    protected void generateFilterRules(ToscaPolicy toscaPolicy, String policyName, PolicyType newPolicyType)
+            throws ToscaPolicyConversionException {
+        //
+        // Validate the algorithm
+        //
+        if (! toscaPolicy.getProperties().containsKey(FIELD_FILTER_ALGORITHM)) {
+            throw new ToscaPolicyConversionException("Missing algorithm");
+        }
+        Object algorithm = toscaPolicy.getProperties().get(FIELD_FILTER_ALGORITHM);
+        if ("whitelist-overrides".equals(algorithm.toString())) {
+            newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_PERMIT_OVERRIDES.stringValue());
+        } else if ("blacklist-overrides".equals(algorithm.toString())) {
+            newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_OVERRIDES.stringValue());
+        } else {
+            throw new ToscaPolicyConversionException(
+                    "Unexpected value for algorithm, should be whitelist-overrides or blacklist-overrides");
+        }
+        //
+        // Validate the filters exist and have the right properties
+        //
+        if (! toscaPolicy.getProperties().containsKey(FIELD_FILTER_FILTERS)) {
+            throw new ToscaPolicyConversionException("Missing filters");
+        }
+        //
+        // Get the filters, which should be an array or collection.
+        //
+        Object arrayFilters = toscaPolicy.getProperties().get(FIELD_FILTER_FILTERS);
+        if (!(arrayFilters instanceof Collection)) {
+            throw new ToscaPolicyConversionException("Filters is not a collection");
+        }
+        //
+        // Iterate the filters
+        //
+        int ruleId = 1;
+        for (Object filterAttributes : ((Collection<?>) arrayFilters)) {
+            if (!(filterAttributes instanceof Map)) {
+                throw new ToscaPolicyConversionException("Filter should be a map");
+            }
+            //
+            // All fields must be there
+            //
+            String field = validateFilterPropertyField((Map<String, Object>) filterAttributes);
+            String filter = validateFilterPropertyFilter((Map<String, Object>) filterAttributes);
+            Identifier function = validateFilterPropertyFunction((Map<String, Object>) filterAttributes);
+            boolean isBlacklisted = validateFilterPropertyBlacklist((Map<String, Object>) filterAttributes);
+            //
+            // Create our filter rule
+            //
+            RuleType filterRule = createFilterRule(policyName + ":rule" + ruleId++, field, filter,
+                    function, isBlacklisted);
+            //
+            // Add the rule to the policy
+            //
+            newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(filterRule);
+        }
+    }
+
+    private String validateFilterPropertyField(Map<String, Object> filterAttributes)
+            throws ToscaPolicyConversionException {
+        Object field = filterAttributes.get(FIELD_FILTER_FIELD);
+        if (field != null) {
+            switch (field.toString().toLowerCase()) {
+                case "generic-vnf.vnf-name":
+                case "generic-vnf.vnf-id":
+                case "generic-vnf.vnf-type":
+                case "generic-vnf.nf-naming-code":
+                case "vserver.vserver-id":
+                case "cloud-region.cloud-region-id":
+                    return field.toString();
+                default:
+                    throw new ToscaPolicyConversionException("Unexpected value for field in filter");
+            }
+        }
+        throw new ToscaPolicyConversionException("Missing \'field\' from filter");
+    }
+
+    private String validateFilterPropertyFilter(Map<String, Object> filterAttributes)
+            throws ToscaPolicyConversionException {
+        Object filter = filterAttributes.get(FIELD_FILTER_FILTER);
+        if (filter != null) {
+            return filter.toString();
+        }
+        throw new ToscaPolicyConversionException("Missing \'filter\' from filter");
+    }
+
+    private Identifier validateFilterPropertyFunction(Map<String, Object> filterAttributes)
+            throws ToscaPolicyConversionException {
+        Object function = filterAttributes.get(FIELD_FILTER_FUNCTION);
+        if (function != null) {
+            switch (function.toString().toLowerCase()) {
+                case "string-equal":
+                    return XACML3.ID_FUNCTION_STRING_EQUAL;
+                case "string-equal-ignore-case":
+                    return XACML3.ID_FUNCTION_STRING_EQUAL_IGNORE_CASE;
+                case "string-regexp-match":
+                    return XACML3.ID_FUNCTION_STRING_REGEXP_MATCH;
+                case "string-contains":
+                    return XACML3.ID_FUNCTION_STRING_CONTAINS;
+                case "string-greater-than":
+                    return XACML3.ID_FUNCTION_STRING_GREATER_THAN;
+                case "string-greater-than-or-equal":
+                    return XACML3.ID_FUNCTION_STRING_GREATER_THAN_OR_EQUAL;
+                case "string-less-than":
+                    return XACML3.ID_FUNCTION_STRING_LESS_THAN;
+                case "string-less-than-or-equal":
+                    return XACML3.ID_FUNCTION_STRING_LESS_THAN_OR_EQUAL;
+                case "string-starts-with":
+                    return XACML3.ID_FUNCTION_STRING_STARTS_WITH;
+                case "string-ends-with":
+                    return XACML3.ID_FUNCTION_STRING_ENDS_WITH;
+                default:
+                    throw new ToscaPolicyConversionException("Unexpected value for function in filter");
+            }
+        }
+        throw new ToscaPolicyConversionException("Missing \'function\' from filter");
+    }
+
+    private boolean validateFilterPropertyBlacklist(Map<String, Object> filterAttributes)
+            throws ToscaPolicyConversionException {
+        Object filter = filterAttributes.get(FIELD_FILTER_BLACKLIST);
+        if (filter != null) {
+            if ("true".equalsIgnoreCase(filter.toString())) {
+                return true;
+            }
+            if ("false".equalsIgnoreCase(filter.toString())) {
+                return false;
+            }
+            throw new ToscaPolicyConversionException("Unexpected value for blacklist in filter");
+        }
+        throw new ToscaPolicyConversionException("Missing \'blacklist\' from filter");
+    }
+
+    private RuleType createFilterRule(String ruleId, String field, String filter, Identifier function,
+            boolean isBlacklisted) {
+        RuleType rule = new RuleType();
+        rule.setRuleId(ruleId);
+
+        //
+        // Create the Match
+        //
+        MatchType matchFilter = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+                function,
+                filter,
+                XACML3.ID_DATATYPE_STRING,
+                new IdentifierImpl(GuardPolicyRequest.PREFIX_RESOURCE_ATTRIBUTE_ID + field),
+                XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE
+                );
+        AllOfType allOf = new AllOfType();
+        allOf.getMatch().add(matchFilter);
+        AnyOfType anyOf = new AnyOfType();
+        anyOf.getAllOf().add(allOf);
+        TargetType target = new TargetType();
+        target.getAnyOf().add(anyOf);
+
+        rule.setTarget(target);
+
+        if (isBlacklisted) {
+            rule.setEffect(EffectType.DENY);
+        } else {
+            rule.setEffect(EffectType.PERMIT);
+        }
+        return rule;
+    }
+
+}
\ No newline at end of file
index e83f4d2..08495a7 100644 (file)
@@ -217,7 +217,7 @@ public class GuardPdpApplicationTest {
         // can support the correct policy types.
         //
         assertThat(service.supportedPolicyTypes()).isNotEmpty();
-        assertThat(service.supportedPolicyTypes().size()).isEqualTo(4);
+        assertThat(service.supportedPolicyTypes().size()).isEqualTo(5);
         assertThat(service.canSupportPolicyType(
                 new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.FrequencyLimiter", "1.0.0")))
                         .isTrue();
@@ -237,6 +237,8 @@ public class GuardPdpApplicationTest {
         assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier(
                 "onap.policies.controlloop.guard.coordination.FirstBlocksSecond", "1.0.1"))).isFalse();
         assertThat(service.canSupportPolicyType(new ToscaPolicyTypeIdentifier("onap.foo", "1.0.1"))).isFalse();
+        assertThat(service.canSupportPolicyType(
+                new ToscaPolicyTypeIdentifier("onap.policies.controlloop.guard.common.Filter", "1.0.0"))).isTrue();
     }
 
     @Test
@@ -352,6 +354,77 @@ public class GuardPdpApplicationTest {
         requestAndCheckDecision(requestVfCount, DENY);
     }
 
+    @SuppressWarnings("unchecked")
+    @Test
+    public void test6Filters() throws Exception {
+        LOGGER.info("**************** Running test6Filters ****************");
+        //
+        // Re-Load Decision Request - so we can start from scratch
+        //
+        requestVfCount =
+                gson.decode(TextFileUtils.getTextFileAsString("src/test/resources/requests/guard.vfCount.json"),
+                        DecisionRequest.class);
+        //
+        // Ensure we are a permit to start
+        //
+        requestAndCheckDecision(requestVfCount, PERMIT);
+        //
+        // Load the filter policy in with the others.
+        //
+        List<ToscaPolicy> loadedPolicies =
+                TestUtils.loadPolicies("src/test/resources/test.policy.guard.filters.yaml", service);
+        assertThat(loadedPolicies).hasSize(2);
+        //
+        // Although the region is blacklisted, the id is not
+        //
+        requestAndCheckDecision(requestVfCount, PERMIT);
+        //
+        // Put in a different vnf id
+        //
+        ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("generic-vnf.vnf-id",
+                "different-vnf-id-should-be-denied");
+        //
+        // The region is blacklisted, and the id is not allowed
+        //
+        requestAndCheckDecision(requestVfCount, DENY);
+        //
+        // Let's switch to a different region
+        //
+        ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("cloud-region.cloud-region-id",
+                "RegionTwo");
+        //
+        // The region is whitelisted, and the id is also allowed
+        //
+        requestAndCheckDecision(requestVfCount, PERMIT);
+        //
+        // Put in a blacklisted vnf id
+        //
+        ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("generic-vnf.vnf-id",
+                "f17face5-69cb-4c88-9e0b-7426db7edddd");
+        //
+        // Although region is whitelisted,  the id is blacklisted
+        //
+        requestAndCheckDecision(requestVfCount, DENY);
+        //
+        // Let's switch to a different region
+        //
+        ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("cloud-region.cloud-region-id",
+                "RegionThree");
+        //
+        // There is no filter for this region, but the id is still blacklisted
+        //
+        requestAndCheckDecision(requestVfCount, DENY);
+        //
+        // Put in a different vnf id
+        //
+        ((Map<String, Object>) requestVfCount.getResource().get("guard")).put("generic-vnf.vnf-id",
+                "different-vnf-id-should-be-permitted");
+        //
+        // There is no filter for this region, and the id is not blacklisted
+        //
+        requestAndCheckDecision(requestVfCount, PERMIT);
+    }
+
     @SuppressWarnings("unchecked")
     private void insertOperationEvent(DecisionRequest request) {
         //
index 41fd470..1c925ce 100644 (file)
@@ -28,6 +28,8 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
 import java.util.HashMap;
 import java.util.Map;
 import org.junit.Test;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.resources.TextFileUtils;
 import org.onap.policy.models.decisions.concepts.DecisionRequest;
 import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
 
@@ -92,4 +94,22 @@ public class GuardPolicyRequestTest {
             GuardPolicyRequest.createInstance(decisionRequest));
     }
 
+    @Test
+    public void testFilterResources() throws Exception {
+        StandardCoder gson = new StandardCoder();
+
+        DecisionRequest request = gson.decode(
+                TextFileUtils.getTextFileAsString("src/test/resources/requests/guard.filter.json"),
+                DecisionRequest.class);
+
+        GuardPolicyRequest guardRequest = GuardPolicyRequest.createInstance(request);
+
+        assertThat(guardRequest.getVnfName()).isEqualTo("my-name");
+        assertThat(guardRequest.getVnfId()).isEqualTo("my-id");
+        assertThat(guardRequest.getVnfType()).isEqualTo("my-type");
+        assertThat(guardRequest.getVnfNfNamingCode()).isEqualTo("my-naming-code");
+        assertThat(guardRequest.getVserverId()).isEqualTo("my-server-id");
+        assertThat(guardRequest.getCloudRegionId()).isEqualTo("my-region");
+    }
+
 }
index 6f7edac..07e60c6 100644 (file)
@@ -115,6 +115,7 @@ public class GuardTranslatorTest {
         //
         for (Map<String, ToscaPolicy> policies : completedJtst.getToscaTopologyTemplate().getPolicies()) {
             for (ToscaPolicy policy : policies.values()) {
+                LOGGER.info("Testing policy " + policy.getName());
                 if ("frequency-missing-properties".equals(policy.getName())) {
                     assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
                         translator.convertPolicy(policy)
@@ -135,6 +136,55 @@ public class GuardTranslatorTest {
                     assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
                         translator.convertPolicy(policy)
                     ).withMessageContaining("Missing blacklist");
+                } else if ("blacklist-noalgorithm".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Missing precedence");
+                } else if ("blacklist-badalgorithm".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class)
+                            .isThrownBy(() -> translator.convertPolicy(policy))
+                            .withMessageContaining(
+                                "Unexpected value for algorithm, should be whitelist-overrides or blacklist-overrides");
+                } else if ("filter-nofilter".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class)
+                            .isThrownBy(() -> translator.convertPolicy(policy))
+                            .withMessageContaining("Missing filters");
+                } else if ("filter-nocollection".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Filters is not a collection");
+                } else if ("filter-noarray".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Filters is not a collection");
+                } else if ("filter-missingfield".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Missing \'field\' from filter");
+                } else if ("filter-badfield".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Unexpected value for field in filter");
+                } else if ("filter-missingfilter".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Missing \'filter\' from filter");
+                } else if ("filter-missingfunction".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Missing \'function\' from filter");
+                } else if ("filter-badfunction".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Unexpected value for function in filter");
+                } else if ("filter-missingblacklist".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Missing \'blacklist\' from filter");
+                } else if ("filter-badblacklist".equals(policy.getName())) {
+                    assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() ->
+                        translator.convertPolicy(policy)
+                    ).withMessageContaining("Unexpected value for blacklist in filter");
                 }
             }
         }
@@ -190,6 +240,8 @@ public class GuardTranslatorTest {
                     validateMinMax(policy, xacmlPolicy);
                 } else if (GuardTranslator.POLICYTYPE_BLACKLIST.equals(policy.getType())) {
                     validateBlacklist(policy, xacmlPolicy);
+                } else if (GuardTranslator.POLICYTYPE_FILTER.equals(policy.getType())) {
+                    validateFilter(policy, xacmlPolicy);
                 }
             }
         }
@@ -322,4 +374,26 @@ public class GuardTranslatorTest {
         }
         assertThat(foundBlacklist).isTrue();
     }
+
+    private void validateFilter(ToscaPolicy policy, PolicyType xacmlPolicy) {
+        assertThat(xacmlPolicy.getRuleCombiningAlgId()).endsWith("-overrides");
+        for (Object rule : xacmlPolicy.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition()) {
+            if (! (rule instanceof RuleType)) {
+                continue;
+            }
+            assertThat(((RuleType) rule).getTarget()).isNotNull();
+            assertThat(((RuleType) rule).getTarget().getAnyOf()).hasSize(1);
+            for (AnyOfType anyOf : ((RuleType) rule).getTarget().getAnyOf()) {
+                assertThat(anyOf.getAllOf()).isNotEmpty();
+                for (AllOfType allOf : anyOf.getAllOf()) {
+                    assertThat(allOf.getMatch()).isNotEmpty();
+                    assertThat(allOf.getMatch()).hasSize(1);
+                    for (MatchType match : allOf.getMatch()) {
+                        assertThat(match.getAttributeDesignator().getAttributeId())
+                            .startsWith(GuardPolicyRequest.PREFIX_RESOURCE_ATTRIBUTE_ID);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/applications/guard/src/test/resources/requests/guard.filter.json b/applications/guard/src/test/resources/requests/guard.filter.json
new file mode 100644 (file)
index 0000000..710cf65
--- /dev/null
@@ -0,0 +1,22 @@
+{
+  "ONAPName": "Policy",
+  "ONAPComponent": "drools-pdp",
+  "ONAPInstance": "usecase-template",
+  "requestId": "unique-request-id-1",
+  "action": "guard",
+  "resource": {
+      "guard": {
+          "actor": "SO",
+          "operation": "VF Module Create",
+          "clname": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
+          "target": "e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e",
+          "vfCount": "0",
+          "generic-vnf.vnf-name": "my-name",
+          "generic-vnf.vnf-id": "my-id",
+          "generic-vnf.vnf-type": "my-type",
+          "generic-vnf.nf-naming-code": "my-naming-code",
+          "vserver.vserver-id": "my-server-id",
+          "cloud-region.cloud-region-id": "my-region"
+      }
+  }
+}
index 1a0a6e5..86a0a96 100644 (file)
           "operation": "VF Module Create",
           "clname": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3",
           "target": "e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e",
-          "vfCount": "0"
+          "vfCount": "0",
+          "generic-vnf.vnf-name": "Ete_vFWCLvFWSNK_7ba1fbde_0",
+          "generic-vnf.vnf-id": "e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e",
+          "generic-vnf.vnf-type": "vFWCL 2019-05-01 15:30:/vFWCL_vFWSNK bbefb8ce-2bde 0",
+          "generic-vnf.nf-naming-code": "aabbccddee",
+          "vserver.vserver-id": "e591441a-e649-4490-82e0-07dac05d674b",
+          "cloud-region.cloud-region-id": "RegionOne"
       }
   }
 }
index df2431d..07040c5 100644 (file)
 tosca_definitions_version: tosca_simple_yaml_1_1_0
 topology_template:
-  policies:
-    -
-      frequency-missing-properties:
-        type: onap.policies.controlloop.guard.common.FrequencyLimiter
-        type_version: 1.0.0
-        version: 1.0.0
-    -
-      frequency-timewindow:
-        type: onap.policies.controlloop.guard.common.FrequencyLimiter
-        type_version: 1.0.0
-        version: 1.0.0
-        properties:
+   policies:
+   -  frequency-missing-properties:
+         type: onap.policies.controlloop.guard.common.FrequencyLimiter
+         type_version: 1.0.0
+         version: 1.0.0
+   -  frequency-timewindow:
+         type: onap.policies.controlloop.guard.common.FrequencyLimiter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
             limit: 5
             timeWindow: i am a bad value
-    -
-      minmax-notarget:
-        type: onap.policies.controlloop.guard.common.MinMax
-        type_version: 1.0.0
-        version: 1.0.0
-        properties:
-    -
-      minmax-nominmax:
-        type: onap.policies.controlloop.guard.common.MinMax
-        type_version: 1.0.0
-        version: 1.0.0
-        properties:
+   -  minmax-notarget:
+         type: onap.policies.controlloop.guard.common.MinMax
+         type_version: 1.0.0
+         version: 1.0.0
+         properties: null
+   -  minmax-nominmax:
+         type: onap.policies.controlloop.guard.common.MinMax
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
             target: foo
-    -
-      blacklist-noblacklist:
-        type: onap.policies.controlloop.guard.common.Blacklist
-        type_version: 1.0.0
-        version: 1.0.0
-        properties:
+   -  blacklist-noblacklist:
+         type: onap.policies.controlloop.guard.common.Blacklist
+         type_version: 1.0.0
+         version: 1.0.0
+         properties: null
+   -  filter-noalgorithm:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties: null
+   -  filter-badalgorithm:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: idontknow
+   -  filter-nofilter:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: whitelist-overrides
+   -  filter-nocollection:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters: vnf1
+   -  filter-noarray:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+               field: geo
+   -  filter-missingfield:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  filter: foo
+   -  filter-badfield:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: notinaai
+   -  filter-missingfilter:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: generic-vnf.vnf-name
+   -  filter-missingfunction:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: generic-vnf.vnf-name
+               filter: vfwl*
+   -  filter-badfunction:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: generic-vnf.vnf-name
+               filter: vfwl*
+               function: notafunction
+   -  filter-missingblacklist:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: generic-vnf.vnf-name
+               filter: vfwl*
+               function: string-equal
+   -  filter-badblacklist:
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            algorithm: blacklist-overrides
+            filters:
+            -  field: generic-vnf.vnf-name
+               filter: vfwl*
+               function: string-equal
+               blacklist: shouldbeboolean
\ No newline at end of file
index 1ac7271..e33f116 100644 (file)
@@ -99,6 +99,60 @@ topology_template:
           blacklist:
               - vnf1
               - vnf2
+    -
+      filter-1:
+        type: onap.policies.controlloop.guard.common.Filter
+        type_version: 1.0.0
+        version: 1.0.0
+        metadata:
+          policy-id : filter-1
+          policy-version: 1.0.0
+        properties:
+          actor: APPC
+          operation: "*"
+          id: loop-1
+          algorithm: blacklist-overrides
+          filters:
+          - field: "generic-vnf.vnf-id"
+            function: "string-equal"
+            filter: "vf-module-id-2"
+            blacklist: true
+          - field: "generic-vnf.vnf-name"
+            function: "string-equal-ignore-case"
+            filter: "vf-MODULE-id-2"
+            blacklist: true
+          - field: "generic-vnf.vnf-type"
+            function: "string-starts-with"
+            filter: "vf-module"
+            blacklist: true
+          - field: "generic-vnf.nf-naming-code"
+            function: "string-regexp-match"
+            filter: "[0-9][a-zA-Z]+"
+            blacklist: true
+          - field: "vserver.vserver-id"
+            function: "string-contains"
+            filter: "myserver"
+            blacklist: true
+          - field: "cloud-region.cloud-region-id"
+            function: "string-ends-with"
+            filter: "mycloud"
+            blacklist: false
+          - field: "cloud-region.cloud-region-id"
+            function: "string-greater-than"
+            filter: "00"
+            blacklist: false
+          - field: "cloud-region.cloud-region-id"
+            function: "string-greater-than-or-equal"
+            filter: "00"
+            blacklist: false
+          - field: "cloud-region.cloud-region-id"
+            function: "string-less-than"
+            filter: "99"
+            blacklist: false
+          - field: "cloud-region.cloud-region-id"
+            function: "string-less-than-or-equal"
+            filter: "99"
+            blacklist: false
     -
       unknown-1:
         type: onap.policies.controlloop.guard.common.Unknown
diff --git a/applications/guard/src/test/resources/test.policy.guard.filters.yaml b/applications/guard/src/test/resources/test.policy.guard.filters.yaml
new file mode 100644 (file)
index 0000000..261ffbe
--- /dev/null
@@ -0,0 +1,39 @@
+tosca_definitions_version: tosca_simple_yaml_1_1_0
+topology_template:
+   policies:
+   -  filter.block.region.allow.one.vnf:
+         description: Block this region from Control Loop actions, but allow a specific vnf.
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            actor: SO
+            operation: VF Module Create
+            algorithm: whitelist-overrides
+            filters:
+            -  field: cloud-region.cloud-region-id
+               filter: RegionOne
+               function: string-equal
+               blacklist: true
+            -  field: generic-vnf.vnf-id
+               filter: e6130d03-56f1-4b0a-9a1d-e1b2ebc30e0e
+               function: string-equal
+               blacklist: false
+   -  filter.allow.region.block.one.vnf:
+         description: allow this region to do Control Loop actions, but block a specific vnf.
+         type: onap.policies.controlloop.guard.common.Filter
+         type_version: 1.0.0
+         version: 1.0.0
+         properties:
+            actor: SO
+            operation: VF Module Create
+            algorithm: blacklist-overrides
+            filters:
+            -  field: cloud-region.cloud-region-id
+               filter: RegionTwo
+               function: string-equal
+               blacklist: false
+            -  field: generic-vnf.vnf-id
+               filter: f17face5-69cb-4c88-9e0b-7426db7edddd
+               function: string-equal
+               blacklist: true
\ No newline at end of file
index 2a85579..cd7041e 100644 (file)
@@ -142,10 +142,10 @@ public class XacmlPdpApplicationManagerTest {
         //
         assertThat(manager).isNotNull();
         assertThat(manager.getPolicyCount()).isZero();
-        assertThat(manager.getPolicyTypeCount()).isEqualTo(19);
+        assertThat(manager.getPolicyTypeCount()).isEqualTo(20);
         assertThat(manager.getToscaPolicies()).isEmpty();
         assertThat(manager.getToscaPolicyIdentifiers()).isEmpty();
-        assertThat(manager.getToscaPolicyTypeIdents()).hasSize(19);
+        assertThat(manager.getToscaPolicyTypeIdents()).hasSize(20);
 
         assertThat(manager.findNativeApplication()).isInstanceOf(NativePdpApplication.class);