summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPamela Dragosh <pdragosh@research.att.com>2019-10-28 08:51:10 -0400
committerPamela Dragosh <pdragosh@research.att.com>2019-10-28 14:06:51 -0400
commit0b278005ad98bcd862bd348d08f664005e9eda60 (patch)
treefdb6050e35a0d387a89b770f6165aa03b8a8de78
parentad4196a174dbf52e575ada6e450613dbfe637284 (diff)
Optimization improvements and test cases
* StdBaseTranslator added helpful support methods and can now add obligations to either rule, policy or policy sets. * StdMatchablePolicyRequest improved to support optional policy-type as part of the request to refine the output results. * Added more tests to ensure that the decision is returning the appropriate results. * Added more Javadoc for code. * Added some sonar fix for either log or throw exception. Issue-ID: POLICY-2066 Change-Id: I90d6d90c2cdbb627e96cfce1d2632b2439a1e477 Signed-off-by: Pamela Dragosh <pdragosh@research.att.com>
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java155
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java22
-rw-r--r--applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java153
-rw-r--r--applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java282
-rw-r--r--applications/optimization/src/test/resources/decision.optimization.input.json (renamed from main/src/test/resources/decisions/decision.optimization.affinity.input.json)4
-rw-r--r--applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml22
6 files changed, 576 insertions, 62 deletions
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java
index 48da9969..d2d383b9 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdBaseTranslator.java
@@ -28,16 +28,23 @@ import com.att.research.xacml.api.Obligation;
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.google.gson.Gson;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ApplyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeDesignatorType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.ConditionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.EffectType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.MatchType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObjectFactory;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.ObligationExpressionsType;
+import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicySetType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType;
import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType;
import org.onap.policy.models.decisions.concepts.DecisionRequest;
@@ -46,6 +53,7 @@ import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
import org.onap.policy.pdp.xacml.application.common.ToscaDictionary;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException;
import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator;
+import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslatorUtils;
import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -99,6 +107,13 @@ public class StdBaseTranslator implements ToscaPolicyTranslator {
return decisionResponse;
}
+ /**
+ * scanObligations - scans the list of obligations and make appropriate method calls to process
+ * obligations.
+ *
+ * @param obligations Collection of obligation objects
+ * @param decisionResponse DecisionResponse object used to store any results from obligations.
+ */
protected void scanObligations(Collection<Obligation> obligations, DecisionResponse decisionResponse) {
for (Obligation obligation : obligations) {
LOGGER.info("Obligation: {}", obligation);
@@ -109,6 +124,12 @@ public class StdBaseTranslator implements ToscaPolicyTranslator {
}
}
+ /**
+ * processObligationAttribute - processes an individual obligation attribute assignment object.
+ *
+ * @param assignment AttributeAssignment object
+ * @param decisionResponse DecisionResponse object used to store any results from attribute assignment.
+ */
@SuppressWarnings("unchecked")
protected void processObligationAttribute(AttributeAssignment assignment, DecisionResponse decisionResponse) {
//
@@ -169,11 +190,21 @@ public class StdBaseTranslator implements ToscaPolicyTranslator {
return policy;
}
- protected RuleType addObligation(RuleType rule, String jsonPolicy) {
+ /**
+ * addObligation - general code to add a json policy as an obligation. Probably could just
+ * return the obligation only instead of adding it directly to a rule/policy/policyset.
+ * But this is fine for now.
+ *
+ * @param <T> RuleType, PolicyType, PolicySetType object
+ * @param ruleOrPolicy Incoming RuleType, PolicyType, PolicySetType object
+ * @param jsonPolicy JSON String representation of policy.
+ * @return Return the Incoming RuleType, PolicyType, PolicySetType object for convenience.
+ */
+ protected <T> T addObligation(T ruleOrPolicy, String jsonPolicy) {
//
- // Convert the YAML Policy to JSON Object
+ // Creating obligation for returning policy
//
- LOGGER.info("JSON Optimization Policy {}{}", XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
+ LOGGER.info("Obligation Policy {}{}", XacmlPolicyUtils.LINE_SEPARATOR, jsonPolicy);
//
// Create an AttributeValue for it
//
@@ -196,12 +227,124 @@ public class StdBaseTranslator implements ToscaPolicyTranslator {
obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue());
obligation.getAttributeAssignmentExpression().add(expressionType);
//
- // Now we can add it into the rule
+ // Now we can add it into the rule/policy/policyset
//
ObligationExpressionsType obligations = new ObligationExpressionsType();
obligations.getObligationExpression().add(obligation);
- rule.setObligationExpressions(obligations);
- return rule;
+ if (ruleOrPolicy instanceof RuleType) {
+ ((RuleType) ruleOrPolicy).setObligationExpressions(obligations);
+ } else if (ruleOrPolicy instanceof PolicyType) {
+ ((PolicyType) ruleOrPolicy).setObligationExpressions(obligations);
+ } else if (ruleOrPolicy instanceof PolicySetType) {
+ ((PolicySetType) ruleOrPolicy).setObligationExpressions(obligations);
+ }
+ //
+ // Return as a convenience
+ //
+ return ruleOrPolicy;
+ }
+
+ /**
+ * generateAnyOfForPolicyType - Creates a specific AnyOfType that includes the check
+ * to match on a specific TOSCA Policy Type.
+ *
+ * @param type String represenatation of TOSCA Policy Type (eg. "onap.policies.Foo")
+ * @return AnyOfType object
+ */
+ protected AnyOfType generateAnyOfForPolicyType(String type) {
+ //
+ // Create the match for the policy type
+ //
+ MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator(
+ XACML3.ID_FUNCTION_STRING_EQUAL,
+ type,
+ XACML3.ID_DATATYPE_STRING,
+ ToscaDictionary.ID_RESOURCE_POLICY_TYPE,
+ XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
+ //
+ // Add it to an AnyOfType object
+ //
+ AnyOfType anyOf = new AnyOfType();
+ anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match));
+ //
+ // Return new AnyOfType
+ //
+ return anyOf;
+ }
+
+ /**
+ * generateConditionForPolicyType - create a ConditionType XACML object
+ * that is able to determine if a request specifies a specific policy type
+ * that the policy is created from, only then is the rule applied. If the
+ * request doesn't even care about the policy type (eg it is missing) then
+ * return the rule should not apply.
+ *
+ * @param type PolicyType (eg. onap.policies.Foo
+ * @return ConditionType object
+ */
+ protected ConditionType generateConditionForPolicyType(String type) {
+ //
+ // Create an ApplyType that checks if the request contains the
+ // policy-type attribute
+ //
+ AttributeDesignatorType designator = new AttributeDesignatorType();
+ designator.setAttributeId(ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue());
+ designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue());
+ designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
+
+ ApplyType applyBagSize = new ApplyType();
+ applyBagSize.setDescription("Get the size of policy-type attributes");
+ applyBagSize.setFunctionId(XACML3.ID_FUNCTION_STRING_BAG_SIZE.stringValue());
+
+ AttributeValueType valueZero = new AttributeValueType();
+ valueZero.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue());
+ valueZero.getContent().add("0"); // Yes really - represent as a string
+
+ ObjectFactory factory = new ObjectFactory();
+ applyBagSize.getExpression().add(factory.createAttributeDesignator(designator));
+
+ ApplyType applyGreaterThan = new ApplyType();
+ applyGreaterThan.setDescription("Does the policy-type attribute exist?");
+ applyGreaterThan.setFunctionId(XACML3.ID_FUNCTION_INTEGER_EQUAL.stringValue());
+
+ applyGreaterThan.getExpression().add(factory.createApply(applyBagSize));
+ applyGreaterThan.getExpression().add(factory.createAttributeValue(valueZero));
+
+ //
+ // Create an apply type that checks the actual value
+ //
+ AttributeValueType value = new AttributeValueType();
+ value.setDataType(XACML3.ID_DATATYPE_STRING.stringValue());
+ value.getContent().add(type);
+
+ //
+ // Create string-is-in apply - which determines if the policy-type
+ // is in the request bag of resources for policy-type
+ //
+ ApplyType applyIsIn = new ApplyType();
+ applyIsIn.setDescription("Is this policy-type in the list?");
+ applyIsIn.setFunctionId(XACML3.ID_FUNCTION_STRING_IS_IN.stringValue());
+ applyIsIn.getExpression().add(factory.createAttributeValue(value));
+ applyIsIn.getExpression().add(factory.createAttributeDesignator(designator));
+
+ //
+ // Create our outer apply
+ //
+ ApplyType applyOr = new ApplyType();
+ applyOr.setDescription("IF exists and is equal");
+ applyOr.setFunctionId(XACML3.ID_FUNCTION_OR.stringValue());
+
+ applyOr.getExpression().add(factory.createApply(applyGreaterThan));
+ applyOr.getExpression().add(factory.createApply(applyIsIn));
+
+ //
+ // Finally create the condition
+ //
+ ConditionType condition = new ConditionType();
+
+ condition.setExpression(factory.createApply(applyOr));
+
+ return condition;
}
}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java
index 0f3a0338..b478e8c1 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java
@@ -59,6 +59,8 @@ public class StdMatchablePolicyRequest {
private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchablePolicyRequest.class);
+ public static final String POLICY_TYPE_KEY = "policy-type";
+
@XACMLSubject(includeInResults = true)
private String onapName;
@@ -120,7 +122,7 @@ public class StdMatchablePolicyRequest {
try {
xacmlRequest = RequestParser.parseRequest(request);
} catch (IllegalAccessException | DataTypeException e) {
- throw new XacmlApplicationException("Could not parse request " + e.getLocalizedMessage());
+ throw new XacmlApplicationException("Could not parse request ", e);
}
//
// Create an object we can add to
@@ -134,18 +136,27 @@ public class StdMatchablePolicyRequest {
Map<String, Object> resources = decisionRequest.getResource();
for (Entry<String, Object> entrySet : resources.entrySet()) {
//
+ // Check for special policy-type
+ //
+ String attributeId;
+ if (POLICY_TYPE_KEY.equals(entrySet.getKey())) {
+ attributeId = ToscaDictionary.ID_RESOURCE_POLICY_TYPE.stringValue();
+ } else {
+ attributeId = ToscaDictionary.ID_RESOURCE_MATCHABLE + entrySet.getKey();
+ }
+ //
// Making an assumption that these fields are matchable.
// Its possible we may have to load the policy type model
// and use that to validate the fields that are matchable.
//
try {
if (entrySet.getValue() instanceof Collection) {
- addResources(resourceAttributes, (Collection) entrySet.getValue(), entrySet.getKey());
+ addResources(resourceAttributes, (Collection) entrySet.getValue(), attributeId);
} else {
- addResources(resourceAttributes, Arrays.asList(entrySet.getValue().toString()), entrySet.getKey());
+ addResources(resourceAttributes, Arrays.asList(entrySet.getValue().toString()), attributeId);
}
} catch (DataTypeException e) {
- throw new XacmlApplicationException("Failed to add resource " + e.getLocalizedMessage());
+ throw new XacmlApplicationException("Failed to add resource ", e);
}
}
mutableRequest.add(resourceAttributes);
@@ -162,7 +173,7 @@ public class StdMatchablePolicyRequest {
for (Object value : values) {
StdMutableAttribute mutableAttribute = new StdMutableAttribute();
mutableAttribute.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE);
- mutableAttribute.setAttributeId(new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + id));
+ mutableAttribute.setAttributeId(new IdentifierImpl(id));
mutableAttribute.setIncludeInResults(true);
DataType<?> dataTypeExtended = factory.getDataType(XACML3.ID_DATATYPE_STRING);
@@ -175,5 +186,4 @@ public class StdMatchablePolicyRequest {
}
return attributes;
}
-
}
diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java
index 5908f53b..7b47ad14 100644
--- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java
+++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java
@@ -109,12 +109,12 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
// Get the TOSCA Policy Type for this policy
//
- Collection<ToscaPolicyType> policyTypes = this.getPolicyTypes(toscaPolicy.getTypeIdentifier());
+ Collection<ToscaPolicyType> toscaPolicyTypes = this.getPolicyTypes(toscaPolicy.getTypeIdentifier());
//
- // If we don't have any policy types, then we cannot know
+ // If we don't have any TOSCA policy types, then we cannot know
// which properties are matchable.
//
- if (policyTypes.isEmpty()) {
+ if (toscaPolicyTypes.isEmpty()) {
throw new ToscaPolicyConversionException(
"Cannot retrieve Policy Type definition for policy " + toscaPolicy.getName());
}
@@ -134,7 +134,7 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
// There should be a metadata section
//
- this.fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
+ fillMetadataSection(newPolicyType, toscaPolicy.getMetadata());
//
// Set the combining rule
//
@@ -142,17 +142,7 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
// Generate the TargetType
//
- newPolicyType.setTarget(generateTargetType(toscaPolicy.getProperties(), policyTypes));
- //
- // Now create the Permit Rule
- // No target since the policy has a target
- // With obligations.
- //
- RuleType rule = new RuleType();
- rule.setDescription("Default is to PERMIT if the policy matches.");
- rule.setRuleId(policyName + ":rule");
- rule.setEffect(EffectType.PERMIT);
- rule.setTarget(new TargetType());
+ newPolicyType.setTarget(new TargetType());
//
// Now represent the policy as Json
//
@@ -163,13 +153,41 @@ public class StdMatchableTranslator extends StdBaseTranslator {
} catch (CoderException e) {
throw new ToscaPolicyConversionException("Failed to encode policy to json", e);
}
- addObligation(rule, jsonPolicy);
+ //
+ // Add it as an obligation
+ //
+ addObligation(newPolicyType, jsonPolicy);
+ //
+ // Now create the Permit Rule for all the
+ // matchable properties.
+ //
+ RuleType rule = new RuleType();
+ rule.setDescription("Default is to PERMIT if the policy matches.");
+ rule.setRuleId(policyName + ":rule");
+ rule.setEffect(EffectType.PERMIT);
+ rule.setTarget(generateTargetType(toscaPolicy.getProperties(), toscaPolicyTypes));
+ rule.setCondition(generateConditionForPolicyType(toscaPolicy.getType()));
+ //
+ // Add the rule to the policy
+ //
+ newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
+ //
+ // If a Decision is for a specific policy-type, make sure
+ // there is a rule for it.
+ //
+ rule = new RuleType();
+ rule.setDescription("Match on policy-type " + toscaPolicy.getType());
+ rule.setRuleId(policyName + ":rule:policy-type");
+ rule.setEffect(EffectType.PERMIT);
+ TargetType target = new TargetType();
+ target.getAnyOf().add(this.generateAnyOfForPolicyType(toscaPolicy.getType()));
+ rule.setTarget(target);
//
// Add the rule to the policy
//
newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule);
//
- // Return our new policy
+ // Log output of the policy
//
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
XACMLPolicyWriter.writePolicyFile(os, newPolicyType);
@@ -177,18 +195,20 @@ public class StdMatchableTranslator extends StdBaseTranslator {
} catch (IOException e) {
LOGGER.error("Failed to create byte array stream", e);
}
+ //
+ // Done
+ //
return newPolicyType;
}
/**
- * For generating target type, we are scan for matchable properties
+ * For generating target type, we scan for matchable properties
* and use those to build the policy.
*
* @param properties Properties section of policy
* @param policyTypes Collection of policy Type to find matchable metadata
* @return TargetType object
*/
- @SuppressWarnings("unchecked")
protected TargetType generateTargetType(Map<String, Object> properties, Collection<ToscaPolicyType> policyTypes) {
TargetType targetType = new TargetType();
//
@@ -200,25 +220,21 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
if (isMatchable(entrySet.getKey(), policyTypes)) {
LOGGER.info("Found matchable property {}", entrySet.getValue());
- if (entrySet.getValue() instanceof Collection) {
- AnyOfType anyOf = generateMatches((Collection<Object>) entrySet.getValue(),
- new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + entrySet.getKey()));
- if (! anyOf.getAllOf().isEmpty()) {
- targetType.getAnyOf().add(anyOf);
- }
- } else {
- AnyOfType anyOf = generateMatches(Arrays.asList(entrySet.getValue()),
- new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + entrySet.getKey()));
- if (! anyOf.getAllOf().isEmpty()) {
- targetType.getAnyOf().add(anyOf);
- }
- }
+ generateMatchable(targetType, entrySet.getKey(), entrySet.getValue());
}
}
return targetType;
}
+ /**
+ * isMatchable - Iterates through available TOSCA Policy Types to determine if a property
+ * should be treated as matchable.
+ *
+ * @param propertyName Name of property
+ * @param policyTypes Collection of TOSCA Policy Types to scan
+ * @return true if matchable
+ */
protected boolean isMatchable(String propertyName, Collection<ToscaPolicyType> policyTypes) {
for (ToscaPolicyType policyType : policyTypes) {
for (Entry<String, ToscaProperty> propertiesEntry : policyType.getProperties().entrySet()) {
@@ -236,6 +252,42 @@ public class StdMatchableTranslator extends StdBaseTranslator {
return false;
}
+ /**
+ * generateMatchable - Given the object, generates list of MatchType objects and add them
+ * to the TargetType object.
+ *
+ * @param targetType TargetType object to add matches to
+ * @param key Property key
+ * @param value Object is the value - which can be a Collection or single Object
+ * @return TargetType incoming TargetType returned as a convenience
+ */
+ @SuppressWarnings("unchecked")
+ protected TargetType generateMatchable(TargetType targetType, String key, Object value) {
+ if (value instanceof Collection) {
+ AnyOfType anyOf = generateMatches((Collection<Object>) value,
+ new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key));
+ if (! anyOf.getAllOf().isEmpty()) {
+ targetType.getAnyOf().add(anyOf);
+ }
+ } else {
+ AnyOfType anyOf = generateMatches(Arrays.asList(value),
+ new IdentifierImpl(ToscaDictionary.ID_RESOURCE_MATCHABLE + key));
+ if (! anyOf.getAllOf().isEmpty()) {
+ targetType.getAnyOf().add(anyOf);
+ }
+ }
+ return targetType;
+ }
+
+ /**
+ * generateMatches - Goes through the collection of objects, creates a MatchType object
+ * for each object and associates it with the given attribute Id. Returns the AnyOfType
+ * object that contains all the generated MatchType objects.
+ *
+ * @param matchables Collection of object to generate MatchType from
+ * @param attributeId Given attribute Id for each MatchType
+ * @return AnyOfType object
+ */
protected AnyOfType generateMatches(Collection<Object> matchables, Identifier attributeId) {
//
// This is our outer AnyOf - which is an OR
@@ -346,11 +398,17 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
childPolicyType = parentPolicyType;
}
-
-
return listTypes;
}
+ /**
+ * findPolicyType - given the ToscaPolicyTypeIdentifier, finds it in memory, or
+ * then tries to find it either locally on disk or pull it from the Policy
+ * Lifecycle API the given TOSCA Policy Type.
+ *
+ * @param policyTypeId ToscaPolicyTypeIdentifier to find
+ * @return ToscaPolicyType object. Can be null if failure.
+ */
private ToscaPolicyType findPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
//
// Is it loaded in memory?
@@ -368,6 +426,14 @@ public class StdMatchableTranslator extends StdBaseTranslator {
return policyType;
}
+ /**
+ * loadPolicyType - Tries to load the given ToscaPolicyTypeIdentifier from local
+ * storage. If it does not exist, will then attempt to pull from Policy Lifecycle
+ * API.
+ *
+ * @param policyTypeId ToscaPolicyTypeIdentifier input
+ * @return ToscaPolicyType object. Null if failure.
+ */
private ToscaPolicyType loadPolicyType(ToscaPolicyTypeIdentifier policyTypeId) {
//
// Construct what the file name should be
@@ -392,6 +458,10 @@ public class StdMatchableTranslator extends StdBaseTranslator {
//
return this.pullPolicyType(policyTypeId, policyTypePath);
}
+ //
+ // Success - we have read locally the policy type. Now bring it into our
+ // return object.
+ //
LOGGER.info("Read in local policy type {}", policyTypePath.toAbsolutePath());
try {
ToscaServiceTemplate serviceTemplate = standardYamlCoder.decode(new String(bytes, StandardCharsets.UTF_8),
@@ -432,6 +502,14 @@ public class StdMatchableTranslator extends StdBaseTranslator {
return null;
}
+ /**
+ * pullPolicyType - pulls the given ToscaPolicyTypeIdentifier from the Policy Lifecycle API.
+ * If successful, will store it locally given the policyTypePath.
+ *
+ * @param policyTypeId ToscaPolicyTypeIdentifier
+ * @param policyTypePath Path object to store locally
+ * @return ToscaPolicyType object. Null if failure.
+ */
private synchronized ToscaPolicyType pullPolicyType(ToscaPolicyTypeIdentifier policyTypeId, Path policyTypePath) {
//
// This is what we return
@@ -460,6 +538,13 @@ public class StdMatchableTranslator extends StdBaseTranslator {
return policyType;
}
+ /**
+ * constructLocalFilePath - common method to ensure the name of the local file for the
+ * policy type is the same.
+ *
+ * @param policyTypeId ToscaPolicyTypeIdentifier
+ * @return Path object
+ */
private Path constructLocalFilePath(ToscaPolicyTypeIdentifier policyTypeId) {
return Paths.get(this.pathForData.toAbsolutePath().toString(), policyTypeId.getName() + "-"
+ policyTypeId.getVersion() + ".yaml");
diff --git a/applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java b/applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java
index b84ec078..be553cf1 100644
--- a/applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java
+++ b/applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java
@@ -32,10 +32,16 @@ import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
+import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
import java.util.Properties;
import java.util.ServiceLoader;
+import jersey.repackaged.com.google.common.collect.Lists;
import org.apache.commons.lang3.tuple.Pair;
+import org.assertj.core.api.Condition;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
@@ -65,7 +71,7 @@ public class OptimizationPdpApplicationTest {
private static File propertiesFile;
private static XacmlApplicationServiceProvider service;
private static StandardCoder gson = new StandardCoder();
- private static DecisionRequest requestAffinity;
+ private static DecisionRequest baseRequest;
private static RestServerParameters clientParams;
private static String[] listPolicyTypeFiles = {
"onap.policies.Optimization",
@@ -95,10 +101,10 @@ public class OptimizationPdpApplicationTest {
//
// Load Single Decision Request
//
- requestAffinity = gson.decode(
+ baseRequest = gson.decode(
TextFileUtils
.getTextFileAsString(
- "../../main/src/test/resources/decisions/decision.optimization.affinity.input.json"),
+ "src/test/resources/decision.optimization.input.json"),
DecisionRequest.class);
//
// Setup our temporary folder
@@ -154,7 +160,7 @@ public class OptimizationPdpApplicationTest {
}
@Test
- public void test1Basics() {
+ public void test01Basics() {
//
// Make sure there's an application name
//
@@ -175,11 +181,11 @@ public class OptimizationPdpApplicationTest {
}
@Test
- public void test2NoPolicies() {
+ public void test02NoPolicies() {
//
- // Ask for a decision
+ // Ask for a decision when there are no policies loaded
//
- Pair<DecisionResponse, Response> decision = service.makeDecision(requestAffinity, null);
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
LOGGER.info("Decision {}", decision.getKey());
assertThat(decision.getKey()).isNotNull();
@@ -187,23 +193,275 @@ public class OptimizationPdpApplicationTest {
}
@Test
- public void test3AddOptimizationPolicies() throws CoderException, FileNotFoundException, IOException,
+ public void test03OptimizationDefault() throws CoderException, FileNotFoundException, IOException,
XacmlApplicationException {
//
- // Now load the optimization policies
+ // Now load all the optimization policies
//
TestUtils.loadPolicies("src/test/resources/vCPE.policies.optimization.input.tosca.yaml", service);
//
- // Ask for a decision
+ // Ask for a decision for default
//
- Pair<DecisionResponse, Response> decision = service.makeDecision(requestAffinity, null);
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(1);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test04OptimizationDefaultGeography() throws CoderException {
+ //
+ // Add US to the geography list
+ //
+ ((List<String>)baseRequest.getResource().get("geography")).add("US");
+ //
+ // Ask for a decision for default US Policy
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(2);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test05OptimizationDefaultGeographyAndService() throws CoderException {
+ //
+ // Add vCPE to the service list
+ //
+ ((List<String>)baseRequest.getResource().get("services")).add("vCPE");
+ //
+ // Ask for a decision for default US policy for vCPE service
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(5);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test06OptimizationDefaultGeographyAndServiceAndResource() throws CoderException {
+ //
+ // Add vCPE to the service list
+ //
+ ((List<String>)baseRequest.getResource().get("resources")).add("vG");
+ //
+ // Ask for a decision for default US service vCPE resource vG policy
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(9);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test07OptimizationGeographyAndServiceAndResourceAndScope() throws CoderException {
+ //
+ // Add gold as a scope
+ //
+ ((List<String>)baseRequest.getResource().get("scope")).add("gold");
+ //
+ // Ask for a decision for specific US vCPE vG gold
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(10);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test08OptimizationGeographyAndServiceAndResourceAndScopeIsGoldOrPlatinum() throws CoderException {
+ //
+ // Add platinum to the scope list: this is now gold OR platinum
+ //
+ ((List<String>)baseRequest.getResource().get("scope")).add("platinum");
+ //
+ // Ask for a decision for specific US vCPE vG (gold or platinum)
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(11);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void test09OptimizationGeographyAndServiceAndResourceAndScopeNotGold() throws CoderException {
+ //
+ // Add gold as a scope
+ //
+ ((List<String>)baseRequest.getResource().get("scope")).remove("gold");
+ //
+ // Ask for a decision for specific US vCPE vG gold
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(11);
+ //
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ //
+ // Validate it
+ //
+ validateDecision(decision.getKey(), baseRequest);
+ }
+
+ @Test
+ public void test10OptimizationPolicyTypeDefault() throws CoderException {
+ //
+ // Remove all the other resources from the request
+ //
+ cleanOutResources();
+ //
+ // Add in policy type
+ //
+ List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.AffinityPolicy");
+ baseRequest.getResource().put("policy-type", policyTypes);
+ //
+ // Ask for a decision for default
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
LOGGER.info("Decision {}", decision.getKey());
assertThat(decision.getKey()).isNotNull();
assertThat(decision.getKey().getPolicies().size()).isEqualTo(4);
//
- // Dump it out as Json
+ // Double check that the contents are what we expect
+ //
+ LOGGER.info(gson.encode(decision.getKey()));
+ }
+
+ @Test
+ public void test20OptimizationPolicyTypeDefault() throws CoderException {
+ //
+ // Remove all the other resources from the request
+ //
+ cleanOutResources();
+ //
+ // Add in policy type
+ //
+ List<String> policyTypes = Lists.newArrayList("onap.policies.optimization.HpaPolicy");
+ baseRequest.getResource().put("policy-type", policyTypes);
+ //
+ // Ask for a decision for default
+ //
+ Pair<DecisionResponse, Response> decision = service.makeDecision(baseRequest, null);
+ LOGGER.info("Decision {}", decision.getKey());
+
+ assertThat(decision.getKey()).isNotNull();
+ assertThat(decision.getKey().getPolicies().size()).isEqualTo(1);
+ //
+ // Double check that the contents are what we expect
//
LOGGER.info(gson.encode(decision.getKey()));
}
+
+ @SuppressWarnings("unchecked")
+ private void validateDecision(DecisionResponse decision, DecisionRequest request) {
+ for (Entry<String, Object> entrySet : decision.getPolicies().entrySet()) {
+ LOGGER.info("Decision Returned Policy {}", entrySet.getKey());
+ assertThat(entrySet.getValue()).isInstanceOf(Map.class);
+ Map<String, Object> policyContents = (Map<String, Object>) entrySet.getValue();
+ assertThat(policyContents.containsKey("properties")).isTrue();
+ assertThat(policyContents.get("properties")).isInstanceOf(Map.class);
+ Map<String, Object> policyProperties = (Map<String, Object>) policyContents.get("properties");
+
+ validateMatchable((Collection<String>) request.getResource().get("scope"),
+ (Collection<String>) policyProperties.get("scope"));
+
+ validateMatchable((Collection<String>) request.getResource().get("services"),
+ (Collection<String>) policyProperties.get("services"));
+
+ validateMatchable((Collection<String>) request.getResource().get("resources"),
+ (Collection<String>) policyProperties.get("resources"));
+
+ validateMatchable((Collection<String>) request.getResource().get("geography"),
+ (Collection<String>) policyProperties.get("geography"));
+ }
+ }
+
+ private void validateMatchable(Collection<String> requestList, Collection<String> policyProperties) {
+ LOGGER.info("Validating matchable: {} with {}", policyProperties, requestList);
+ //
+ // Null or empty implies '*' - that is any value is acceptable
+ // for this policy.
+ //
+ if (policyProperties == null || policyProperties.isEmpty()) {
+ return;
+ }
+ Condition<String> condition = new Condition<>(
+ requestList::contains,
+ "Request list is contained");
+ assertThat(policyProperties).haveAtLeast(1, condition);
+
+ }
+
+ @SuppressWarnings("unchecked")
+ private void cleanOutResources() {
+ ((List<String>)baseRequest.getResource().get("scope")).clear();
+ ((List<String>)baseRequest.getResource().get("services")).clear();
+ ((List<String>)baseRequest.getResource().get("resources")).clear();
+ ((List<String>)baseRequest.getResource().get("geography")).clear();
+ }
}
diff --git a/main/src/test/resources/decisions/decision.optimization.affinity.input.json b/applications/optimization/src/test/resources/decision.optimization.input.json
index 1bf18fde..3872ca90 100644
--- a/main/src/test/resources/decisions/decision.optimization.affinity.input.json
+++ b/applications/optimization/src/test/resources/decision.optimization.input.json
@@ -5,8 +5,8 @@
"action": "optimize",
"resource": {
"scope": [],
- "services": ["vCPE"],
+ "services": [],
"resources": [],
- "geography": ["US"]
+ "geography": []
}
} \ No newline at end of file
diff --git a/applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml b/applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml
index 80888149..919a2f8b 100644
--- a/applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml
+++ b/applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml
@@ -13,6 +13,24 @@ topology_template:
scope: []
services: []
resources: []
+ geography: []
+ identity: affinity_vCPE
+ applicableResources: any
+ affinityProperties:
+ qualifier: same
+ category: complex
+ -
+ OSDF_CASABLANCA.Affinity_Default_US:
+ type: onap.policies.optimization.AffinityPolicy
+ version: 1.0.0
+ type_version: 1.0.0
+ metadata:
+ policy-id: OSDF_CASABLANCA.Affinity_Default_US
+ policy-version: 1
+ properties:
+ scope: []
+ services: []
+ resources: []
geography: [US]
identity: affinity_vCPE
applicableResources: any
@@ -20,12 +38,12 @@ topology_template:
qualifier: same
category: complex
-
- OSDF_CASABLANCA.Affinity_vCPE_0:
+ OSDF_CASABLANCA.Affinity_Default_vCPE_0:
type: onap.policies.optimization.AffinityPolicy
version: 1.0.0
type_version: 1.0.0
metadata:
- policy-id: OSDF_CASABLANCA.Affinity_vCPE_0
+ policy-id: OSDF_CASABLANCA.Affinity_Default_vCPE_0
policy-version: 1
properties:
scope: []