From 2c847e0855b316c162c9fd31456fdf8e338a5dba Mon Sep 17 00:00:00 2001 From: Pamela Dragosh Date: Fri, 22 Mar 2019 14:12:52 -0400 Subject: [PATCH] Adding optimization application finish guard Created Optimization application and created a translator for it. The translator makes an assumption that OOF wants to query on policyScope and policyType properties. Rearranged some of the test code for re-usability. Guard policies are now creating for frequency limiter and min max. Probably could use some clean up. Upgraded to xacml 2.0.1 to include a fix for handling null attribute values. Added some code to test missing values. Issue-ID: POLICY-1273 Change-Id: Ia3dbfa992bbe0cbb5aa294c38aa2aff430a3230a Signed-off-by: Pamela Dragosh --- applications/common/pom.xml | 2 +- .../common/OnapPolicyFinderFactory.java | 53 +- .../xacml/application/common/ToscaDictionary.java | 64 ++ .../xacml/application/common/XacmlPolicyUtils.java | 129 +++- .../common/std/StdCombinedPolicyRequest.java | 87 ++- .../std/StdCombinedPolicyResultsTranslator.java | 75 ++- .../common/std/StdMatchablePolicyRequest.java | 141 ++++ .../common/std/StdMatchableTranslator.java | 400 +++++++++++ .../common/std/StdMetadataTranslator.java | 110 --- applications/guard/pom.xml | 9 - .../pdp/application/guard/GuardPdpApplication.java | 40 +- .../guard/LegacyGuardPolicyRequest.java | 163 +++++ .../application/guard/LegacyGuardTranslator.java | 740 +++++++++++++++++++++ .../application/guard/GuardPdpApplicationTest.java | 354 ++++++---- .../guard.policy-minmax-missing-fields1.yaml | 19 + .../vDNS.policy.guard.frequency.output.tosca.yaml | 20 + .../vDNS.policy.guard.minmax.output.tosca.yaml | 19 + .../guard/src/test/resources/xacml.properties | 13 +- applications/monitoring/pom.xml | 9 - .../application/monitoring/MonitoringRequest.java | 78 --- .../monitoring/MonitoringPdpApplicationTest.java | 298 ++++----- .../resources/vDNS.policy.decision.payload.json | 0 .../monitoring/src/test/resources/xacml.properties | 8 - applications/optimization/pom.xml | 43 ++ .../optimization/OptimizationPdpApplication.java | 164 +++++ ...lication.common.XacmlApplicationServiceProvider | 1 + .../OptimizationPdpApplicationTest.java | 211 ++++++ .../vCPE.policies.optimization.input.tosca.yaml | 137 ++++ .../src/test/resources/xacml.properties | 31 + applications/pom.xml | 1 + main/pom.xml | 5 + .../decisions/decision.guard.shoulddeny.input.json | 7 +- .../decision.guard.shoulddeny.input2.json | 15 + .../decision.guard.shoulddeny.output.json | 3 - .../decision.guard.shouldpermit.input.json | 8 +- .../decision.guard.shouldpermit.output.json | 3 - .../decision.optimization.affinity.input.json | 10 + pom.xml | 6 +- 38 files changed, 2881 insertions(+), 595 deletions(-) create mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java create mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java delete mode 100644 applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java create mode 100644 applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java create mode 100644 applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java create mode 100644 applications/guard/src/test/resources/guard.policy-minmax-missing-fields1.yaml create mode 100644 applications/guard/src/test/resources/vDNS.policy.guard.frequency.output.tosca.yaml create mode 100644 applications/guard/src/test/resources/vDNS.policy.guard.minmax.output.tosca.yaml delete mode 100644 applications/monitoring/src/main/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringRequest.java delete mode 100644 applications/monitoring/src/test/resources/vDNS.policy.decision.payload.json create mode 100644 applications/optimization/pom.xml create mode 100644 applications/optimization/src/main/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplication.java create mode 100644 applications/optimization/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider create mode 100644 applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java create mode 100644 applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml create mode 100644 applications/optimization/src/test/resources/xacml.properties create mode 100644 main/src/test/resources/decisions/decision.guard.shoulddeny.input2.json delete mode 100644 main/src/test/resources/decisions/decision.guard.shoulddeny.output.json delete mode 100644 main/src/test/resources/decisions/decision.guard.shouldpermit.output.json create mode 100644 main/src/test/resources/decisions/decision.optimization.affinity.input.json diff --git a/applications/common/pom.xml b/applications/common/pom.xml index 30017302..1e75e0dc 100644 --- a/applications/common/pom.xml +++ b/applications/common/pom.xml @@ -45,7 +45,7 @@ com.att.research.xacml xacml-pdp - 2.0.0 + 2.0.1 diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java index 7da455c0..66352010 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/OnapPolicyFinderFactory.java @@ -20,16 +20,24 @@ package org.onap.policy.pdp.xacml.application.common; +import com.att.research.xacml.std.IdentifierImpl; import com.att.research.xacml.std.StdStatusCode; +import com.att.research.xacml.std.StdVersion; import com.att.research.xacml.std.dom.DOMStructureException; import com.att.research.xacml.util.FactoryException; import com.att.research.xacml.util.XACMLProperties; +import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithm; +import com.att.research.xacmlatt.pdp.policy.CombiningAlgorithmFactory; import com.att.research.xacmlatt.pdp.policy.Policy; import com.att.research.xacmlatt.pdp.policy.PolicyDef; import com.att.research.xacmlatt.pdp.policy.PolicyFinder; import com.att.research.xacmlatt.pdp.policy.PolicyFinderFactory; +import com.att.research.xacmlatt.pdp.policy.PolicySet; +import com.att.research.xacmlatt.pdp.policy.PolicySetChild; +import com.att.research.xacmlatt.pdp.policy.Target; import com.att.research.xacmlatt.pdp.policy.dom.DOMPolicyDef; import com.att.research.xacmlatt.pdp.std.StdPolicyFinder; +import com.att.research.xacmlatt.pdp.util.ATTPDPProperties; import com.google.common.base.Splitter; import com.google.common.base.Strings; @@ -43,6 +51,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; +import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -212,7 +221,49 @@ public class OnapPolicyFinderFactory extends PolicyFinderFactory { protected synchronized void init() { if (this.needsInit) { logger.debug("Initializing OnapPolicyFinderFactory Properties "); - this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES); + + // + // Check for property that combines root policies into one policyset + // + String combiningAlgorithm = properties.getProperty( + ATTPDPProperties.PROP_POLICYFINDERFACTORY_COMBINEROOTPOLICIES); + if (combiningAlgorithm != null) { + try { + logger.info("Combining root policies with {}", combiningAlgorithm); + // + // Find the combining algorithm + // + CombiningAlgorithm algorithm = CombiningAlgorithmFactory.newInstance() + .getPolicyCombiningAlgorithm(new IdentifierImpl(combiningAlgorithm)); + // + // Create our root policy + // + PolicySet root = new PolicySet(); + root.setIdentifier(new IdentifierImpl(UUID.randomUUID().toString())); + root.setVersion(StdVersion.newInstance("1.0")); + root.setTarget(new Target()); + // + // Set the algorithm + // + root.setPolicyCombiningAlgorithm(algorithm); + // + // Load all our root policies + // + for (PolicyDef policy : this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES)) { + root.addChild(policy); + } + // + // Set this policy as the root + // + this.rootPolicies = new ArrayList<>(); + this.rootPolicies.add(root); + } catch (Exception e) { + logger.error("Failed to load Combining Algorithm Factory: {}", e.getLocalizedMessage()); + } + } else { + logger.info("Loading root policies"); + this.rootPolicies = this.getPolicyDefs(XACMLProperties.PROP_ROOTPOLICIES); + } this.referencedPolicies = this.getPolicyDefs(XACMLProperties.PROP_REFERENCEDPOLICIES); logger.debug("Root Policies: {}", this.rootPolicies.size()); logger.debug("Referenced Policies: {}", this.referencedPolicies.size()); diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java index 352e51d8..0dcafa00 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/ToscaDictionary.java @@ -43,6 +43,68 @@ public final class ToscaDictionary { public static final Identifier ID_RESOURCE_POLICY_TYPE_VERSION = new IdentifierImpl(URN_ONAP, "policy-type-version"); + /* + * These ID's are for identifying Subjects + */ + + public static final Identifier ID_SUBJECT_ONAP_NAME = + XACML3.ID_SUBJECT_SUBJECT_ID; + + public static final Identifier ID_SUBJECT_ONAP_COMPONENT = + new IdentifierImpl(URN_ONAP, "onap-component"); + + public static final Identifier ID_SUBJECT_ONAP_INSTANCE = + new IdentifierImpl(URN_ONAP, "onap-instance"); + + /* + * These 2 ID's are for Optimization policies + */ + + public static final Identifier ID_RESOURCE_POLICY_SCOPE_PROPERTY = + new IdentifierImpl(URN_ONAP, "policy-scope-property"); + + public static final Identifier ID_RESOURCE_POLICY_TYPE_PROPERTY = + new IdentifierImpl(URN_ONAP, "policy-type-property"); + + /* + * These ID's are for Legacy Guard Policies + */ + public static final Identifier ID_RESOURCE_GUARD_ACTOR = + new IdentifierImpl(URN_ONAP, "guard:actor:actor-id"); + public static final Identifier ID_RESOURCE_GUARD_RECIPE = + new IdentifierImpl(URN_ONAP, "guard:operation:operation-id"); + public static final Identifier ID_RESOURCE_GUARD_CLNAME = + new IdentifierImpl(URN_ONAP, "guard:clname:clname-id"); + public static final Identifier ID_RESOURCE_GUARD_TARGETID = + new IdentifierImpl(URN_ONAP, "guard:target:target-id"); + public static final Identifier ID_SUBJECT_GUARD_REQUESTID = + new IdentifierImpl(URN_ONAP, "guard:request:request-id"); + public static final Identifier ID_RESOURCE_GUARD_VFCOUNT = + new IdentifierImpl(URN_ONAP, "guard:target:vf-count"); + public static final Identifier ID_RESOURCE_GUARD_MIN = + new IdentifierImpl(URN_ONAP, "guard:target:min"); + public static final Identifier ID_RESOURCE_GUARD_MAX = + new IdentifierImpl(URN_ONAP, "guard:target:max"); + + /* + * This id specifically for guard is provided by the + * operational history database PIP. + */ + public static final Identifier ID_RESOURCE_GUARD_OPERATIONCOUNT = + new IdentifierImpl(URN_ONAP, "guard:operation:operation-count"); + + /* + * This id is specifically for advice returned from guard + */ + public static final Identifier ID_ADVICE_GUARD = + new IdentifierImpl(URN_ONAP, "guard:advice"); + public static final Identifier ID_ADVICE_GUARD_REQUESTID = + new IdentifierImpl(URN_ONAP, "guard:advice:request-id"); + + /* + * Obligation specific ID's + */ + public static final Identifier ID_OBLIGATION_REST_BODY = new IdentifierImpl(URN_ONAP, "rest:body"); @@ -61,6 +123,8 @@ public final class ToscaDictionary { public static final Identifier ID_OBLIGATION_MONITORING_ISSUER = new IdentifierImpl(URN_ONAP, "issuer:monitoring"); + + private ToscaDictionary() { super(); } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java index ca327b90..46742af9 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/XacmlPolicyUtils.java @@ -23,11 +23,11 @@ package org.onap.policy.pdp.xacml.application.common; import com.att.research.xacml.api.Identifier; -import com.att.research.xacml.api.pdp.PDPEngine; -import com.att.research.xacml.api.pdp.PDPEngineFactory; -import com.att.research.xacml.util.FactoryException; import com.att.research.xacml.util.XACMLProperties; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -145,6 +145,40 @@ public class XacmlPolicyUtils { return rootPolicy; } + /** + * Adds in the root policy to the PDP properties object. + * + * @param properties Input properties + * @param rootPolicyPath Path to the root policy file + * @return Properties object + */ + public static Properties addRootPolicy(Properties properties, Path rootPolicyPath) { + // + // Get the current set of referenced policy ids + // + Set rootPolicies = XACMLProperties.getRootPolicyIDs(properties); + // + // Construct a unique id + // + int id = 1; + while (true) { + String refId = "ref" + id; + if (rootPolicies.contains(refId)) { + id++; + } else { + rootPolicies.add(refId); + properties.put(refId + DOT_FILE_SUFFIX, rootPolicyPath.toAbsolutePath().toString()); + break; + } + } + // + // Set the new comma separated list + // + properties.setProperty(XACMLProperties.PROP_ROOTPOLICIES, + rootPolicies.stream().collect(Collectors.joining(","))); + return properties; + } + /** * Adds in the referenced policy to the PDP properties object. * @@ -318,23 +352,90 @@ public class XacmlPolicyUtils { return Paths.get(rootPath.toAbsolutePath().toString(), "xacml.properties"); } + public interface FileCreator { + public File createAFile(String filename) throws IOException; + + } /** - * Creates an instance of PDP engine given the Properties object. + * Copies a xacml.properties file to another location and all the policies defined within it. * - * @param properties Incoming Properties object - * @return PDPEngine instance or null if failed + * @param propertiesPath Path to an existing properties file + * @param properties Properties object + * @param creator A callback that can create files. Allows JUnit test to pass Temporary folder + * @return File object that points to new Properties file + * @throws IOException Could not read/write files */ - public static PDPEngine createEngine(Properties properties) { + public static File copyXacmlPropertiesContents(String propertiesPath, Properties properties, + FileCreator creator) throws IOException { // - // Now initialize the XACML PDP Engine + // Open the properties file // - try { - PDPEngineFactory factory = PDPEngineFactory.newInstance(); - return factory.newEngine(properties); - } catch (FactoryException e) { - LOGGER.error("Failed to create XACML PDP Engine {}", e); + try (InputStream is = new FileInputStream(propertiesPath)) { + // + // Load in the properties + // + properties.load(is); + // + // Now we create a new xacml.properties in the temporary folder location + // + File propertiesFile = creator.createAFile("xacml.properties"); + // + // Iterate through any root policies defined + // + for (String root : XACMLProperties.getRootPolicyIDs(properties)) { + // + // Get a file + // + Path rootPath = Paths.get(properties.getProperty(root + DOT_FILE_SUFFIX)); + LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName()); + // + // Construct new path for the root policy + // + File newRootPath = creator.createAFile(rootPath.getFileName().toString()); + // + // Copy the policy file to the temporary folder + // + com.google.common.io.Files.copy(rootPath.toFile(), newRootPath); + // + // Change the properties object to point to where the new policy is + // in the temporary folder + // + properties.setProperty(root + DOT_FILE_SUFFIX, newRootPath.getAbsolutePath()); + } + // + // Iterate through any referenced policies defined + // + for (String referenced : XACMLProperties.getReferencedPolicyIDs(properties)) { + // + // Get a file + // + Path refPath = Paths.get(properties.getProperty(referenced + DOT_FILE_SUFFIX)); + LOGGER.debug("Referenced file {} {}", refPath, refPath.getFileName()); + // + // Construct new path for the root policy + // + File newReferencedPath = creator.createAFile(refPath.getFileName().toString()); + // + // Copy the policy file to the temporary folder + // + com.google.common.io.Files.copy(refPath.toFile(), newReferencedPath); + // + // Change the properties object to point to where the new policy is + // in the temporary folder + // + properties.setProperty(referenced + DOT_FILE_SUFFIX, newReferencedPath.getAbsolutePath()); + } + // + // Save the new properties file to the temporary folder + // + try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) { + properties.store(os, ""); + } + // + // Return the new path to the properties folder + // + return propertiesFile; } - return null; } } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java index 3914ba60..3038b651 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyRequest.java @@ -27,27 +27,41 @@ import com.att.research.xacml.std.annotations.XACMLRequest; import com.att.research.xacml.std.annotations.XACMLResource; import com.att.research.xacml.std.annotations.XACMLSubject; +import java.util.ArrayList; +import java.util.Collection; import java.util.Map; import java.util.Map.Entry; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + import org.onap.policy.models.decisions.concepts.DecisionRequest; +@Getter +@Setter +@ToString @XACMLRequest(ReturnPolicyIdList = true) public class StdCombinedPolicyRequest { - public StdCombinedPolicyRequest() { - super(); - } - @XACMLSubject(includeInResults = true) - String onapName = "DCAE"; + private String onapName; - @XACMLResource(includeInResults = true) - String resource = "onap.policies.Monitoring"; + @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true) + private String onapComponent; + + @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true) + private String onapInstance; @XACMLAction() - String action = "configure"; + private String action; + + @XACMLResource(includeInResults = true) + private Collection resource = new ArrayList<>(); + public StdCombinedPolicyRequest() { + super(); + } /** * Parses the DecisionRequest into a MonitoringRequest. @@ -55,30 +69,57 @@ public class StdCombinedPolicyRequest { * @param decisionRequest Input DecisionRequest * @return MonitoringRequest */ + @SuppressWarnings({"unchecked", "rawtypes"}) public static StdCombinedPolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our request object + // StdCombinedPolicyRequest request = new StdCombinedPolicyRequest(); + // + // Add the subject attributes + // request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + // + // Add the action attribute + // request.action = decisionRequest.getAction(); - + // + // Add the resource attributes + // Map resources = decisionRequest.getResource(); - for (Entry entry : resources.entrySet()) { - if ("policy-id".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); + for (Entry entrySet : resources.entrySet()) { + if ("policy-id".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyIds(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.resource.add(entrySet.getValue().toString()); + } continue; } - if ("policy-type".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); + if ("policy-type".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyTypes(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.resource.add(entrySet.getValue().toString()); + } } } - // - // TODO handle a bad incoming request. Do that here? - // + return request; + } + + private static StdCombinedPolicyRequest addPolicyIds(StdCombinedPolicyRequest request, Collection ids) { + for (Object id : ids) { + request.resource.add(id.toString()); + } + return request; + } + + private static StdCombinedPolicyRequest addPolicyTypes(StdCombinedPolicyRequest request, Collection types) { + for (Object type : types) { + request.resource.add(type.toString()); + } return request; } } diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java index b39c2e60..16798379 100644 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdCombinedPolicyResultsTranslator.java @@ -37,6 +37,7 @@ import com.google.gson.Gson; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -144,40 +145,55 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator // // Go through obligations // - for (Obligation obligation : xacmlResult.getObligations()) { - LOGGER.debug("Obligation: {}", obligation); - for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { - LOGGER.debug("Attribute Assignment: {}", assignment); - // - // We care about the content attribute - // - if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS - .equals(assignment.getAttributeId())) { - // - // The contents are in Json form - // - Object stringContents = assignment.getAttributeValue().getValue(); - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); - } - // - // Let's parse it into a map using Gson - // - Gson gson = new Gson(); - @SuppressWarnings("unchecked") - Map result = gson.fromJson(stringContents.toString() ,Map.class); - decisionResponse.getPolicies().add(result); - } - } - } - } else { - decisionResponse.setErrorMessage("A better error message"); + scanObligations(xacmlResult.getObligations(), decisionResponse); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no policy + // + decisionResponse.setPolicies(new ArrayList<>()); + } + if (xacmlResult.getDecision() == Decision.DENY + || xacmlResult.getDecision() == Decision.INDETERMINATE) { + // + // TODO we have to return an ErrorResponse object instead + // + decisionResponse.setStatus("A better error message"); } } return decisionResponse; } + protected void scanObligations(Collection obligations, DecisionResponse decisionResponse) { + for (Obligation obligation : obligations) { + LOGGER.debug("Obligation: {}", obligation); + for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { + LOGGER.debug("Attribute Assignment: {}", assignment); + // + // We care about the content attribute + // + if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS + .equals(assignment.getAttributeId())) { + // + // The contents are in Json form + // + Object stringContents = assignment.getAttributeValue().getValue(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); + } + // + // Let's parse it into a map using Gson + // + Gson gson = new Gson(); + @SuppressWarnings("unchecked") + Map result = gson.fromJson(stringContents.toString() ,Map.class); + decisionResponse.getPolicies().add(result); + } + } + } + } + @SuppressWarnings("unchecked") protected PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { // @@ -211,9 +227,6 @@ public class StdCombinedPolicyResultsTranslator implements ToscaPolicyTranslator // // Generate the TargetType // - // - // There should be a metadata section - // if (! policyDefinition.containsKey("type")) { throw new ToscaPolicyConversionException(policyName + " missing type value"); } 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 new file mode 100644 index 00000000..086d21db --- /dev/null +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchablePolicyRequest.java @@ -0,0 +1,141 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common.std; + +import com.att.research.xacml.std.annotations.XACMLAction; +import com.att.research.xacml.std.annotations.XACMLRequest; +import com.att.research.xacml.std.annotations.XACMLResource; +import com.att.research.xacml.std.annotations.XACMLSubject; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Map; +import java.util.Map.Entry; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import org.onap.policy.models.decisions.concepts.DecisionRequest; + +@Getter +@Setter +@ToString +@XACMLRequest(ReturnPolicyIdList = true) +public class StdMatchablePolicyRequest { + + @XACMLSubject(includeInResults = true) + private String onapName; + + @XACMLSubject(attributeId = "urn:org:onap:onap-component", includeInResults = true) + private String onapComponent; + + @XACMLSubject(attributeId = "urn:org:onap:onap-instance", includeInResults = true) + private String onapInstance; + + @XACMLAction() + private String action; + + // + // Unfortunately the annotations won't take an object.toString() + // So I could not use the ToscaDictionary class to put these id's + // into the annotations. + // + @XACMLResource(attributeId = "urn:org:onap:policy-scope-property", includeInResults = true) + Collection policyScopes = new ArrayList<>(); + + @XACMLResource(attributeId = "urn:org:onap:policy-type-property", includeInResults = true) + Collection policyTypes = new ArrayList<>(); + + public StdMatchablePolicyRequest() { + super(); + } + + /** + * Parses the DecisionRequest into a MonitoringRequest. + * + * @param decisionRequest Input DecisionRequest + * @return MonitoringRequest + */ + @SuppressWarnings({"rawtypes", "unchecked"}) + public static StdMatchablePolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our request object + // + StdMatchablePolicyRequest request = new StdMatchablePolicyRequest(); + // + // Add the subject attributes + // + request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + // + // Add the action attribute + // + request.action = decisionRequest.getAction(); + // + // Add the resource attributes + // + Map resources = decisionRequest.getResource(); + for (Entry entrySet : resources.entrySet()) { + // + // Making an assumption that these two fields are matchable. + // Its possible we may have to load the policy type model + // and use that to find the fields that are matchable. + // + if ("policyScope".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyScopes(request, (Collection) entrySet.getValue()); + } else if (entrySet.getValue() instanceof String) { + request.policyScopes.add(entrySet.getValue().toString()); + } + continue; + } + if ("policyType".equals(entrySet.getKey())) { + if (entrySet.getValue() instanceof Collection) { + addPolicyTypes(request, (Collection) entrySet.getValue()); + } + if (entrySet.getValue() instanceof String) { + request.policyTypes.add(entrySet.getValue().toString()); + } + } + } + return request; + } + + private static StdMatchablePolicyRequest addPolicyScopes(StdMatchablePolicyRequest request, + Collection scopes) { + for (Object scope : scopes) { + request.policyScopes.add(scope.toString()); + } + return request; + } + + private static StdMatchablePolicyRequest addPolicyTypes(StdMatchablePolicyRequest request, + Collection types) { + for (Object type : types) { + request.policyTypes.add(type.toString()); + } + return request; + } +} 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 new file mode 100644 index 00000000..8550b12e --- /dev/null +++ b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMatchableTranslator.java @@ -0,0 +1,400 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.pdp.xacml.application.common.std; + +import com.att.research.xacml.api.AttributeAssignment; +import com.att.research.xacml.api.DataTypeException; +import com.att.research.xacml.api.Decision; +import com.att.research.xacml.api.Identifier; +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.att.research.xacml.std.annotations.RequestParser; +import com.att.research.xacml.util.XACMLPolicyWriter; +import com.google.gson.Gson; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AnyOfType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeAssignmentExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AttributeValueType; +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.PolicyType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; + +import org.json.JSONObject; +import org.onap.policy.models.decisions.concepts.DecisionRequest; +import org.onap.policy.models.decisions.concepts.DecisionResponse; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class StdMatchableTranslator implements ToscaPolicyTranslator { + + private static final Logger LOGGER = LoggerFactory.getLogger(StdMatchableTranslator.class); + + public StdMatchableTranslator() { + super(); + } + + @SuppressWarnings("unchecked") + @Override + public List scanAndConvertPolicies(Map toscaObject) + throws ToscaPolicyConversionException { + // + // Our return object + // + List scannedPolicies = new ArrayList<>(); + // + // Iterate each of the Policies + // + List policies = (List) toscaObject.get("policies"); + for (Object policyObject : policies) { + // + // Get the contents + // + LOGGER.debug("Found policy {}", policyObject.getClass()); + Map policyContents = (Map) policyObject; + for (Entry entrySet : policyContents.entrySet()) { + LOGGER.debug("Entry set {}", entrySet); + // + // Convert this policy + // + PolicyType policy = this.convertPolicy(entrySet); + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + XACMLPolicyWriter.writePolicyFile(os, policy); + LOGGER.debug("{}", os); + } catch (IOException e) { + LOGGER.error("Failed to convert {}", e); + } + // + // Convert and add in the new policy + // + scannedPolicies.add(policy); + } + } + + return scannedPolicies; + } + + @Override + public Request convertRequest(DecisionRequest request) { + LOGGER.debug("Converting Request {}", request); + try { + return RequestParser.parseRequest(StdMatchablePolicyRequest.createInstance(request)); + } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) { + LOGGER.error("Failed to convert DecisionRequest: {}", e); + } + // + // TODO throw exception + // + return null; + } + + @Override + public DecisionResponse convertResponse(Response xacmlResponse) { + LOGGER.debug("Converting Response {}", xacmlResponse); + DecisionResponse decisionResponse = new DecisionResponse(); + // + // Iterate through all the results + // + for (Result xacmlResult : xacmlResponse.getResults()) { + // + // Check the result + // + if (xacmlResult.getDecision() == Decision.PERMIT) { + // + // Setup policies + // + decisionResponse.setPolicies(new ArrayList<>()); + // + // Go through obligations + // + scanObligations(xacmlResult.getObligations(), decisionResponse); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no policy + // + decisionResponse.setPolicies(new ArrayList<>()); + } + if (xacmlResult.getDecision() == Decision.DENY + || xacmlResult.getDecision() == Decision.INDETERMINATE) { + // + // TODO we have to return an ErrorResponse object instead + // + decisionResponse.setStatus("A better error message"); + } + } + + return decisionResponse; + } + + protected void scanObligations(Collection obligations, DecisionResponse decisionResponse) { + for (Obligation obligation : obligations) { + LOGGER.debug("Obligation: {}", obligation); + for (AttributeAssignment assignment : obligation.getAttributeAssignments()) { + LOGGER.debug("Attribute Assignment: {}", assignment); + // + // We care about the content attribute + // + if (ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS + .equals(assignment.getAttributeId())) { + // + // The contents are in Json form + // + Object stringContents = assignment.getAttributeValue().getValue(); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("DCAE contents: {}{}", System.lineSeparator(), stringContents); + } + // + // Let's parse it into a map using Gson + // + Gson gson = new Gson(); + @SuppressWarnings("unchecked") + Map result = gson.fromJson(stringContents.toString() ,Map.class); + decisionResponse.getPolicies().add(result); + } + } + } + + } + + @SuppressWarnings("unchecked") + protected PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { + // + // Policy name should be at the root + // + String policyName = entrySet.getKey(); + Map policyDefinition = (Map) entrySet.getValue(); + // + // Set it as the policy ID + // + PolicyType newPolicyType = new PolicyType(); + newPolicyType.setPolicyId(policyName); + // + // Optional description + // + if (policyDefinition.containsKey("description")) { + newPolicyType.setDescription(policyDefinition.get("description").toString()); + } + // + // There should be a metadata section + // + if (! policyDefinition.containsKey("metadata")) { + throw new ToscaPolicyConversionException(policyName + " missing metadata section"); + } + this.fillMetadataSection(newPolicyType, + (Map) policyDefinition.get("metadata")); + // + // Set the combining rule + // + newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_FIRST_APPLICABLE.stringValue()); + // + // Generate the TargetType + // + if (! policyDefinition.containsKey("properties")) { + throw new ToscaPolicyConversionException(policyName + " missing properties section"); + } + policyDefinition.get("properties"); + newPolicyType.setTarget(generateTargetType((Map) policyDefinition.get("properties"))); + // + // 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()); + // + // Now represent the policy as Json + // + JSONObject jsonObligation = new JSONObject(); + jsonObligation.put(policyName, policyDefinition); + addObligation(rule, jsonObligation); + // + // Add the rule to the policy + // + newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule); + // + // Return our new policy + // + return newPolicyType; + } + + /** + * From the TOSCA metadata section, pull in values that are needed into the XACML policy. + * + * @param policy Policy Object to store the metadata + * @param metadata The Metadata TOSCA Map + * @return Same Policy Object + * @throws ToscaPolicyConversionException If there is something missing from the metadata + */ + protected PolicyType fillMetadataSection(PolicyType policy, + Map metadata) throws ToscaPolicyConversionException { + if (! metadata.containsKey("policy-id")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id"); + } else { + // + // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field + // + } + if (! metadata.containsKey("policy-version")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version"); + } else { + // + // Add in the Policy Version + // + policy.setVersion(metadata.get("policy-version").toString()); + } + return policy; + } + + /** + * For generating target type, we are making an assumption that the + * policyScope and policyType are the fields that OOF wants to match on. + * + *

In the future, we would need to receive the Policy Type specification + * from the PAP so we can dynamically see which fields are matchable. + * + *

Note: I am making an assumption that the matchable fields are what + * the OOF wants to query a policy on. + * + * @param properties Properties section of policy + * @return TargetType object + */ + @SuppressWarnings("unchecked") + protected TargetType generateTargetType(Map properties) { + TargetType targetType = new TargetType(); + // + // Iterate the properties + // + for (Entry entrySet : properties.entrySet()) { + // + // Find policyScope and policyType + // + if (entrySet.getKey().equals("policyScope")) { + LOGGER.debug("Found policyScope: {}", entrySet.getValue()); + if (entrySet.getValue() instanceof Collection) { + targetType.getAnyOf().add(generateMatches((Collection) entrySet.getValue(), + ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY)); + } else if (entrySet.getValue() instanceof String) { + targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()), + ToscaDictionary.ID_RESOURCE_POLICY_SCOPE_PROPERTY)); + } + } + if (entrySet.getKey().equals("policyType")) { + LOGGER.debug("Found policyType: {}", entrySet.getValue()); + if (entrySet.getValue() instanceof Collection) { + targetType.getAnyOf().add(generateMatches((Collection) entrySet.getValue(), + ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY)); + } else if (entrySet.getValue() instanceof String) { + targetType.getAnyOf().add(generateMatches(Arrays.asList(entrySet.getValue()), + ToscaDictionary.ID_RESOURCE_POLICY_TYPE_PROPERTY)); + } + } + } + + return targetType; + } + + protected AnyOfType generateMatches(Collection matchables, Identifier attributeId) { + // + // This is our outer AnyOf - which is an OR + // + AnyOfType anyOf = new AnyOfType(); + for (Object matchable : matchables) { + // + // Create a match for this + // + MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator( + XACML3.ID_FUNCTION_STRING_EQUAL, + matchable.toString(), + XACML3.ID_DATATYPE_STRING, + attributeId, + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE); + // + // Now create an anyOf (OR) + // + anyOf.getAllOf().add(ToscaPolicyTranslatorUtils.buildAllOf(match)); + } + return anyOf; + } + + protected RuleType addObligation(RuleType rule, JSONObject jsonPolicy) { + // + // Convert the YAML Policy to JSON Object + // + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("JSON Optimization Policy {}{}", System.lineSeparator(), jsonPolicy); + } + // + // Create an AttributeValue for it + // + AttributeValueType value = new AttributeValueType(); + value.setDataType(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_DATATYPE.stringValue()); + value.getContent().add(jsonPolicy.toString()); + // + // Create our AttributeAssignmentExpression where we will + // store the contents of the policy in JSON format. + // + AttributeAssignmentExpressionType expressionType = new AttributeAssignmentExpressionType(); + expressionType.setAttributeId(ToscaDictionary.ID_OBLIGATION_POLICY_MONITORING_CONTENTS.stringValue()); + ObjectFactory factory = new ObjectFactory(); + expressionType.setExpression(factory.createAttributeValue(value)); + // + // Create an ObligationExpression for it + // + ObligationExpressionType obligation = new ObligationExpressionType(); + obligation.setFulfillOn(EffectType.PERMIT); + obligation.setObligationId(ToscaDictionary.ID_OBLIGATION_REST_BODY.stringValue()); + obligation.getAttributeAssignmentExpression().add(expressionType); + // + // Now we can add it into the rule + // + ObligationExpressionsType obligations = new ObligationExpressionsType(); + obligations.getObligationExpression().add(obligation); + rule.setObligationExpressions(obligations); + return rule; + } + +} diff --git a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java b/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java deleted file mode 100644 index 11651f4f..00000000 --- a/applications/common/src/main/java/org/onap/policy/pdp/xacml/application/common/std/StdMetadataTranslator.java +++ /dev/null @@ -1,110 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * ONAP - * ================================================================================ - * Copyright (C) 2019 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * SPDX-License-Identifier: Apache-2.0 - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.pdp.xacml.application.common.std; - -import com.att.research.xacml.api.Request; -import com.att.research.xacml.api.Response; -import com.att.research.xacml.util.XACMLPolicyWriter; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; - -import org.onap.policy.models.decisions.concepts.DecisionRequest; -import org.onap.policy.models.decisions.concepts.DecisionResponse; -import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; -import org.onap.policy.pdp.xacml.application.common.ToscaPolicyTranslator; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class StdMetadataTranslator implements ToscaPolicyTranslator { - - private static final Logger LOGGER = LoggerFactory.getLogger(StdMetadataTranslator.class); - - public StdMetadataTranslator() { - super(); - } - - @SuppressWarnings("unchecked") - @Override - public List scanAndConvertPolicies(Map toscaObject) - throws ToscaPolicyConversionException { - // - // Our return object - // - List scannedPolicies = new ArrayList<>(); - // - // Iterate each of the Policies - // - List policies = (List) toscaObject.get("policies"); - for (Object policyObject : policies) { - // - // Get the contents - // - LOGGER.debug("Found policy {}", policyObject.getClass()); - Map policyContents = (Map) policyObject; - for (Entry entrySet : policyContents.entrySet()) { - LOGGER.debug("Entry set {}", entrySet); - // - // Convert this policy - // - PolicyType policy = this.convertPolicy(entrySet); - try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { - XACMLPolicyWriter.writePolicyFile(os, policy); - LOGGER.debug("{}", os); - } catch (IOException e) { - LOGGER.error("Failed to convert {}", e); - } - // - // Convert and add in the new policy - // - scannedPolicies.add(policy); - } - } - - return scannedPolicies; - } - - @Override - public Request convertRequest(DecisionRequest request) { - // TODO Auto-generated method stub - return null; - } - - @Override - public DecisionResponse convertResponse(Response xacmlResponse) { - // TODO Auto-generated method stub - return null; - } - - private PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { - - return null; - } - -} diff --git a/applications/guard/pom.xml b/applications/guard/pom.xml index 7ee3da08..6696e55e 100644 --- a/applications/guard/pom.xml +++ b/applications/guard/pom.xml @@ -33,15 +33,6 @@ This modules contain an application that implements onap.Guard policy-types for XACML PDP. - - com.google.code.gson - gson - - - org.onap.policy.common - common-parameters - ${policy.common.version} - org.onap.policy.xacml-pdp.applications common diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java index 18385239..1b12fca8 100644 --- a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplication.java @@ -24,19 +24,23 @@ package org.onap.policy.xacml.pdp.application.guard; import com.att.research.xacml.api.Request; import com.att.research.xacml.api.Response; +import com.att.research.xacml.util.XACMLPolicyWriter; import com.google.common.collect.Lists; +import java.io.IOException; +import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Properties; import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; import org.onap.policy.models.decisions.concepts.DecisionRequest; import org.onap.policy.models.decisions.concepts.DecisionResponse; import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; -import org.onap.policy.pdp.xacml.application.common.std.StdMetadataTranslator; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -52,7 +56,7 @@ public class GuardPdpApplication extends StdXacmlApplicationServiceProvider { private static final Logger LOGGER = LoggerFactory.getLogger(GuardPdpApplication.class); private static final String STRING_VERSION100 = "1.0.0"; private Map supportedPolicyTypes = new HashMap<>(); - private StdMetadataTranslator translator = new StdMetadataTranslator(); + private LegacyGuardTranslator translator = new LegacyGuardTranslator(); /** Constructor. * @@ -103,9 +107,37 @@ public class GuardPdpApplication extends StdXacmlApplicationServiceProvider { throw new ToscaPolicyConversionException("Converted 0 policies"); } // - // TODO update properties, save to disk, etc. + // Create a copy of the properties object // - } catch (ToscaPolicyConversionException e) { + Properties newProperties = this.getProperties(); + // + // Iterate through the policies + // + for (PolicyType newPolicy : listPolicies) { + // + // Construct the filename + // + Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(newPolicy, this.getDataPath()); + // + // Write the policy to disk + // Maybe check for an error + // + XACMLPolicyWriter.writePolicyFile(refPath, newPolicy); + // + // Add root policy to properties object + // + XacmlPolicyUtils.addRootPolicy(newProperties, refPath); + } + // + // Write the properties to disk + // + XacmlPolicyUtils.storeXacmlProperties(newProperties, + XacmlPolicyUtils.getPropertiesPath(this.getDataPath())); + // + // Reload the engine + // + this.createEngine(newProperties); + } catch (IOException | ToscaPolicyConversionException e) { LOGGER.error("Failed to loadPolicies {}", e); } } diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java new file mode 100644 index 00000000..0b5b5675 --- /dev/null +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardPolicyRequest.java @@ -0,0 +1,163 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.xacml.pdp.application.guard; + +import com.att.research.xacml.std.annotations.XACMLAction; +import com.att.research.xacml.std.annotations.XACMLRequest; +import com.att.research.xacml.std.annotations.XACMLResource; +import com.att.research.xacml.std.annotations.XACMLSubject; + +import java.util.Map; + +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; + +import org.onap.policy.models.decisions.concepts.DecisionRequest; + +@Getter +@Setter +@ToString +@XACMLRequest(ReturnPolicyIdList = true) +public class LegacyGuardPolicyRequest { + + private static final String STR_GUARD = "guard"; + + @XACMLSubject(includeInResults = true) + private String onapName; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:onap-component") + private String onapComponent; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:onap-instance") + private String onapInstance; + + @XACMLSubject(includeInResults = true, attributeId = "urn:org:onap:guard:request:request-id") + private String requestId; + + @XACMLAction + private String action = STR_GUARD; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:clname:clname-id") + private String clnameId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:actor:actor-id") + private String actorId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:operation:operation-id") + private String operationId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:target-id") + private String targetId; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:vf-count") + private Integer vfCount; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:min") + private Integer min; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:target:max") + private Integer max; + + @XACMLResource(includeInResults = true, attributeId = "urn:org:onap:guard:operation:operation-count") + private Integer operationCount; + + public LegacyGuardPolicyRequest() { + super(); + } + + /** + * Parses the DecisionRequest into a StdMetadataPolicyRequest. + * + * @param decisionRequest Input DecisionRequest + * @return StdMetadataPolicyRequest + */ + @SuppressWarnings("unchecked") + public static LegacyGuardPolicyRequest createInstance(DecisionRequest decisionRequest) { + // + // Create our return object + // + LegacyGuardPolicyRequest request = new LegacyGuardPolicyRequest(); + // + // Add the subject attributes + // + request.onapName = decisionRequest.getOnapName(); + request.onapComponent = decisionRequest.getOnapComponent(); + request.onapInstance = decisionRequest.getOnapInstance(); + request.requestId = decisionRequest.getRequestId(); + // + // Now pull from the resources + // + Map resources = decisionRequest.getResource(); + // + // Just in case nothing is in there + // + if (resources == null || resources.isEmpty() || ! resources.containsKey(STR_GUARD)) { + // + // Perhaps we throw an exception and then caller + // can put together a response + // + return request; + } + Map guard = (Map) resources.get(STR_GUARD); + if (guard == null || guard.isEmpty()) { + // + // again, same problem throw an exception? + // + return request; + } + // + // Find our fields + // + if (guard.containsKey("actor")) { + request.actorId = guard.get("actor").toString(); + } + if (guard.containsKey("recipe")) { + request.operationId = guard.get("recipe").toString(); + } + if (guard.containsKey("clname")) { + request.clnameId = guard.get("clname").toString(); + } + if (guard.containsKey("targets")) { + request.targetId = guard.get("targets").toString(); + } + if (guard.containsKey("vfCount")) { + request.vfCount = Integer.decode(guard.get("vfCount").toString()); + } + if (guard.containsKey("min")) { + request.min = Integer.decode(guard.get("min").toString()); + } + if (guard.containsKey("max")) { + request.max = Integer.decode(guard.get("max").toString()); + } + // + // TODO - remove this when the PIP is hooked up + // + if (guard.containsKey("operationCount")) { + request.operationCount = Integer.decode(guard.get("operationCount").toString()); + } + + return request; + } + +} diff --git a/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java new file mode 100644 index 00000000..81340b4d --- /dev/null +++ b/applications/guard/src/main/java/org/onap/policy/xacml/pdp/application/guard/LegacyGuardTranslator.java @@ -0,0 +1,740 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.xacml.pdp.application.guard; + +import com.att.research.xacml.api.DataTypeException; +import com.att.research.xacml.api.Decision; +import com.att.research.xacml.api.Identifier; +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.annotations.RequestParser; +import com.att.research.xacml.util.XACMLPolicyWriter; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AdviceExpressionsType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.AllOfType; +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.PolicyType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.RuleType; +import oasis.names.tc.xacml._3_0.core.schema.wd_17.TargetType; + +import org.onap.policy.models.decisions.concepts.DecisionRequest; +import org.onap.policy.models.decisions.concepts.DecisionResponse; +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.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class LegacyGuardTranslator implements ToscaPolicyTranslator { + + private static final Logger LOGGER = LoggerFactory.getLogger(LegacyGuardTranslator.class); + + private static final String FIELD_POLICIES = "policies"; + private static final String FIELD_TOPOLOGY_TEMPLATE = "topology_template"; + private static final String FIELD_GUARD_ACTIVE_START = "guardActiveStart"; + private static final String FIELD_GUARD_ACTIVE_END = "guardActiveEnd"; + + public LegacyGuardTranslator() { + super(); + } + + @SuppressWarnings("unchecked") + @Override + public List scanAndConvertPolicies(Map toscaObject) + throws ToscaPolicyConversionException { + // + // Our return object + // + List scannedPolicies = new ArrayList<>(); + // + // Find the Policies + // + List policies; + + if (toscaObject.containsKey(FIELD_POLICIES)) { + policies = (List) toscaObject.get(FIELD_POLICIES); + } else if (toscaObject.containsKey(FIELD_TOPOLOGY_TEMPLATE)) { + Map topologyTemplate = (Map) toscaObject.get(FIELD_TOPOLOGY_TEMPLATE); + if (topologyTemplate.containsKey(FIELD_POLICIES)) { + policies = (List) topologyTemplate.get(FIELD_POLICIES); + } else { + LOGGER.warn("topologyTemplate does not contain policies"); + return scannedPolicies; + } + } else { + LOGGER.warn("Failed to find policies or topologyTemplate"); + return scannedPolicies; + } + // + // Iterate each of the Policies + // + for (Object policyObject : policies) { + // + // Get the contents + // + LOGGER.debug("Found policy {}", policyObject.getClass()); + Map policyContents = (Map) policyObject; + for (Entry entrySet : policyContents.entrySet()) { + LOGGER.debug("Entry set {}", entrySet); + // + // Convert this policy + // + PolicyType policy = this.convertPolicy(entrySet); + if (policy == null) { + // + // Somehow there wasn't enough information to create + // a policy + // + LOGGER.debug("Failed to convert policy"); + continue; + } + // + // Debug dump this + // + try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { + XACMLPolicyWriter.writePolicyFile(os, policy); + LOGGER.debug("{}", os); + } catch (IOException e) { + LOGGER.error("Failed to convert {}", e); + } + // + // Convert and add in the new policy + // + scannedPolicies.add(policy); + } + } + + return scannedPolicies; + } + + @Override + public Request convertRequest(DecisionRequest request) { + LOGGER.debug("Converting Request {}", request); + try { + return RequestParser.parseRequest(LegacyGuardPolicyRequest.createInstance(request)); + } catch (IllegalArgumentException | IllegalAccessException | DataTypeException e) { + LOGGER.error("Failed to convert DecisionRequest: {}", e); + } + // + // TODO throw exception + // + return null; + } + + + @Override + public DecisionResponse convertResponse(Response xacmlResponse) { + LOGGER.debug("Converting Response {}", xacmlResponse); + DecisionResponse decisionResponse = new DecisionResponse(); + // + // Iterate through all the results + // + for (Result xacmlResult : xacmlResponse.getResults()) { + // + // Check the result + // + if (xacmlResult.getDecision() == Decision.PERMIT) { + // + // Just simply return a Permit response + // + decisionResponse.setStatus(Decision.PERMIT.toString()); + } + if (xacmlResult.getDecision() == Decision.DENY) { + // + // Just simply return a Deny response + // + decisionResponse.setStatus(Decision.DENY.toString()); + } + if (xacmlResult.getDecision() == Decision.NOTAPPLICABLE) { + // + // There is no guard policy, so we return a permit + // + decisionResponse.setStatus(Decision.PERMIT.toString()); + } + } + + return decisionResponse; + } + + @SuppressWarnings("unchecked") + private PolicyType convertPolicy(Entry entrySet) throws ToscaPolicyConversionException { + // + // Policy name should be at the root + // + String policyName = entrySet.getKey(); + Map policyDefinition = (Map) entrySet.getValue(); + // + // Set it as the policy ID + // + PolicyType newPolicyType = new PolicyType(); + newPolicyType.setPolicyId(policyName); + // + // Optional description + // + if (policyDefinition.containsKey("description")) { + newPolicyType.setDescription(policyDefinition.get("description").toString()); + } + // + // There should be a metadata section + // + if (! policyDefinition.containsKey("metadata")) { + throw new ToscaPolicyConversionException(policyName + " missing metadata section"); + } + this.fillMetadataSection(newPolicyType, + (Map) policyDefinition.get("metadata")); + // + // Set the combining rule + // + newPolicyType.setRuleCombiningAlgId(XACML3.ID_RULE_DENY_UNLESS_PERMIT.stringValue()); + // + // Generate the TargetType + // + if (! policyDefinition.containsKey("properties")) { + throw new ToscaPolicyConversionException(policyName + " missing properties section"); + } + newPolicyType.setTarget(this.generateTargetType((Map) policyDefinition.get("properties"))); + // + // Now create the Permit Rule + // + RuleType rule = generatePermitRule(policyName, policyDefinition.get("type").toString(), + (Map) policyDefinition.get("properties")); + // + // Check if we were able to create the rule + // + if (rule == null) { + LOGGER.warn("Failed to create rule"); + return null; + } + // + // Add the rule to the policy + // + newPolicyType.getCombinerParametersOrRuleCombinerParametersOrVariableDefinition().add(rule); + // + // Return our new policy + // + return newPolicyType; + } + + /** + * From the TOSCA metadata section, pull in values that are needed into the XACML policy. + * + * @param policy Policy Object to store the metadata + * @param metadata The Metadata TOSCA Map + * @return Same Policy Object + * @throws ToscaPolicyConversionException If there is something missing from the metadata + */ + protected PolicyType fillMetadataSection(PolicyType policy, + Map metadata) throws ToscaPolicyConversionException { + if (! metadata.containsKey("policy-id")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-id"); + } else { + // + // Do nothing here - the XACML PolicyId is used from TOSCA Policy Name field + // + } + if (! metadata.containsKey("policy-version")) { + throw new ToscaPolicyConversionException(policy.getPolicyId() + " missing metadata policy-version"); + } else { + // + // Add in the Policy Version + // + policy.setVersion(metadata.get("policy-version").toString()); + } + return policy; + } + + protected TargetType generateTargetType(Map properties) { + // + // Go through potential properties + // + AllOfType allOf = new AllOfType(); + if (properties.containsKey("actor")) { + addMatch(allOf, properties.get("actor"), ToscaDictionary.ID_RESOURCE_GUARD_ACTOR); + } + if (properties.containsKey("recipe")) { + addMatch(allOf, properties.get("recipe"), ToscaDictionary.ID_RESOURCE_GUARD_RECIPE); + } + if (properties.containsKey("targets")) { + addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID); + } + if (properties.containsKey("clname")) { + addMatch(allOf, properties.get("clname"), ToscaDictionary.ID_RESOURCE_GUARD_CLNAME); + } + if (properties.containsKey("targets")) { + addMatch(allOf, properties.get("targets"), ToscaDictionary.ID_RESOURCE_GUARD_TARGETID); + } + // + // Create target + // + TargetType target = new TargetType(); + AnyOfType anyOf = new AnyOfType(); + anyOf.getAllOf().add(allOf); + target.getAnyOf().add(anyOf); + return target; + } + + private static AllOfType addMatch(AllOfType allOf, Object value, Identifier attributeId) { + if (value instanceof String) { + if (".*".equals(value.toString())) { + // + // There's no point to even have a match + // + return allOf; + } else { + // + // Exact match + // + MatchType match = ToscaPolicyTranslatorUtils.buildMatchTypeDesignator( + XACML3.ID_FUNCTION_STRING_EQUAL, + value, + XACML3.ID_DATATYPE_STRING, + attributeId, + XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE); + + allOf.getMatch().add(match); + } + return allOf; + } + if (value instanceof Collection) { + // + // TODO support a collection of that attribute + // + } + return allOf; + } + + private static RuleType generatePermitRule(String policyName, String policyType, Map properties) { + // + // Now determine which policy type we are generating + // + if ("onap.policies.controlloop.guard.FrequencyLimiter".equals(policyType)) { + return generateFrequencyPermit(policyName, properties); + } else if ("onap.policies.controlloop.guard.MinMax".equals(policyType)) { + return generateMinMaxPermit(policyName, properties); + } + return null; + } + + private static RuleType generateFrequencyPermit(String policyName, Map properties) { + // + // See if its possible to generate a count + // + Integer limit = null; + if (properties.containsKey("limit")) { + limit = Integer.decode(properties.get("limit").toString()); + } + if (limit == null) { + LOGGER.debug("Must have a limit value for frequency guard policy to be created"); + return null; + } + // + // Get the properties that are common among guards + // + String timeWindow = null; + if (properties.containsKey("timeWindow")) { + timeWindow = properties.get("timeWindow").toString(); + } + String timeUnits = null; + if (properties.containsKey("timeUnits")) { + timeUnits = properties.get("timeUnits").toString(); + } + String guardActiveStart = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) { + guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString(); + } + String guardActiveEnd = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) { + guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString(); + } + // + // Generate the time in range + // + final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd); + // + // Generate a count + // + final ApplyType countCheck = generateCountCheck(limit, timeWindow, timeUnits); + // + // Now combine into an And + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + applyAnd.getExpression().add(new ObjectFactory().createApply(timeRange)); + applyAnd.getExpression().add(new ObjectFactory().createApply(countCheck)); + // + // And create an outer negation of the And + // + ApplyType applyNot = new ApplyType(); + applyNot.setDescription("Negate the and"); + applyNot.setFunctionId(XACML3.ID_FUNCTION_NOT.stringValue()); + applyNot.getExpression().add(new ObjectFactory().createApply(applyAnd)); + + // + // Create our condition + // + final ConditionType condition = new ConditionType(); + condition.setExpression(new ObjectFactory().createApply(applyNot)); + + // + // Now we can create our rule + // + RuleType permit = new RuleType(); + permit.setDescription("Default is to PERMIT if the policy matches."); + permit.setRuleId(policyName + ":rule"); + permit.setEffect(EffectType.PERMIT); + permit.setTarget(new TargetType()); + // + // Add the condition + // + permit.setCondition(condition); + // + // TODO Add the advice - Is the request id needed to be returned? + // + // permit.setAdviceExpressions(adviceExpressions); + // + // Done + // + return permit; + } + + private static RuleType generateMinMaxPermit(String policyName, Map properties) { + // + // Get the properties that are common among guards + // + String guardActiveStart = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_START)) { + guardActiveStart = properties.get(FIELD_GUARD_ACTIVE_START).toString(); + } + String guardActiveEnd = null; + if (properties.containsKey(FIELD_GUARD_ACTIVE_END)) { + guardActiveEnd = properties.get(FIELD_GUARD_ACTIVE_END).toString(); + } + // + // Generate the time in range + // + final ApplyType timeRange = generateTimeInRange(guardActiveStart, guardActiveEnd); + // + // See if its possible to generate a count + // + Integer min = null; + if (properties.containsKey("min")) { + min = Integer.decode(properties.get("min").toString()); + } + Integer max = null; + if (properties.containsKey("max")) { + max = Integer.decode(properties.get("max").toString()); + } + final ApplyType minApply = generateMinCheck(min); + final ApplyType maxApply = generateMaxCheck(max); + // + // Make sure we have at least something to check here, + // otherwise there really is no point to this policy. + // + if (timeRange == null && minApply == null && maxApply == null) { + return null; + } + // + // Create our rule + // + RuleType permit = new RuleType(); + permit.setDescription("Default is to PERMIT if the policy matches."); + permit.setRuleId(policyName + ":rule"); + permit.setEffect(EffectType.PERMIT); + permit.setTarget(new TargetType()); + // + // Create our condition + // + final ConditionType condition = new ConditionType(); + // + // Check if we have all the fields (this can be a little + // ugly) but the ultimate goal is to simplify the policy + // condition to only check for necessary attributes. + // + ObjectFactory factory = new ObjectFactory(); + if (timeRange != null && minApply != null && maxApply != null) { + // + // All 3 must apply + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + applyAnd.getExpression().add(factory.createApply(timeRange)); + applyAnd.getExpression().add(factory.createApply(minApply)); + applyAnd.getExpression().add(factory.createApply(maxApply)); + // + // Add into the condition + // + condition.setExpression(factory.createApply(applyAnd)); + } else { + // + // At least one of these applies is null. We need at least + // two to require the And apply. Otherwise there is no need + // for an outer And apply as the single condition can work + // on its own. + // + if (timeRange != null && minApply == null && maxApply == null) { + // + // Only the time range check is necessary + // + condition.setExpression(factory.createApply(timeRange)); + } else if (timeRange == null && minApply != null && maxApply == null) { + // + // Only the min check is necessary + // + condition.setExpression(factory.createApply(minApply)); + } else if (timeRange == null && minApply == null) { + // + // Only the max check is necessary + // + condition.setExpression(factory.createApply(maxApply)); + } else { + // + // Ok we will need an outer And and have at least the + // time range and either min or max check + // + ApplyType applyAnd = new ApplyType(); + applyAnd.setDescription("return true if all the apply's are true."); + applyAnd.setFunctionId(XACML3.ID_FUNCTION_AND.stringValue()); + if (timeRange != null) { + applyAnd.getExpression().add(factory.createApply(timeRange)); + } + if (minApply != null) { + applyAnd.getExpression().add(factory.createApply(minApply)); + } + if (maxApply != null) { + applyAnd.getExpression().add(factory.createApply(maxApply)); + } + // + // Add into the condition + // + condition.setExpression(factory.createApply(applyAnd)); + } + } + // + // Add the condition + // + permit.setCondition(condition); + // + // TODO Add the advice - Is the request id needed to be returned? + // + // permit.setAdviceExpressions(adviceExpressions); + // + // Done + // + return permit; + } + + private static ApplyType generateTimeInRange(String start, String end) { + if (start == null || end == null) { + LOGGER.warn("Missing time range start {} end {}", start, end); + return null; + } + if (start.isEmpty() || end.isEmpty()) { + LOGGER.warn("Empty time range start {} end {}", start, end); + return null; + } + + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(XACML3.ID_ENVIRONMENT_CURRENT_TIME.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_ENVIRONMENT.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + + AttributeValueType valueStart = new AttributeValueType(); + valueStart.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + valueStart.getContent().add(start); + + AttributeValueType valueEnd = new AttributeValueType(); + valueEnd.setDataType(XACML3.ID_DATATYPE_TIME.stringValue()); + valueEnd.getContent().add(end); + + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the current time"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_TIME_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyTimeInRange = new ApplyType(); + applyTimeInRange.setDescription("return true if current time is in range."); + applyTimeInRange.setFunctionId(XACML3.ID_FUNCTION_TIME_IN_RANGE.stringValue()); + applyTimeInRange.getExpression().add(factory.createApply(applyOneAndOnly)); + applyTimeInRange.getExpression().add(factory.createAttributeValue(valueStart)); + applyTimeInRange.getExpression().add(factory.createAttributeValue(valueEnd)); + + return applyTimeInRange; + } + + private static ApplyType generateCountCheck(Integer limit, String timeWindow, String timeUnits) { + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_OPERATIONCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // TODO Add this back in when the operational database PIP is configured. + // The issuer indicates that the PIP will be providing this attribute during + // the decision making. + // + // Right now I am faking the count value by re-using the request-id field + // + //String issuer = "org:onap:xacml:guard:historydb:tw:" + timeWindow + ":" + timeUnits; + //designator.setIssuer(issuer); + + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(limit.toString()); + + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the limit"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is greater than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static ApplyType generateMinCheck(Integer min) { + if (min == null) { + return null; + } + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // + // + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(min.toString()); + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the min"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is greater than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_GREATER_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static ApplyType generateMaxCheck(Integer max) { + if (max == null) { + return null; + } + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_RESOURCE_GUARD_VFCOUNT.stringValue()); + designator.setCategory(XACML3.ID_ATTRIBUTE_CATEGORY_RESOURCE.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // + // + AttributeValueType valueLimit = new AttributeValueType(); + valueLimit.setDataType(XACML3.ID_DATATYPE_INTEGER.stringValue()); + // + // Yes really use toString(), the marshaller will + // throw an exception if this is an integer object + // and not a string. + // + valueLimit.getContent().add(max.toString()); + ObjectFactory factory = new ObjectFactory(); + + ApplyType applyOneAndOnly = new ApplyType(); + applyOneAndOnly.setDescription("Unbag the min"); + applyOneAndOnly.setFunctionId(XACML3.ID_FUNCTION_INTEGER_ONE_AND_ONLY.stringValue()); + applyOneAndOnly.getExpression().add(factory.createAttributeDesignator(designator)); + + ApplyType applyGreaterThanEqual = new ApplyType(); + applyGreaterThanEqual.setDescription("return true if current count is less than or equal."); + applyGreaterThanEqual.setFunctionId(XACML3.ID_FUNCTION_INTEGER_LESS_THAN_OR_EQUAL.stringValue()); + applyGreaterThanEqual.getExpression().add(factory.createApply(applyOneAndOnly)); + applyGreaterThanEqual.getExpression().add(factory.createAttributeValue(valueLimit)); + + return applyGreaterThanEqual; + } + + private static AdviceExpressionsType generateRequestIdAdvice() { + AdviceExpressionType adviceExpression = new AdviceExpressionType(); + adviceExpression.setAppliesTo(EffectType.PERMIT); + adviceExpression.setAdviceId(ToscaDictionary.ID_ADVICE_GUARD.stringValue()); + + AttributeDesignatorType designator = new AttributeDesignatorType(); + designator.setAttributeId(ToscaDictionary.ID_SUBJECT_GUARD_REQUESTID.stringValue()); + designator.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue()); + designator.setDataType(XACML3.ID_DATATYPE_STRING.stringValue()); + + AttributeAssignmentExpressionType assignment = new AttributeAssignmentExpressionType(); + assignment.setAttributeId(ToscaDictionary.ID_ADVICE_GUARD_REQUESTID.stringValue()); + assignment.setCategory(XACML3.ID_SUBJECT_CATEGORY_ACCESS_SUBJECT.stringValue()); + assignment.setExpression(new ObjectFactory().createAttributeDesignator(designator)); + + adviceExpression.getAttributeAssignmentExpression().add(assignment); + + AdviceExpressionsType adviceExpressions = new AdviceExpressionsType(); + adviceExpressions.getAdviceExpression().add(adviceExpression); + + return adviceExpressions; + } +} diff --git a/applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplicationTest.java b/applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplicationTest.java index ae4193d3..ff137e13 100644 --- a/applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplicationTest.java +++ b/applications/guard/src/test/java/org/onap/policy/xacml/pdp/application/guard/GuardPdpApplicationTest.java @@ -23,168 +23,300 @@ package org.onap.policy.xacml.pdp.application.guard; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; - -import com.att.research.xacml.util.XACMLProperties; -import com.google.common.io.Files; -import com.google.gson.Gson; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Path; -import java.nio.file.Paths; +import java.util.HashMap; import java.util.Iterator; +import java.util.Map; import java.util.Properties; import java.util.ServiceLoader; +import java.util.UUID; -import org.junit.Before; +import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runners.MethodSorters; +import org.onap.policy.common.utils.coder.CoderException; +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.models.decisions.serialization.DecisionRequestMessageBodyHandler; -import org.onap.policy.models.decisions.serialization.DecisionResponseMessageBodyHandler; +import org.onap.policy.models.decisions.concepts.DecisionResponse; import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class GuardPdpApplicationTest { private static final Logger LOGGER = LoggerFactory.getLogger(GuardPdpApplicationTest.class); private static Properties properties = new Properties(); private static File propertiesFile; private static XacmlApplicationServiceProvider service; - private static DecisionRequest requestSinglePolicy; - - private static Gson gsonDecisionRequest; - private static Gson gsonDecisionResponse; + private static DecisionRequest requestGuardPermit; + private static DecisionRequest requestGuardDeny; + private static DecisionRequest requestGuardDeny2; + private static StandardCoder gson = new StandardCoder(); @ClassRule public static final TemporaryFolder policyFolder = new TemporaryFolder(); - @Before - public void setUp() throws Exception { + /** + * Copies the xacml.properties and policies files into + * temporary folder and loads the service provider saving + * instance of provider off for other tests to use. + */ + @BeforeClass + public static void setUp() throws Exception { + // + // Setup our temporary folder + // + XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename); + propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties", + properties, myCreator); + // + // Load service + // + ServiceLoader applicationLoader = + ServiceLoader.load(XacmlApplicationServiceProvider.class); + // + // Find the guard service application and save for use in all the tests + // + StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator()); + Iterator iterator = applicationLoader.iterator(); + while (iterator.hasNext()) { + XacmlApplicationServiceProvider application = iterator.next(); + // + // Is it our service? + // + if (application instanceof GuardPdpApplication) { + // + // Should be the first and only one + // + assertThat(service).isNull(); + service = application; + } + strDump.append(application.applicationName()); + strDump.append(" supports "); + strDump.append(application.supportedPolicyTypes()); + strDump.append(System.lineSeparator()); + } + LOGGER.debug("{}", strDump); + // + // Tell it to initialize based on the properties file + // we just built for it. + // + service.initialize(propertiesFile.toPath().getParent()); + } + @Test + public void test1Basics() throws CoderException, IOException { + // + // Load Single Decision Request + // + requestGuardPermit = gson.decode( + TextFileUtils.getTextFileAsString( + "../../main/src/test/resources/decisions/decision.guard.shouldpermit.input.json"), + DecisionRequest.class); + // + // Load Single Decision Request + // + requestGuardDeny = gson.decode(TextFileUtils.getTextFileAsString( + "../../main/src/test/resources/decisions/decision.guard.shoulddeny.input.json"), + DecisionRequest.class); + // + // Load Single Decision Request + // + requestGuardDeny2 = gson.decode(TextFileUtils.getTextFileAsString( + "../../main/src/test/resources/decisions/decision.guard.shoulddeny.input2.json"), + DecisionRequest.class); + // + // Make sure there's an application name + // + assertThat(service.applicationName()).isNotEmpty(); + // + // Decisions + // + assertThat(service.actionDecisionsSupported().size()).isEqualTo(1); + assertThat(service.actionDecisionsSupported()).contains("guard"); + // + // Ensure it has the supported policy types and + // can support the correct policy types. + // + assertThat(service.supportedPolicyTypes()).isNotEmpty(); + assertThat(service.supportedPolicyTypes().size()).isEqualTo(2); + assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.0")) + .isTrue(); + assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.1")) + .isFalse(); + assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.0")).isTrue(); + assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.1")).isFalse(); + assertThat(service.canSupportPolicyType("onap.foo", "1.0.1")).isFalse(); } @Test - public void testBasics() { - assertThatCode(() -> { + public void test2NoPolicies() { + // + // Ask for a decision + // + DecisionResponse response = service.makeDecision(requestGuardPermit); + LOGGER.info("Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Permit"); + } + + @Test + public void test3FrequencyLimiter() throws CoderException, FileNotFoundException, IOException { + // + // Now load the vDNS frequency limiter Policy - make sure + // the pdp can support it and have it load + // into the PDP. + // + try (InputStream is = new FileInputStream("src/test/resources/vDNS.policy.guard.frequency.output.tosca.yaml")) { // - // Create our Gson builder + // Have yaml parse it // - gsonDecisionRequest = new DecisionRequestMessageBodyHandler().getGson(); - gsonDecisionResponse = new DecisionResponseMessageBodyHandler().getGson(); + Yaml yaml = new Yaml(); + Map toscaObject = yaml.load(is); // - // Load Single Decision Request + // Load the policies // - requestSinglePolicy = gsonDecisionRequest.fromJson( - TextFileUtils - .getTextFileAsString("../../main/src/test/resources/decisions/decision.single.input.json"), - DecisionRequest.class); + service.loadPolicies(toscaObject); // - // Copy all the properties and root policies to the temporary folder + // Ask for a decision - should get permit // - try (InputStream is = new FileInputStream("src/test/resources/xacml.properties")) { - // - // Load it in - // - properties.load(is); - propertiesFile = policyFolder.newFile("xacml.properties"); - // - // Copy the root policies - // - for (String root : XACMLProperties.getRootPolicyIDs(properties)) { - // - // Get a file - // - Path rootPath = Paths.get(properties.getProperty(root + ".file")); - LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName()); - // - // Construct new file name - // - File newRootPath = policyFolder.newFile(rootPath.getFileName().toString()); - // - // Copy it - // - Files.copy(rootPath.toFile(), newRootPath); - assertThat(newRootPath).exists(); - // - // Point to where the new policy is in the temp dir - // - properties.setProperty(root + ".file", newRootPath.getAbsolutePath()); - } - try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) { - properties.store(os, ""); - assertThat(propertiesFile).exists(); - } - } + DecisionResponse response = service.makeDecision(requestGuardPermit); + LOGGER.info("Looking for Permit Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Permit"); // - // Load service + // Dump it out as Json // - ServiceLoader applicationLoader = - ServiceLoader.load(XacmlApplicationServiceProvider.class); + LOGGER.info(gson.encode(response)); // - // Iterate through them - I could store the object as - // XacmlApplicationServiceProvider pointer. + // Ask for a decision - should get deny // - // Try this later. + response = service.makeDecision(requestGuardDeny2); + LOGGER.info("Looking for Deny Decision {}", response); + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Deny"); // - StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator()); - Iterator iterator = applicationLoader.iterator(); - while (iterator.hasNext()) { - XacmlApplicationServiceProvider application = iterator.next(); - // - // Is it our service? - // - if (application instanceof GuardPdpApplication) { - // - // Should be the first and only one - // - assertThat(service).isNull(); - service = application; - } - strDump.append(application.applicationName()); - strDump.append(" supports "); - strDump.append(application.supportedPolicyTypes()); - strDump.append(System.lineSeparator()); - } - LOGGER.debug("{}", strDump); + // Dump it out as Json + // + LOGGER.info(gson.encode(response)); + } + } + + @Test + public void test4MinMax() throws CoderException, FileNotFoundException, IOException { + // + // Now load the vDNS min max Policy - make sure + // the pdp can support it and have it load + // into the PDP. + // + try (InputStream is = new FileInputStream("src/test/resources/vDNS.policy.guard.minmax.output.tosca.yaml")) { + // + // Have yaml parse it + // + Yaml yaml = new Yaml(); + Map toscaObject = yaml.load(is); + // + // Load the policies + // + service.loadPolicies(toscaObject); + // + // Ask for a decision - should get permit + // + DecisionResponse response = service.makeDecision(requestGuardPermit); + LOGGER.info("Looking for Permit Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Permit"); + // + // Dump it out as Json + // + LOGGER.info(gson.encode(response)); + // + // Ask for a decision - should get deny + // + response = service.makeDecision(requestGuardDeny); + LOGGER.info("Looking for Deny Decision {}", response); + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Deny"); + // + // Dump it out as Json + // + LOGGER.info(gson.encode(response)); + } + } + + @Test + public void test5MissingFields() throws FileNotFoundException, IOException { + LOGGER.debug("Running test5"); + // + // Most likely we would not get a policy with missing fields passed to + // us from the API. But in case that happens, or we decide that some fields + // will be optional due to re-working of how the XACML policies are built, + // let's add support in for that. + // + try (InputStream is = new FileInputStream("src/test/resources/guard.policy-minmax-missing-fields1.yaml")) { // - // Tell it to initialize based on the properties file - // we just built for it. + // Have yaml parse it // - service.initialize(propertiesFile.toPath().getParent()); + Yaml yaml = new Yaml(); + Map toscaObject = yaml.load(is); // - // Make sure there's an application name + // Load the policies // - assertThat(service.applicationName()).isNotEmpty(); + service.loadPolicies(toscaObject); // - // Decisions + // We can create a DecisionRequest on the fly - no need + // to have it in the .json files // - assertThat(service.actionDecisionsSupported().size()).isEqualTo(1); - assertThat(service.actionDecisionsSupported()).contains("guard"); + DecisionRequest request = new DecisionRequest(); + request.setOnapName("JUnit"); + request.setOnapComponent("test5MissingFields"); + request.setRequestId(UUID.randomUUID().toString()); + request.setAction("guard"); + Map guard = new HashMap<>(); + guard.put("actor", "FOO"); + guard.put("recipe", "bar"); + guard.put("vfCount", "4"); + Map resource = new HashMap<>(); + resource.put("guard", guard); + request.setResource(resource); // - // Ensure it has the supported policy types and - // can support the correct policy types. + // Ask for a decision - should get permit // - assertThat(service.supportedPolicyTypes()).isNotEmpty(); - assertThat(service.supportedPolicyTypes().size()).isEqualTo(2); - assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.0")) - .isTrue(); - assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.FrequencyLimiter", "1.0.1")) - .isFalse(); - assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.0")).isTrue(); - assertThat(service.canSupportPolicyType("onap.policies.controlloop.guard.MinMax", "1.0.1")).isFalse(); - assertThat(service.canSupportPolicyType("onap.foo", "1.0.1")).isFalse(); + DecisionResponse response = service.makeDecision(request); + LOGGER.info("Looking for Permit Decision {}", response); + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Permit"); // - // Ensure it supports decisions + // Try a deny // - assertThat(service.actionDecisionsSupported()).contains("guard"); - }).doesNotThrowAnyException(); + guard.put("vfCount", "10"); + resource.put("guard", guard); + request.setResource(resource); + response = service.makeDecision(request); + LOGGER.info("Looking for Deny Decision {}", response); + assertThat(response).isNotNull(); + assertThat(response.getStatus()).isNotNull(); + assertThat(response.getStatus()).isEqualTo("Deny"); + } } } diff --git a/applications/guard/src/test/resources/guard.policy-minmax-missing-fields1.yaml b/applications/guard/src/test/resources/guard.policy-minmax-missing-fields1.yaml new file mode 100644 index 00000000..6a441182 --- /dev/null +++ b/applications/guard/src/test/resources/guard.policy-minmax-missing-fields1.yaml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +topology_template: + policies: + - + guard.minmax.missing1: + type: onap.policies.controlloop.guard.MinMax + version: 1.0.0 + metadata: + policy-id : guard.minmax.scaleout + policy-version: 1 + properties: + actor: FOO + recipe: bar +# targets: *. +# clname: ControlLoop-Foo-Bar + min: 1 + max: 5 +# guardActiveStart: 00:00:01-05:00 +# guardActiveEnd: 23:59:59-05:00 diff --git a/applications/guard/src/test/resources/vDNS.policy.guard.frequency.output.tosca.yaml b/applications/guard/src/test/resources/vDNS.policy.guard.frequency.output.tosca.yaml new file mode 100644 index 00000000..03afd5e2 --- /dev/null +++ b/applications/guard/src/test/resources/vDNS.policy.guard.frequency.output.tosca.yaml @@ -0,0 +1,20 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +topology_template: + policies: + - + guard.frequency.scaleout: + type: onap.policies.controlloop.guard.FrequencyLimiter + version: 1.0.0 + metadata: + policy-id: guard.frequency.scaleout + policy-version: 1 + properties: + actor: SO + recipe: scaleOut + targets: .* + clname: ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3 + limit: 1 + timeWindow: 10 + timeUnits: minute + guardActiveStart: 00:00:01-05:00 + guardActiveEnd: 23:59:59-05:00 diff --git a/applications/guard/src/test/resources/vDNS.policy.guard.minmax.output.tosca.yaml b/applications/guard/src/test/resources/vDNS.policy.guard.minmax.output.tosca.yaml new file mode 100644 index 00000000..5ac76015 --- /dev/null +++ b/applications/guard/src/test/resources/vDNS.policy.guard.minmax.output.tosca.yaml @@ -0,0 +1,19 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +topology_template: + policies: + - + guard.minmax.scaleout: + type: onap.policies.controlloop.guard.MinMax + version: 1.0.0 + metadata: + policy-id : guard.minmax.scaleout + policy-version: 1 + properties: + actor: SO + recipe: scaleOut + targets: .* + clname: ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3 + min: 1 + max: 5 + guardActiveStart: 00:00:01-05:00 + guardActiveEnd: 23:59:59-05:00 diff --git a/applications/guard/src/test/resources/xacml.properties b/applications/guard/src/test/resources/xacml.properties index b32a936c..9bd7bfb8 100644 --- a/applications/guard/src/test/resources/xacml.properties +++ b/applications/guard/src/test/resources/xacml.properties @@ -20,18 +20,13 @@ xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctio xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory # -# ONAP Implementation Factories +# Use a root combining algorithm # -#xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapApplicationPolicyFinder +xacml.att.policyFinderFactory.combineRootPolicies=urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:permit-unless-deny -# -# NOTE: If you are testing against a RESTful PDP, then the PDP must be configured with the -# policies and PIP configuration as defined below. Otherwise, this is the configuration that -# the embedded PDP uses. -# # Policies to load # -xacml.rootPolicies=guard -guard.file=src/main/resources/RootGuardPolicy.xml +#xacml.rootPolicies=guard +#guard.file=src/main/resources/RootGuardPolicy.xml diff --git a/applications/monitoring/pom.xml b/applications/monitoring/pom.xml index 018c3722..d477bee7 100644 --- a/applications/monitoring/pom.xml +++ b/applications/monitoring/pom.xml @@ -33,15 +33,6 @@ This modules contains applications that implement policy-types for XACML PDP. - - com.google.code.gson - gson - - - org.onap.policy.common - common-parameters - ${policy.common.version} - org.onap.policy.xacml-pdp.applications common diff --git a/applications/monitoring/src/main/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringRequest.java b/applications/monitoring/src/main/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringRequest.java deleted file mode 100644 index ce0bd3f2..00000000 --- a/applications/monitoring/src/main/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringRequest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * ONAP Policy Decision Models - * ================================================================================ - * Copyright (C) 2019 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. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ============LICENSE_END========================================================= - */ - -package org.onap.policy.xacml.pdp.application.monitoring; - -import com.att.research.xacml.std.annotations.XACMLAction; -import com.att.research.xacml.std.annotations.XACMLRequest; -import com.att.research.xacml.std.annotations.XACMLResource; -import com.att.research.xacml.std.annotations.XACMLSubject; - -import java.util.Map; -import java.util.Map.Entry; - -import org.onap.policy.models.decisions.concepts.DecisionRequest; - -@XACMLRequest(ReturnPolicyIdList = true) -public class MonitoringRequest { - - @XACMLSubject(includeInResults = true) - String onapName = "DCAE"; - - @XACMLResource(includeInResults = true) - String resource = "onap.policies.Monitoring"; - - @XACMLAction() - String action = "configure"; - - - /** - * Parses the DecisionRequest into a MonitoringRequest. - * - * @param decisionRequest Input DecisionRequest - * @return MonitoringRequest - */ - public static MonitoringRequest createInstance(DecisionRequest decisionRequest) { - MonitoringRequest request = new MonitoringRequest(); - request.onapName = decisionRequest.getOnapName(); - request.action = decisionRequest.getAction(); - - Map resources = decisionRequest.getResource(); - for (Entry entry : resources.entrySet()) { - if ("policy-id".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); - continue; - } - if ("policy-type".equals(entry.getKey())) { - // - // TODO handle lists of policies - // - request.resource = entry.getValue().toString(); - } - } - // - // TODO handle a bad incoming request. Do that here? - // - return request; - } -} diff --git a/applications/monitoring/src/test/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringPdpApplicationTest.java b/applications/monitoring/src/test/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringPdpApplicationTest.java index d3624a64..4af4bac4 100644 --- a/applications/monitoring/src/test/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringPdpApplicationTest.java +++ b/applications/monitoring/src/test/java/org/onap/policy/xacml/pdp/application/monitoring/MonitoringPdpApplicationTest.java @@ -23,20 +23,11 @@ package org.onap.policy.xacml.pdp.application.monitoring; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatCode; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; - -import com.att.research.xacml.util.XACMLProperties; -import com.google.common.io.Files; -import com.google.gson.Gson; import java.io.File; import java.io.FileInputStream; -import java.io.FileOutputStream; +import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -46,19 +37,22 @@ import java.util.ServiceLoader; import org.junit.BeforeClass; import org.junit.ClassRule; +import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.rules.TemporaryFolder; +import org.junit.runners.MethodSorters; +import org.onap.policy.common.utils.coder.CoderException; +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.models.decisions.concepts.DecisionResponse; -import org.onap.policy.models.decisions.serialization.DecisionRequestMessageBodyHandler; -import org.onap.policy.models.decisions.serialization.DecisionResponseMessageBodyHandler; -import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yaml.snakeyaml.Yaml; +@FixMethodOrder(MethodSorters.NAME_ASCENDING) public class MonitoringPdpApplicationTest { private static final Logger LOGGER = LoggerFactory.getLogger(MonitoringPdpApplicationTest.class); @@ -67,210 +61,166 @@ public class MonitoringPdpApplicationTest { private static XacmlApplicationServiceProvider service; private static DecisionRequest requestSinglePolicy; - private static Gson gsonDecisionRequest; - private static Gson gsonDecisionResponse; + private static StandardCoder gson = new StandardCoder(); @ClassRule public static final TemporaryFolder policyFolder = new TemporaryFolder(); /** - * Load a test engine. + * Copies the xacml.properties and policies files into + * temporary folder and loads the service provider saving + * instance of provider off for other tests to use. */ @BeforeClass - public static void setup() { - assertThatCode(() -> { - // - // Create our Gson builder - // - gsonDecisionRequest = new DecisionRequestMessageBodyHandler().getGson(); - gsonDecisionResponse = new DecisionResponseMessageBodyHandler().getGson(); - // - // Load Single Decision Request - // - requestSinglePolicy = gsonDecisionRequest.fromJson( - TextFileUtils - .getTextFileAsString("../../main/src/test/resources/decisions/decision.single.input.json"), - DecisionRequest.class); - // - // Copy all the properties and root policies to the temporary folder - // - try (InputStream is = new FileInputStream("src/test/resources/xacml.properties")) { - // - // Load it in - // - properties.load(is); - propertiesFile = policyFolder.newFile("xacml.properties"); - // - // Copy the root policies - // - for (String root : XACMLProperties.getRootPolicyIDs(properties)) { - // - // Get a file - // - Path rootPath = Paths.get(properties.getProperty(root + ".file")); - LOGGER.debug("Root file {} {}", rootPath, rootPath.getFileName()); - // - // Construct new file name - // - File newRootPath = policyFolder.newFile(rootPath.getFileName().toString()); - // - // Copy it - // - Files.copy(rootPath.toFile(), newRootPath); - assertThat(newRootPath).exists(); - // - // Point to where the new policy is in the temp dir - // - properties.setProperty(root + ".file", newRootPath.getAbsolutePath()); - } - try (OutputStream os = new FileOutputStream(propertiesFile.getAbsolutePath())) { - properties.store(os, ""); - assertThat(propertiesFile).exists(); - } - } - // - // Load service - // - ServiceLoader applicationLoader = - ServiceLoader.load(XacmlApplicationServiceProvider.class); - // - // Iterate through them - I could store the object as - // XacmlApplicationServiceProvider pointer. + public static void setup() throws Exception { + // + // Load Single Decision Request + // + requestSinglePolicy = gson.decode( + TextFileUtils + .getTextFileAsString("../../main/src/test/resources/decisions/decision.single.input.json"), + DecisionRequest.class); + // + // Setup our temporary folder + // + XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename); + propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties", + properties, myCreator); + // + // Load XacmlApplicationServiceProvider service + // + ServiceLoader applicationLoader = + ServiceLoader.load(XacmlApplicationServiceProvider.class); + // + // Look for our class instance and save it + // + StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator()); + Iterator iterator = applicationLoader.iterator(); + while (iterator.hasNext()) { + XacmlApplicationServiceProvider application = iterator.next(); // - // Try this later. + // Is it our service? // - StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator()); - Iterator iterator = applicationLoader.iterator(); - while (iterator.hasNext()) { - XacmlApplicationServiceProvider application = iterator.next(); + if (application instanceof MonitoringPdpApplication) { // - // Is it our service? + // Should be the first and only one // - if (application instanceof MonitoringPdpApplication) { - // - // Should be the first and only one - // - assertThat(service).isNull(); - service = application; - } - strDump.append(application.applicationName()); - strDump.append(" supports "); - strDump.append(application.supportedPolicyTypes()); - strDump.append(System.lineSeparator()); + assertThat(service).isNull(); + service = application; } - LOGGER.debug("{}", strDump); - // - // Tell it to initialize based on the properties file - // we just built for it. - // - service.initialize(propertiesFile.toPath().getParent()); - // - // Make sure there's an application name - // - assertThat(service.applicationName()).isNotEmpty(); - // - // Ensure it has the supported policy types and - // can support the correct policy types. - // - assertThat(service.canSupportPolicyType("onap.Monitoring", "1.0.0")).isTrue(); - assertThat(service.canSupportPolicyType("onap.Monitoring", "1.5.0")).isTrue(); - assertThat(service.canSupportPolicyType("onap.policies.monitoring.foobar", "1.0.1")).isTrue(); - assertThat(service.canSupportPolicyType("onap.foobar", "1.0.0")).isFalse(); - assertThat(service.supportedPolicyTypes()).contains("onap.Monitoring"); - // - // Ensure it supports decisions - // - assertThat(service.actionDecisionsSupported()).contains("configure"); - }).doesNotThrowAnyException(); + strDump.append(application.applicationName()); + strDump.append(" supports "); + strDump.append(application.supportedPolicyTypes()); + strDump.append(System.lineSeparator()); + } + LOGGER.debug("{}", strDump); + // + // Tell it to initialize based on the properties file + // we just built for it. + // + service.initialize(propertiesFile.toPath().getParent()); } @Test - public void testNoPolicies() { + public void test1Basics() { // - // Make a simple decision - NO policies are loaded + // Make sure there's an application name // - assertThatCode(() -> { - // - // Ask for a decision - // - DecisionResponse response = service.makeDecision(requestSinglePolicy); - LOGGER.info("Decision {}", response); + assertThat(service.applicationName()).isNotEmpty(); + // + // Ensure it has the supported policy types and + // can support the correct policy types. + // + assertThat(service.canSupportPolicyType("onap.Monitoring", "1.0.0")).isTrue(); + assertThat(service.canSupportPolicyType("onap.Monitoring", "1.5.0")).isTrue(); + assertThat(service.canSupportPolicyType("onap.policies.monitoring.foobar", "1.0.1")).isTrue(); + assertThat(service.canSupportPolicyType("onap.foobar", "1.0.0")).isFalse(); + assertThat(service.supportedPolicyTypes()).contains("onap.Monitoring"); + // + // Ensure it supports decisions + // + assertThat(service.actionDecisionsSupported()).contains("configure"); + } - assertThat(response).isNotNull(); - assertThat(response.getErrorMessage()).isNullOrEmpty(); - assertThat(response.getPolicies().size()).isEqualTo(0); + @Test + public void test2NoPolicies() { + // + // Ask for a decision + // + DecisionResponse response = service.makeDecision(requestSinglePolicy); + LOGGER.info("Decision {}", response); - }).doesNotThrowAnyException(); + assertThat(response).isNotNull(); + assertThat(response.getPolicies().size()).isEqualTo(0); } @SuppressWarnings("unchecked") @Test - public void testvDnsPolicy() { + public void test3AddvDnsPolicy() throws IOException, CoderException { // // Now load the vDNS Policy - make sure // the pdp can support it and have it load // into the PDP. // - assertThatCode(() -> { - try (InputStream is = new FileInputStream("src/test/resources/vDNS.policy.input.yaml")) { - Yaml yaml = new Yaml(); - Map toscaObject = yaml.load(is); - List policies = (List) toscaObject.get("policies"); - // - // What we should really do is split the policies out from the ones that - // are not supported to ones that are. And then load these. + try (InputStream is = new FileInputStream("src/test/resources/vDNS.policy.input.yaml")) { + // + // Have yaml parse it + // + Yaml yaml = new Yaml(); + Map toscaObject = yaml.load(is); + List policies = (List) toscaObject.get("policies"); + // + // Sanity check to ensure the policy type and version are supported + // + for (Object policyObject : policies) { // - // In another future review.... + // Get the contents // - for (Object policyObject : policies) { + Map policyContents = (Map) policyObject; + for (Entry entrySet : policyContents.entrySet()) { + LOGGER.info("Entry set {}", entrySet.getKey()); + Map policyDefinition = (Map) entrySet.getValue(); // - // Get the contents + // Find the type and make sure the engine supports it // - Map policyContents = (Map) policyObject; - for (Entry entrySet : policyContents.entrySet()) { - LOGGER.info("Entry set {}", entrySet.getKey()); - Map policyDefinition = (Map) entrySet.getValue(); - // - // Find the type and make sure the engine supports it - // - assertThat(policyDefinition.containsKey("type")).isTrue(); - assertThat(service.canSupportPolicyType( - policyDefinition.get("type").toString(), - policyDefinition.get("version").toString())) - .isTrue(); - } + assertThat(policyDefinition.containsKey("type")).isTrue(); + assertThat(service.canSupportPolicyType( + policyDefinition.get("type").toString(), + policyDefinition.get("version").toString())) + .isTrue(); } - // - // Just go ahead and load them all for now - // - // Assuming all are supported etc. - // - service.loadPolicies(toscaObject); - // - // Ask for a decision - // - DecisionResponse response = service.makeDecision(requestSinglePolicy); - LOGGER.info("Decision {}", response); - - assertThat(response).isNotNull(); - assertThat(response.getPolicies().size()).isEqualTo(1); - // - // Dump it out as Json - // - LOGGER.info(gsonDecisionResponse.toJson(response)); } - }).doesNotThrowAnyException(); + // + // Load the policies + // + service.loadPolicies(toscaObject); + // + // Ask for a decision + // + DecisionResponse response = service.makeDecision(requestSinglePolicy); + LOGGER.info("Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getPolicies().size()).isEqualTo(1); + // + // Dump it out as Json + // + LOGGER.info(gson.encode(response)); + } } @Test - public void testBadPolicies() { + public void test4BadPolicies() { + /* + * + * THESE TEST SHOULD BE MOVED INTO THE API PROJECT + * // // No need for service, just test some of the methods // for bad policies // MonitoringPdpApplication onapPdpEngine = new MonitoringPdpApplication(); - /* assertThatExceptionOfType(ToscaPolicyConversionException.class).isThrownBy(() -> { try (InputStream is = new FileInputStream("src/test/resources/test.monitoring.policy.missingmetadata.yaml")) { diff --git a/applications/monitoring/src/test/resources/vDNS.policy.decision.payload.json b/applications/monitoring/src/test/resources/vDNS.policy.decision.payload.json deleted file mode 100644 index e69de29b..00000000 diff --git a/applications/monitoring/src/test/resources/xacml.properties b/applications/monitoring/src/test/resources/xacml.properties index 9b5330dc..56a92d69 100644 --- a/applications/monitoring/src/test/resources/xacml.properties +++ b/applications/monitoring/src/test/resources/xacml.properties @@ -19,14 +19,6 @@ xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctio # xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory -# -# NOTE: If you are testing against a RESTful PDP, then the PDP must be configured with the -# policies and PIP configuration as defined below. Otherwise, this is the configuration that -# the embedded PDP uses. -# - -policytypes=onap.Monitoring, onap.policies.monitoring.cdap.tca.hi.lo.app - # Policies to load # xacml.rootPolicies=monitoring diff --git a/applications/optimization/pom.xml b/applications/optimization/pom.xml new file mode 100644 index 00000000..0723ec5e --- /dev/null +++ b/applications/optimization/pom.xml @@ -0,0 +1,43 @@ + + + + 4.0.0 + + org.onap.policy.xacml-pdp.applications + applications + 2.0.0-SNAPSHOT + + + optimization + + ${project.artifactId} + This modules contains applications that implement policy-types for XACML PDP. + + + + org.onap.policy.xacml-pdp.applications + common + ${project.version} + + + + diff --git a/applications/optimization/src/main/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplication.java b/applications/optimization/src/main/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplication.java new file mode 100644 index 00000000..4a4a6046 --- /dev/null +++ b/applications/optimization/src/main/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplication.java @@ -0,0 +1,164 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.xacml.pdp.application.optimization; + +import com.att.research.xacml.api.Request; +import com.att.research.xacml.api.Response; +import com.att.research.xacml.util.XACMLPolicyWriter; +import com.google.common.collect.Lists; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import oasis.names.tc.xacml._3_0.core.schema.wd_17.PolicyType; + +import org.onap.policy.models.decisions.concepts.DecisionRequest; +import org.onap.policy.models.decisions.concepts.DecisionResponse; +import org.onap.policy.pdp.xacml.application.common.ToscaPolicyConversionException; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; +import org.onap.policy.pdp.xacml.application.common.std.StdMatchableTranslator; +import org.onap.policy.pdp.xacml.application.common.std.StdXacmlApplicationServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class OptimizationPdpApplication extends StdXacmlApplicationServiceProvider { + + private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplication.class); + private static final String STRING_VERSION100 = "1.0.0"; + + private StdMatchableTranslator translator = new StdMatchableTranslator(); + private Map supportedPolicyTypes = new HashMap<>(); + + /** + * Constructor. + */ + public OptimizationPdpApplication() { + this.supportedPolicyTypes.put("onap.policies.optimization.AffinityPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.DistancePolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.HpaPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.OptimizationPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.PciPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.QueryPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.SubscriberPolicy", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.Vim_fit", STRING_VERSION100); + this.supportedPolicyTypes.put("onap.policies.optimization.VnfPolicy", STRING_VERSION100); + } + + @Override + public String applicationName() { + return "Optimization Application"; + } + + @Override + public List actionDecisionsSupported() { + return Arrays.asList("optimize"); + } + + @Override + public synchronized List supportedPolicyTypes() { + return Lists.newArrayList(supportedPolicyTypes.keySet()); + } + + @Override + public boolean canSupportPolicyType(String policyType, String policyTypeVersion) { + // + // For the time being, restrict this if the version isn't known. + // Could be too difficult to support changing of versions dynamically. + // + if (! this.supportedPolicyTypes.containsKey(policyType)) { + return false; + } + // + // Must match version exactly + // + return this.supportedPolicyTypes.get(policyType).equals(policyTypeVersion); + } + + @Override + public synchronized void loadPolicies(Map toscaPolicies) { + try { + // + // Convert the policies first + // + List listPolicies = translator.scanAndConvertPolicies(toscaPolicies); + if (listPolicies.isEmpty()) { + throw new ToscaPolicyConversionException("Converted 0 policies"); + } + // + // Create a copy of the properties object + // + Properties newProperties = this.getProperties(); + // + // Iterate through the policies + // + for (PolicyType newPolicy : listPolicies) { + // + // Construct the filename + // + Path refPath = XacmlPolicyUtils.constructUniquePolicyFilename(newPolicy, this.getDataPath()); + // + // Write the policy to disk + // Maybe check for an error + // + XACMLPolicyWriter.writePolicyFile(refPath, newPolicy); + // + // Add root policy to properties object + // + XacmlPolicyUtils.addRootPolicy(newProperties, refPath); + } + // + // Write the properties to disk + // + XacmlPolicyUtils.storeXacmlProperties(newProperties, + XacmlPolicyUtils.getPropertiesPath(this.getDataPath())); + // + // Reload the engine + // + this.createEngine(newProperties); + } catch (IOException | ToscaPolicyConversionException e) { + LOGGER.error("Failed to loadPolicies {}", e); + } + } + + @Override + public synchronized DecisionResponse makeDecision(DecisionRequest request) { + // + // Convert to a XacmlRequest + // + Request xacmlRequest = translator.convertRequest(request); + // + // Now get a decision + // + Response xacmlResponse = this.xacmlDecision(xacmlRequest); + // + // Convert to a DecisionResponse + // + return translator.convertResponse(xacmlResponse); + } + +} diff --git a/applications/optimization/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider b/applications/optimization/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider new file mode 100644 index 00000000..ffb7e802 --- /dev/null +++ b/applications/optimization/src/main/resources/META-INF/services/org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider @@ -0,0 +1 @@ +org.onap.policy.xacml.pdp.application.optimization.OptimizationPdpApplication \ No newline at end of file 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 new file mode 100644 index 00000000..efbf730c --- /dev/null +++ b/applications/optimization/src/test/java/org/onap/policy/xacml/pdp/application/optimization/OptimizationPdpApplicationTest.java @@ -0,0 +1,211 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * Copyright (C) 2019 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.policy.xacml.pdp.application.optimization; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +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 org.junit.BeforeClass; +import org.junit.ClassRule; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.junit.runners.MethodSorters; +import org.onap.policy.common.utils.coder.CoderException; +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.models.decisions.concepts.DecisionResponse; +import org.onap.policy.pdp.xacml.application.common.XacmlApplicationServiceProvider; +import org.onap.policy.pdp.xacml.application.common.XacmlPolicyUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.yaml.snakeyaml.Yaml; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class OptimizationPdpApplicationTest { + + private static final Logger LOGGER = LoggerFactory.getLogger(OptimizationPdpApplicationTest.class); + private static Properties properties = new Properties(); + private static File propertiesFile; + private static XacmlApplicationServiceProvider service; + private static StandardCoder gson = new StandardCoder(); + private static DecisionRequest requestAffinity; + + @ClassRule + public static final TemporaryFolder policyFolder = new TemporaryFolder(); + + /** + * Copies the xacml.properties and policies files into + * temporary folder and loads the service provider saving + * instance of provider off for other tests to use. + */ + @BeforeClass + public static void setUp() throws Exception { + // + // Load Single Decision Request + // + requestAffinity = gson.decode( + TextFileUtils + .getTextFileAsString( + "../../main/src/test/resources/decisions/decision.optimization.affinity.input.json"), + DecisionRequest.class); + // + // Setup our temporary folder + // + XacmlPolicyUtils.FileCreator myCreator = (String filename) -> policyFolder.newFile(filename); + propertiesFile = XacmlPolicyUtils.copyXacmlPropertiesContents("src/test/resources/xacml.properties", + properties, myCreator); + // + // Load service + // + ServiceLoader applicationLoader = + ServiceLoader.load(XacmlApplicationServiceProvider.class); + // + // Iterate through Xacml application services and find + // the optimization service. Save it for use throughout + // all the Junit tests. + // + StringBuilder strDump = new StringBuilder("Loaded applications:" + System.lineSeparator()); + Iterator iterator = applicationLoader.iterator(); + while (iterator.hasNext()) { + XacmlApplicationServiceProvider application = iterator.next(); + // + // Is it our service? + // + if (application instanceof OptimizationPdpApplication) { + // + // Should be the first and only one + // + assertThat(service).isNull(); + service = application; + } + strDump.append(application.applicationName()); + strDump.append(" supports "); + strDump.append(application.supportedPolicyTypes()); + strDump.append(System.lineSeparator()); + } + LOGGER.debug("{}", strDump); + // + // Tell it to initialize based on the properties file + // we just built for it. + // + service.initialize(propertiesFile.toPath().getParent()); + } + + @Test + public void test1Basics() { + // + // Make sure there's an application name + // + assertThat(service.applicationName()).isNotEmpty(); + // + // Decisions + // + assertThat(service.actionDecisionsSupported().size()).isEqualTo(1); + assertThat(service.actionDecisionsSupported()).contains("optimize"); + // + // Ensure it has the supported policy types and + // can support the correct policy types. + // + assertThat(service.canSupportPolicyType("onap.policies.optimization.AffinityPolicy", "1.0.0")).isTrue(); + assertThat(service.canSupportPolicyType("onap.foobar", "1.0.0")).isFalse(); + } + + @Test + public void test2NoPolicies() { + // + // Ask for a decision + // + DecisionResponse response = service.makeDecision(requestAffinity); + LOGGER.info("Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getPolicies().size()).isEqualTo(0); + } + + @SuppressWarnings("unchecked") + @Test + public void test3AddOptimizationPolicies() throws CoderException, FileNotFoundException, IOException { + // + // Now load the optimization policies + // + try (InputStream is = new FileInputStream("src/test/resources/vCPE.policies.optimization.input.tosca.yaml")) { + // + // Have yaml parse it + // + Yaml yaml = new Yaml(); + Map toscaObject = yaml.load(is); + List policies = (List) toscaObject.get("policies"); + // + // Sanity check to ensure the policy type and version are supported + // + for (Object policyObject : policies) { + // + // Get the contents + // + Map policyContents = (Map) policyObject; + for (Entry entrySet : policyContents.entrySet()) { + LOGGER.info("Entry set {}", entrySet.getKey()); + Map policyDefinition = (Map) entrySet.getValue(); + // + // Find the type and make sure the engine supports it + // + assertThat(policyDefinition.containsKey("type")).isTrue(); + assertThat(service.canSupportPolicyType( + policyDefinition.get("type").toString(), + policyDefinition.get("version").toString())) + .isTrue(); + } + } + // + // Load the policies + // + service.loadPolicies(toscaObject); + // + // Ask for a decision + // + DecisionResponse response = service.makeDecision(requestAffinity); + LOGGER.info("Decision {}", response); + + assertThat(response).isNotNull(); + assertThat(response.getPolicies().size()).isEqualTo(1); + // + // Dump it out as Json + // + LOGGER.info(gson.encode(response)); + } + } + +} 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 new file mode 100644 index 00000000..2fc7c140 --- /dev/null +++ b/applications/optimization/src/test/resources/vCPE.policies.optimization.input.tosca.yaml @@ -0,0 +1,137 @@ +tosca_definitions_version: tosca_simple_yaml_1_0_0 +topology_template: +policies: + - + OSDF_CASABLANCA.Affinity_vCPE_1: + type: onap.policies.optimization.AffinityPolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.Affinity_vCPE_1 + policy-version: 1 + properties: + identity: affinity_vCPE + policyScope: [vCPE, US, INTERNATIONAL, ip, vGMuxInfra, vG] + affinityProperties: + qualifier: same + category: complex + policyType: zone + resources: [vGMuxInfra, vG] + - + OSDF_CASABLANCA.Capacity_vG_1: + type: onap.policies.optimization.Vim_fit + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.Capacity_vG_1 + policy-version: 1 + properties: + identity: capacity_vG + policyScope: [VCPE, US, INTERNATIONAL, ip, vG] + resources: [vG] + capacityProperty: + controller: multicloud + request: "{\"vCPU\": 10, \"Memory\": {\"quantity\": {\"get_param\": \"REQUIRED_MEM\"}, \"unit\": \"GB\"}, \"Storage\": {\"quantity\": {\"get_param\": \"REQUIRED_DISK\"}, \"unit\": \"GB\"}}" + policyType: vim_fit + applicableResources: any + - + OSDF_CASABLANCA.Distance_vG_1: + type: onap.policies.optimization.DistancePolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.Distance_vG_1 + policy-version: 1 + properties: + distanceProperties: + locationInfo: customer_loc + distance: + value: 1500 + operator: "<" + unit: km + identity: "distance-vG" + resources: [vG] + policyScope: [vCPE, US, INTERNATIONAL, ip, vG] + policyType: distance_to_location + applicableResources: any + - + OSDF_CASABLANCA.hpa_policy_vG_1: + type: onap.policies.optimization.HpaPolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.hpa_policy_vG_1 + policy-version: 1 + properties: + resources: [vG] + identity: "hpa-vG" + policyScope: [vCPE, US, INTERNATIONAL, ip, vG] + policyType: hpa + # NONE OF THE FLAVORFEATURES CAME OUT RIGHT + - + OSDF_CASABLANCA.queryPolicy_vCPE: + type: onap.policies.optimization.QueryPolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.queryPolicy_vCPE + policy-version: 1 + properties: + queryProperties: + - + attribute: locationId + attribute_location: customerLocation + value: "" + - + attribute: id + attribute_location: "vpnInfo.vpnId" + value: "" + - + attribute: upstreamBW + attribute_location: "vpnInfo.upstreamBW" + value: "" + - + attribute: customerLatitude + attribute_location: customerLatitude + value: 1.1 + - + attribute: customerLongitude + attribute_location: customerLongitude + value: 2.2 + serviceName: vCPE + policyScope: [vCPE, US, INTERNATIONAL, ip, vGMuxInfra, vG] + policyType: request_param_query + identity: vCPE_Query_Policy + + - + OSDF_CASABLANCA.SubscriberPolicy_v1: + type: onap.policies.optimization.SubscriberPolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.SubscriberPolicy_v1 + policy-version: 1 + properties: + identity: subscriber_vCPE + policyScope: [vCPE, subscriber_x, subscriber_y, subscriberPolicy] + properties: + subscriberName: [subscriber_x, subscriber_y] + subscriberRole: ["PVT Homing"] + provStatus: [CAPPED] + policyType: subscriberPolicy + serviceName: vCPE + - + OSDF_CASABLANCA.vnfPolicy_vG: + type: onap.policies.optimization.VnfPolicy + version: 1.0.0 + metadata: + policy-id: OSDF_CASABLANCA.vnfPolicy_vG + policy-version: 1 + properties: + identity: vnf_vG + policyScope: [vCPE, US, INTERNATIONAL, ip, vG] + policyType: vnfPolicy + resources: [vG] + applicableResources: any + vnfProperties: + - + inventoryProvider: aai + serviceType: "" + inventoryType: cloud + customerId: "" + orchestrationStatus: "" + equipmentRole: "" \ No newline at end of file diff --git a/applications/optimization/src/test/resources/xacml.properties b/applications/optimization/src/test/resources/xacml.properties new file mode 100644 index 00000000..5ea247cf --- /dev/null +++ b/applications/optimization/src/test/resources/xacml.properties @@ -0,0 +1,31 @@ +# +# Properties that the embedded PDP engine uses to configure and load +# +# Standard API Factories +# +xacml.dataTypeFactory=com.att.research.xacml.std.StdDataTypeFactory +xacml.pdpEngineFactory=com.att.research.xacmlatt.pdp.ATTPDPEngineFactory +xacml.pepEngineFactory=com.att.research.xacml.std.pep.StdEngineFactory +xacml.pipFinderFactory=com.att.research.xacml.std.pip.StdPIPFinderFactory +xacml.traceEngineFactory=com.att.research.xacml.std.trace.LoggingTraceEngineFactory +# +# AT&T PDP Implementation Factories +# +xacml.att.evaluationContextFactory=com.att.research.xacmlatt.pdp.std.StdEvaluationContextFactory +xacml.att.combiningAlgorithmFactory=com.att.research.xacmlatt.pdp.std.StdCombiningAlgorithmFactory +xacml.att.functionDefinitionFactory=com.att.research.xacmlatt.pdp.std.StdFunctionDefinitionFactory +# +# ONAP PDP Implementation Factories +# +xacml.att.policyFinderFactory=org.onap.policy.pdp.xacml.application.common.OnapPolicyFinderFactory + +# +# Use a root combining algorithm +# +xacml.att.policyFinderFactory.combineRootPolicies=urn:com:att:xacml:3.0:policy-combining-algorithm:combined-permit-overrides + +# +# Policies to load +# +xacml.rootPolicies= +xacml.referencedPolicies= \ No newline at end of file diff --git a/applications/pom.xml b/applications/pom.xml index 8d5d4b28..0a1cac02 100644 --- a/applications/pom.xml +++ b/applications/pom.xml @@ -35,6 +35,7 @@ common monitoring guard + optimization diff --git a/main/pom.xml b/main/pom.xml index f4b0c9f4..872a5a0e 100644 --- a/main/pom.xml +++ b/main/pom.xml @@ -71,6 +71,11 @@ guard ${project.version} + + org.onap.policy.xacml-pdp.applications + optimization + ${project.version} + diff --git a/main/src/test/resources/decisions/decision.guard.shoulddeny.input.json b/main/src/test/resources/decisions/decision.guard.shoulddeny.input.json index ba9b5543..65d40c0a 100644 --- a/main/src/test/resources/decisions/decision.guard.shoulddeny.input.json +++ b/main/src/test/resources/decisions/decision.guard.shoulddeny.input.json @@ -1,14 +1,15 @@ { "ONAPName": "Policy", - "ONAPComponent": "DCAE", - "ONAPInstance": "optional-tbd", + "ONAPComponent": "drools-pdp", + "ONAPInstance": "usecase-template", + "requestId": "unique-request-id-2", "action": "guard", "resource": { "guard": { "actor": "SO", "recipe": "scaleOut", "clname": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3", - "vfcount" : "5" + "operationCount" : "1" } } } \ No newline at end of file diff --git a/main/src/test/resources/decisions/decision.guard.shoulddeny.input2.json b/main/src/test/resources/decisions/decision.guard.shoulddeny.input2.json new file mode 100644 index 00000000..29dfc3dc --- /dev/null +++ b/main/src/test/resources/decisions/decision.guard.shoulddeny.input2.json @@ -0,0 +1,15 @@ +{ + "ONAPName": "Policy", + "ONAPComponent": "drools-pdp", + "ONAPInstance": "usecase-template", + "requestId": "unique-request-id-2", + "action": "guard", + "resource": { + "guard": { + "actor": "SO", + "recipe": "scaleOut", + "clname": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3", + "vfCount" : "6" + } + } +} \ No newline at end of file diff --git a/main/src/test/resources/decisions/decision.guard.shoulddeny.output.json b/main/src/test/resources/decisions/decision.guard.shoulddeny.output.json deleted file mode 100644 index 3752fe47..00000000 --- a/main/src/test/resources/decisions/decision.guard.shoulddeny.output.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "deny" -} \ No newline at end of file diff --git a/main/src/test/resources/decisions/decision.guard.shouldpermit.input.json b/main/src/test/resources/decisions/decision.guard.shouldpermit.input.json index 324d495a..92e933f7 100644 --- a/main/src/test/resources/decisions/decision.guard.shouldpermit.input.json +++ b/main/src/test/resources/decisions/decision.guard.shouldpermit.input.json @@ -1,14 +1,16 @@ { "ONAPName": "Policy", - "ONAPComponent": "DCAE", - "ONAPInstance": "optional-tbd", + "ONAPComponent": "drools-pdp", + "ONAPInstance": "usecase-template", + "requestId": "unique-request-id-1", "action": "guard", "resource": { "guard": { "actor": "SO", "recipe": "scaleOut", "clname": "ControlLoop-vDNS-6f37f56d-a87d-4b85-b6a9-cc953cf779b3", - "vfcount" : "1" + "operationCount": "0", + "vfCount": "1" } } } \ No newline at end of file diff --git a/main/src/test/resources/decisions/decision.guard.shouldpermit.output.json b/main/src/test/resources/decisions/decision.guard.shouldpermit.output.json deleted file mode 100644 index a1939262..00000000 --- a/main/src/test/resources/decisions/decision.guard.shouldpermit.output.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "status": "permit" -} \ No newline at end of file diff --git a/main/src/test/resources/decisions/decision.optimization.affinity.input.json b/main/src/test/resources/decisions/decision.optimization.affinity.input.json new file mode 100644 index 00000000..1794acea --- /dev/null +++ b/main/src/test/resources/decisions/decision.optimization.affinity.input.json @@ -0,0 +1,10 @@ +{ + "ONAPName": "OOF", + "ONAPComponent": "OOF-component", + "ONAPInstance": "OOF-component-instance", + "action": "optimize", + "resource": { + "policyScope": ["vCPE", "US", "INTERNATIONAL", "ip", "vGMuxInfra", "vG"], + "policyType": "zone" + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 77838654..1559f963 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,10 @@ snakeyaml 1.24 + + org.projectlombok + lombok + org.json json @@ -106,7 +110,7 @@ org.onap.policy.models - models-decisions + policy-models-decisions ${policy.models.version} -- 2.16.6