diff options
Diffstat (limited to 'controlloop/m2/test')
10 files changed, 0 insertions, 2099 deletions
diff --git a/controlloop/m2/test/pom.xml b/controlloop/m2/test/pom.xml deleted file mode 100644 index ee610711b..000000000 --- a/controlloop/m2/test/pom.xml +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0"?> -<!-- - ============LICENSE_START======================================================= - ONAP Policy Engine - Drools PDP - ================================================================================ - Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - ================================================================================ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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========================================================= - --> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onap.policy.drools-applications.controlloop.m2</groupId> - <artifactId>m2</artifactId> - <version>1.7.1-SNAPSHOT</version> - </parent> - - <artifactId>test</artifactId> - - <build> - <plugins> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-surefire-plugin</artifactId> - <executions> - <execution> - <id>default-test</id> - <configuration> - <systemPropertyVariables> - <project.version>${project.version}</project.version> - </systemPropertyVariables> - </configuration> - <goals> - <goal>test</goal> - </goals> - </execution> - </executions> - <configuration> - <skip>false</skip> - </configuration> - </plugin> - </plugins> - </build> - - <dependencies> - <dependency> - <groupId>org.onap.policy.drools-pdp</groupId> - <artifactId>policy-core</artifactId> - <version>${version.policy.drools-pdp}</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.onap.policy.drools-pdp</groupId> - <artifactId>policy-management</artifactId> - <version>${version.policy.drools-pdp}</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.onap.policy.drools-pdp</groupId> - <artifactId>feature-drools-init</artifactId> - <version>${version.policy.drools-pdp}</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.onap.policy.models.policy-models-interactions</groupId> - <artifactId>model-yaml</artifactId> - <version>${policy.models.version}</version> - <scope>test</scope> - </dependency> - - <dependency> - <groupId>org.onap.policy.drools-applications.controlloop.m2</groupId> - <artifactId>appclcm</artifactId> - <version>${project.version}</version> - <scope>test</scope> - </dependency> - - </dependencies> -</project> diff --git a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/AppcLcmTest.java b/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/AppcLcmTest.java deleted file mode 100644 index 31003cba3..000000000 --- a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/AppcLcmTest.java +++ /dev/null @@ -1,333 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * m2/test - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Bell Canada. - * ================================================================================ - * 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.m2.test; - -import static org.awaitility.Awaitility.await; -import static org.junit.Assert.assertNotNull; -import static org.onap.policy.guard.Util.ONAP_KEY_PASS; -import static org.onap.policy.guard.Util.ONAP_KEY_URL; -import static org.onap.policy.guard.Util.ONAP_KEY_USER; -import static org.onap.policy.guard.Util.PROP_GUARD_URL; -import static org.onap.policy.m2.test.Util.assertSubset; -import static org.onap.policy.m2.test.Util.json; - -import com.google.gson.JsonObject; -import java.io.File; -import java.time.Duration; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicReference; -import org.awaitility.Durations; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.Test; -import org.onap.policy.drools.system.PolicyController; -import org.onap.policy.drools.system.PolicyEngineConstants; -import org.onap.policy.drools.util.KieUtils; -import org.onap.policy.drools.utils.PropertyUtil; -import org.onap.policy.m2.test.Util.Input; -import org.onap.policy.m2.test.Util.Output; - -public class AppcLcmTest { - private static String closedLoopControlName = null; - private static Output dcae = null; - private static Output appcResponse = null; - private static Input notification = null; - private static Input appcRequest = null; - private static Properties properties = null; - private static PolicyController policyController = null; - - /** - * Initialization method, which creates the following: - * 1) VUSPLCM artifact - * 2) The associated PolicyController and Drools session - * 3) DMAAP/UEB topic writers and readers - * . - */ - @BeforeClass - public static void init() throws Exception { - Util.commonInit(); - - String projectVersion = System.getProperty("project.version"); - assertNotNull(projectVersion); - closedLoopControlName = "appclcm-" + UUID.randomUUID().toString(); - - File kmodule = new File("src/test/resources/appclcm/kmodule.xml"); - - String pom = Util.openAndReplace("src/test/resources/appclcm/pom.xml", - "${project.version}", projectVersion); - - String yaml = Util.fileToString(new File("src/test/resources/appclcm/CLRulevUSPAPPCLCMGuardTemplate.yaml")); - - // build a '.drl' file (as a String), by replacing '${variable}' names - String drl = Util.openAndReplace( - "src/test/resources/appclcm/M2CLRulevUSPAPPCLCMGuardTemplate.drl", - "${closedLoopControlName}", closedLoopControlName, - "${controlLoopYaml}", Util.convertYaml(yaml), - "${notificationTopic}", "NOTIFICATION-APPCLCM-TOPIC", - "${operationTopic}", "APPC-REQUEST-APPCLCM-TOPIC", - "${policyName}", "appclcm", - "${policyScope}", "service=vUSP;resource=vCTS;type=operational", - "${policyVersion}", - "org.onap.policy.m2.test:appclcm:" + projectVersion, - "${unique}", "2"); - - // this creates the JAR file, and installs it in the local repository - KieUtils.installArtifact(kmodule, Util.stringToFile(pom, ".xml"), - "src/main/resources/rules/rules.drl", Util.stringToFile(drl, ".drl")); - - properties = PropertyUtil.getProperties("src/test/resources/appclcm/controller.properties"); - properties.setProperty("rules.version", projectVersion); - //properties.setProperty("pdpx.username", ""); - //properties.setProperty("pdpx.password", ""); - - // create PolicyController, which creates the Drools session - PolicyEngineConstants.getManager().setEnvironmentProperty(PROP_GUARD_URL, "http://127.0.0.1:8443/pdp/"); - PolicyEngineConstants.getManager().setEnvironmentProperty(ONAP_KEY_URL, "jdbc:h2:file:./H2DB"); - PolicyEngineConstants.getManager().setEnvironmentProperty(ONAP_KEY_USER, "sa"); - PolicyEngineConstants.getManager().setEnvironmentProperty(ONAP_KEY_PASS, ""); - policyController = - PolicyEngineConstants.getManager().createPolicyController("appclcm", properties); - policyController.start(); - - // create writers - dcae = new Output("org.onap.DCAE-APPCLCM-TOPIC"); - appcResponse = new Output("APPC-RESPONSE-APPCLCM-TOPIC"); - - // create readers - notification = new Input("NOTIFICATION-APPCLCM-TOPIC"); - appcRequest = new Input("APPC-REQUEST-APPCLCM-TOPIC"); - } - - /** - * Clean up. - */ - @AfterClass - public static void cleanup() { - // close readers - notification.close(); - appcRequest.close(); - - // close writers - dcae.close(); - appcResponse.close(); - - // shut down PolicyController and Drools session - policyController.stop(); - PolicyEngineConstants.getManager().stop(); - - // clean up REST servers - Util.commonShutdown(); - } - - /** - * This is a sunny-day scenario. - */ - @Test - public void sunnyDayTest() throws Exception { - Request req = new Request(); - - // send initial ONSET message - dcae.send(req.msg); - - // receive active notification, and restart operation - awaitAndAssert(10, Durations.TWO_HUNDRED_MILLISECONDS, notification, - json("notification", "ACTIVE")); - - appcOperation(req, "Restart", 400, "Restart Successful"); - - // send ABATED - req.msg.addProperty("closedLoopEventStatus", "ABATED"); - dcae.send(req.msg); - - // receive final success notification - awaitAndAssert(10, Durations.TWO_HUNDRED_MILLISECONDS, notification, - json("notification", "FINAL: SUCCESS")); - - // sleep to allow DB update - Thread.sleep(1000); - } - - /** - * In this scenario, all requests fail until the final 'Evacuate'. - */ - @Test - public void initialFailure() throws Exception { - Request req = new Request(); - - // send initial ONSET message - dcae.send(req.msg); - - // active notification, and restart 1 operation - awaitAndAssert(10, Durations.TWO_HUNDRED_MILLISECONDS, notification, - json("notification", "ACTIVE")); - - appcOperation(req, "Restart", 450, "Restart 1 Failed"); - appcOperation(req, "Restart", 450, "Restart 2 Failed"); - appcOperation(req, "Rebuild", 450, "Rebuild Failed"); - appcOperation(req, "Migrate", 450, "Migrate Failed"); - appcOperation(req, "Evacuate", 400, "Evacuate Successful"); - - // send ABATED - req.msg.addProperty("closedLoopEventStatus", "ABATED"); - dcae.send(req.msg); - - // receive final success notification - awaitAndAssert(10, Durations.TWO_HUNDRED_MILLISECONDS, notification, - json("notification", "FINAL: SUCCESS")); - - // sleep to allow DB update - Thread.sleep(1000); - } - - private void awaitAndAssert(int maxWaitSecond, Duration pollIntervalMilli, Input notification, - JsonObject jsonObj) { - AtomicReference<JsonObject> obj = new AtomicReference<>(); - await().atMost(maxWaitSecond, TimeUnit.SECONDS) - .with().pollInterval(pollIntervalMilli) - .until(() -> { - obj.set(notification.poll()); - return obj.get() != null; - }); - assertSubset(jsonObj, obj.get()); - } - - private void appcOperation(Request req, String name, int responseCode, String responseMessage) - throws Exception { - String lcName = name.toLowerCase(); - assertSubset(json("notification", "OPERATION", - "message", ".*operation=" + name + ",.*"), - notification.poll()); - - // receive request - JsonObject opRequest = appcRequest.poll(); - assertSubset(json("version", "2.0", - "rpc-name", lcName, - "correlation-id", ".*", - "type", "request", - "body", - json("input", json("common-header", - json("request-id", req.requestId), - "action", name - ))), - opRequest); - - // send response - JsonObject ch = opRequest - .getAsJsonObject("body") - .getAsJsonObject("input") - .getAsJsonObject("common-header"); - JsonObject opResponse = - json("correlation-id", opRequest.get("correlation-id"), - "body", json("output", - json("common-header", - json("flags", json(), - "api-ver", "2.00", - "originator-id", ch.get("originator-id"), - "sub-request-id", ch.get("sub-request-id"), - "request-id", req.requestId, - "timestamp", ch.get("timestamp") - ), - "status", - json("code", responseCode, - "message", responseMessage - ))), - "type", "response", - "version", "2.0", - "rpc-name", lcName - ); - appcResponse.send(opResponse); - - // receive success or failure notification - String expectedNotification = - (responseCode == 400 ? "OPERATION: SUCCESS" : "OPERATION: FAILURE"); - assertSubset(json("notification", expectedNotification, - "message", ".*operation=" + name + ",.*"), - notification.poll()); - } - - /* ============================================================ */ - - /** - * An instance of this class is created for each Transaction. It allocates - * any identifiers, such as 'requestId', and creates the initial ONSET - * message. - */ - class Request { - String requestId; - String triggerId; - JsonObject msg; - - Request() { - long time = System.currentTimeMillis(); - requestId = UUID.randomUUID().toString(); - triggerId = "trigger-" + time; - - msg = json("closedLoopEventClient", "configuration.dcae.microservice.stringmatcher.xml", - "policyVersion", "1610", - "triggerSourceName", "ctsf0002vm014", - "policyName", "vUSP_vCTS_CL_7.Config_MS_ClosedLoop_" - + "104b1445_6b30_11e7_852e_0050568c4ccf_StringMatch_1wo2qh0", - "policyScope", "resource=F5,service=vSCP,type=configuration," - + "closedLoopControlName=vSCP_F5_Firewall_d925ed73-8231-4d02-9545-db4e101f88f8", - "triggerID", triggerId, - "target_type", "VM", - "AAI", - json("vserver.l-interface.l3-interface-ipv6-address-list.l3-inteface-ipv6-address", null, - "vserver.selflink", "https://compute-aic.dpa3.cci.att.com:8774/v2/d0719b845a804b368f8ac0bba39e188b/servers/7953d05b-6698-4aa6-87bd-39bed606133a", - "vserver.is-closed-loop-disabled", "false", - "vserver.l-interface.network-name", "vUSP_DPA3_OAM_3750", - "vserver.l-interface.l3-interface-ipv4-address-list.l3-inteface-ipv4-address", //continues - "135.144.3.50", - "vserver.vserver-id", "78fe4342-8f85-49ba-be9f-d0c1bdf1ba7b", - "generic-vnf.service-id", "e433710f-9217-458d-a79d-1c7aff376d89", - "complex.city", "AAIDefault", - "vserver.in-maint", "N", - "complex.state", "NJ", - "vserver.vserver-name", "ctsf0002vm025", - "complex.physical-location-id", "LSLEILAA", - "tenant.tenant-id", "d0719b845a804b368f8ac0bba39e188b", - "vserver.prov-status", "PROV", - "generic-vnf.vnf-name", "ctsf0002v", - "vserver.l-interface.interface-name", // continues - "ctsf0002v-ALU-LCP-Pair07-oziwyxlxwdyc-1-a4psuz5awjw7-ALU-LCP-ETH2-ygmny7m7rpb5", - "generic-vnf.vnf-type", "vUSP-vCTS", - "cloud-region.identity-url", "https://auth.pdk11.cci.att.com:5000/v2.0" - ), - "closedLoopAlarmStart", "1507143409107000", - "closedLoopEventStatus", "ONSET", - "closedLoopControlName", closedLoopControlName, - "version", "1.0.2", - "target", "vserver.vserver-name", - "resourceInstance", json("resourceName", "", - "resourceInstanceName", "" - ), - "requestID", requestId, - "from", "DCAE", - "serviceInstance", json("serviceInstanceName", "", - "serviceName", "" - ) - ); - } - } -} diff --git a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimDmaap.java b/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimDmaap.java deleted file mode 100644 index 1c11fccdb..000000000 --- a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimDmaap.java +++ /dev/null @@ -1,264 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * m2/test - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.m2.test; - -import java.util.Map; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.MediaType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This class simulates a UEB/DMAAP server. - */ - -@Path("/") -public class SimDmaap { - private static Logger logger = LoggerFactory.getLogger(SimDmaap.class); - - // maps topic name to 'Topic' instance - static Map<String, Topic> topicTable = new ConcurrentHashMap<>(); - - /** - * Each instance of this class corresponds to a DMAAP or UEB topic. - */ - static class Topic { - // topic name - String topic; - - // maps group name into group instance - Map<String, Group> groupTable = new ConcurrentHashMap<>(); - - /** - * Create or get a Topic. - * - * @param name the topic name - * @return the associated Topic instance - */ - static Topic createOrGet(String name) { - // look up the topic name - Topic topicObj = topicTable.get(name); - if (topicObj == null) { - // no entry found -- the following will create one, without - // the need for explicit synchronization - topicTable.putIfAbsent(name, new Topic(name)); - topicObj = topicTable.get(name); - } - return topicObj; - } - - /** - * Constructor - initialize the 'topic' field. - * - * @param topic the topic name - */ - private Topic(String topic) { - this.topic = topic; - } - - /** - * Handle an incoming '/events/{topic}' POST REST message. - * - * @param the body of the REST message - * @return the appropriate JSON response - */ - String post(String data) { - // start of message processing - long startTime = System.currentTimeMillis(); - - // current and ending indices to the 'data' field - int cur = 0; - int end = data.length(); - - // the number of messages retrieved so far - int messageCount = 0; - - while (cur < end) { - // The body of the message may consist of multiple JSON messages, - // each preceded by 3 integers separated by '.'. The second one - // is the length, in bytes (the third seems to be some kind of - // channel identifier). - - int leftBrace = data.indexOf('{', cur); - if (leftBrace < 0) { - // no more messages - break; - } - String[] prefix = data.substring(cur, leftBrace).split("\\."); - if (prefix.length == 3) { - try { - // determine length of message, and advance current position - int length = Integer.parseInt(prefix[1]); - cur = leftBrace + length; - - // extract message, and update count -- each '\' is converted - // to '\\', and each double quote has a '\' character placed - // before it, so the overall message can be placed in double - // quotes, and parsed as a literal string - String message = data.substring(leftBrace, cur) - .replace("\\", "\\\\").replace("\"", "\\\"") - .replace("\n", "\\n"); - messageCount += 1; - - // send to all listening groups - for (Group group : groupTable.values()) { - group.messages.add(message); - } - } catch (Exception e) { - logger.info("{}: {}", prefix[1], e); - break; - } - } else if (cur == 0) { - // there is only a single message -- extract it, and update count - String message = data.substring(leftBrace, end) - .replace("\\", "\\\\").replace("\"", "\\\"") - .replace("\n", "\\n"); - messageCount += 1; - - // send to all listening grops - for (Group group : groupTable.values()) { - group.messages.add(message); - } - break; - } else { - // don't know what this is -- toss it - break; - } - } - - // generate response message - long elapsedTime = System.currentTimeMillis() - startTime; - return "{\n" - + " \"count\": " + messageCount + ",\n" - + " \"serverTimeMs\": " + elapsedTime + "\n" - + "}"; - } - - /** - * read one or more incoming messages. - * - * @param group the 'consumerGroup' value - * @param timeout how long to wait for a message, in milliseconds - * @param limit the maximum number of messages to receive - * @return a JSON array, containing 0-limit messages - */ - String get(String group, long timeout, int limit) - throws InterruptedException { - // look up the group -- create one if it doesn't exist - Group groupObj = groupTable.get(group); - if (groupObj == null) { - // no entry found -- the following will create one, without - // the need for explicit synchronization - groupTable.putIfAbsent(group, new Group()); - groupObj = groupTable.get(group); - } - - // pass it on to the 'Group' instance - return groupObj.get(timeout, limit); - } - } - - /* ============================================================ */ - - /** - * Each instance of this class corresponds to a Consumer Group. - */ - static class Group { - // messages queued for this group - private BlockingQueue<String> messages = new LinkedBlockingQueue<>(); - - /** - * Retrieve messages sent to this group. - * - * @param timeout how long to wait for a message, in milliseconds - * @param limit the maximum number of messages to receive - * @return a JSON array, containing 0-limit messages - */ - String get(long timeout, int limit) throws InterruptedException { - String message = messages.poll(timeout, TimeUnit.MILLISECONDS); - if (message == null) { - // timed out without messages - return "[]"; - } - - // use 'StringBuilder' to assemble the response -- add the first message - StringBuilder builder = new StringBuilder(); - builder.append("[\"").append(message); - - // add up to '<limit>-1' more messages - for (int i = 1; i < limit; i += 1) { - // fetch the next message -- don't wait if it isn't currently there - message = messages.poll(); - if (message == null) { - // no more currently available - break; - } - builder.append("\",\"").append(message); - } - builder.append("\"]"); - return builder.toString(); - } - } - - /* ============================================================ */ - - /** - * Process an HTTP POST to /events/{topic}. - */ - @POST - @Path("/events/{topic}") - @Consumes("application/cambria") - @Produces(MediaType.APPLICATION_JSON) - public String send(@PathParam("topic") String topic, - String data) { - logger.info("Send: topic={}", topic); - return Topic.createOrGet(topic).post(data); - } - - /** - * Process an HTTP GET to /events/{topic}/{group}/{id}. - */ - @GET - @Path("/events/{topic}/{group}/{id}") - @Consumes(MediaType.TEXT_PLAIN) - @Produces(MediaType.APPLICATION_JSON) - public String receive(@PathParam("topic") String topic, - @PathParam("group") String group, - @PathParam("id") String id, - @QueryParam("timeout") long timeout, - @QueryParam("limit") int limit) - throws InterruptedException { - - logger.info("Receive: topic={}, group={}, id={}, timeout={}, limit={}", - topic, group, id, timeout, limit); - return Topic.createOrGet(topic).get(group, timeout, limit); - } -} diff --git a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimGuard.java b/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimGuard.java deleted file mode 100644 index 67df8503a..000000000 --- a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/SimGuard.java +++ /dev/null @@ -1,62 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * m2/test - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.m2.test; - -import com.google.gson.JsonObject; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import org.onap.policy.common.utils.coder.CoderException; -import org.onap.policy.common.utils.coder.StandardCoder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * minimal Guard Simulator -- just enough to support the current tests. - */ -@Path("/") -public class SimGuard { - private static Logger logger = LoggerFactory.getLogger(SimGuard.class); - - // used for JSON <-> String conversion - private static StandardCoder coder = new StandardCoder(); - - /** - * Process an HTTP POST to /pdp/. - */ - @POST - @Path("/pdp/") - @Consumes(MediaType.APPLICATION_JSON) - @Produces(MediaType.APPLICATION_JSON) - public String query(String data) throws CoderException { - - JsonObject msg = coder.decode(data, JsonObject.class); - logger.info("SimGuard query:\n{}", Util.prettyPrint(msg)); - - JsonObject response = new JsonObject(); - response.addProperty("status", "Permit"); - logger.info("Returning:\n{}", Util.prettyPrint(response)); - - return response.toString(); - } -} diff --git a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/Util.java b/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/Util.java deleted file mode 100644 index f6740f83b..000000000 --- a/controlloop/m2/test/src/test/java/org/onap/policy/m2/test/Util.java +++ /dev/null @@ -1,500 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * m2/test - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * Modifications Copyright (C) 2020 Bell Canada. - * ================================================================================ - * 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.m2.test; - -import static org.junit.Assert.assertTrue; - -import com.att.nsa.cambria.client.CambriaBatchingPublisher; -import com.att.nsa.cambria.client.CambriaClientBuilders; -import com.att.nsa.cambria.client.CambriaClientBuilders.ConsumerBuilder; -import com.att.nsa.cambria.client.CambriaClientBuilders.PublisherBuilder; -import com.att.nsa.cambria.client.CambriaConsumer; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; -import com.google.gson.JsonPrimitive; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.LinkedList; -import java.util.List; -import java.util.Properties; -import java.util.UUID; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.TimeUnit; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.server.ServerConnector; -import org.eclipse.jetty.servlet.ServletContextHandler; -import org.eclipse.jetty.servlet.ServletHolder; -import org.onap.policy.common.utils.coder.StandardCoder; -import org.onap.policy.drools.system.PolicyEngineConstants; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Util { - private static Logger logger = LoggerFactory.getLogger(Util.class); - - // used for JSON <-> String conversion - private static StandardCoder coder = new StandardCoder(); - - // used for pretty-printing: gson.toJson(JsonObject obj) - private static Gson gson = - new GsonBuilder().setPrettyPrinting().serializeNulls().create(); - - // contains the currently running set of servers - private static List<Server> runningServers = new LinkedList<>(); - - /** - * Read from an 'InputStream' until EOF or until it is closed. This method - * may block, depending on the type of 'InputStream'. - * - * @param input This is the input stream - * @return A 'String' containing the contents of the input stream - */ - public static String inputStreamToString(InputStream input) { - StringBuilder sb = new StringBuilder(); - byte[] buffer = new byte[8192]; - int length; - - try { - while ((length = input.read(buffer)) > 0) { - sb.append(new String(buffer, 0, length)); - } - } catch (IOException e) { - // return what we have so far - } - return sb.toString(); - } - - /** - * Read in a file, converting the contents to a string. - * - * @param file the input file - * @return a String containing the contents of the file - */ - public static String fileToString(File file) - throws IOException, FileNotFoundException { - try (FileInputStream fis = new FileInputStream(file)) { - String string = inputStreamToString(fis); - return string; - } - } - - /** - * Create a file containing the contents of the specified string. - * - * @param string the input string - * @param suffix the suffix to pass to 'createTempFile - * @return a File, whose contents contain the string - */ - public static File stringToFile(String string, String suffix) - throws IOException { - File file = File.createTempFile("templates-util", suffix); - file.deleteOnExit(); - - try (FileOutputStream fos = new FileOutputStream(file)) { - fos.write(string.getBytes()); - } - return file; - } - - /** - * Create a file containing the contents of the specified string. - * - * @param string the input string - * @return a File, whose contents contain the string - */ - public static File stringToFile(String string) - throws IOException { - return stringToFile(string, ""); - } - - /** - * This method converts a YAML string into one that can be embedded into - * a '.drl' file. - * - * @param yaml the input string, which is typically read from a file - * @return the converted string - */ - public static String convertYaml(String yaml) { - yaml = yaml.replace("\n", "%0A"); - yaml = yaml.replace("\r", ""); - yaml = yaml.replace(":", "%3A"); - yaml = yaml.replace(' ', '+'); - return yaml; - } - - /** - * This is a convenience method which reads a file into a string, and - * then does a set of string replacements on it. The real purpose is to - * make it easy to do '${parameter}' replacements in files, as part of - * building a Drools artifact. - * - * @param fileName this is the input file name - * @param args these parameters come in pairs: - * 'input-string' and 'output-string'. - * @return a String containing the contents of the file, with the parameters - * replaced - */ - public static String openAndReplace(String fileName, String... args) - throws IOException, FileNotFoundException { - String text = fileToString(new File(fileName)); - for (int i = 0; i < args.length; i += 2) { - text = text.replace(args[i], args[i + 1]); - } - return text; - } - - /** - * Convert an Object to a JsonElement. - * - * @param object the object to convert - * @return a JsonElement that corresponds to 'object' - */ - public static JsonElement toJsonElement(Object object) { - if (object == null || object instanceof JsonElement) { - return (JsonElement) object; - } - if (object instanceof Number) { - return new JsonPrimitive((Number) object); - } - if (object instanceof Boolean) { - return new JsonPrimitive((Boolean) object); - } - if (object instanceof Character) { - return new JsonPrimitive((Character) object); - } - return new JsonPrimitive(object.toString()); - } - - /** - * This is a convenience method to build a 'JsonObject', and populate - * it with a set of keyword/value pairs. - * - * @param data this parameter comes in pairs: 'keyword', and 'value' - * @return the populated JsonObject - */ - public static JsonObject json(Object... data) { - JsonObject obj = new JsonObject(); - for (int i = 0; i < data.length; i += 2) { - obj.add(data[i].toString(), toJsonElement(data[i + 1])); - } - return obj; - } - - /** - * Convert a JsonElement to a String (pretty-printing). - * - * @param jsonElement the object to convert - * @return a pretty-printed string - */ - public static String prettyPrint(JsonElement jsonElement) { - return gson.toJson(jsonElement); - } - - /** - * This method is used to check whether a JSON message has a set of fields - * populated with the values expected. - * - * @param subset this is a 'JsonObject', which contains field names and - * values (the values are interpreted as regular expressions). The values - * may also be 'JsonObject' instances, in which case they are compared - * recursively. - * @param whole ordinarily, this will be a 'JsonObject', and will contain - * a superset of the fields in 'subset'. If not, the 'assert' fails. - */ - public static void assertSubset(JsonObject subset, Object whole) { - StringBuilder sb = new StringBuilder(); - assertSubsetAssist(sb, "", subset, toJsonElement(whole)); - String sbString = sb.toString(); - assertTrue(sbString, sbString.isEmpty()); - } - - /** - * This is similar to 'assertSubset', but just returns 'true' if the - * pattern matches. - * - * @param subset this is a 'JsonObject', which contains field names and - * values (the values are interpreted as regular expressions). The values - * may also be 'JsonObject' instances, in which case they are compared - * recursively. - * @param whole ordinarily, this will be a 'JsonObject', and will contain - * a superset of the fields in 'subset'. If not, the 'assert' fails. - * @return 'true' if 'whole' is a superset of 'subset' - */ - public static boolean testSubset(JsonObject subset, Object whole) { - StringBuilder sb = new StringBuilder(); - assertSubsetAssist(sb, "", subset, toJsonElement(whole)); - return sb.length() == 0; - } - - /** - * This is an internal support method for 'assertSubset' and 'testSubset', - * and handles the recursive comparison. - * - * @param sb a 'StringBuilder', which is appended to when there are - * mismatches - * @param prefix the field name being compared (the empty string indicates - * the top-level field). - * @param subset the 'JsonObject' being compared at this level - * @param argWhole the value being tested -- if it is not a 'JsonObject', - * the comparison fails - */ - private static void assertSubsetAssist(StringBuilder sb, String prefix, JsonObject subset, JsonElement argWhole) { - if (!(argWhole.isJsonObject())) { - sb.append(prefix).append(" is not a JsonObject\n"); - return; - } - JsonObject whole = argWhole.getAsJsonObject(); - for (String key : subset.keySet()) { - String fullKey = (prefix.isEmpty() ? key : prefix + "." + key); - JsonElement value = subset.get(key); - JsonElement value2 = whole.get(key); - if (value.isJsonObject()) { - assertSubsetAssist(sb, fullKey, value.getAsJsonObject(), value2); - } else if (!value.equals(value2) - && (value2 == null || !value2.toString().matches(value.toString()))) { - sb.append(fullKey) - .append(": got ") - .append(String.valueOf(value2)) - .append(", expected ") - .append(String.valueOf(value)) - .append("\n"); - } - } - } - - /** - * Do whatever needs to be done to start the server. I don't know exactly - * what abstractions the various pieces provide, but the following code - * ties the pieces together, and starts up the server. - * - * @param name used as the 'ServerConnector' name, and also used to generate - * a name for the server thread - * @param host the host IP address to bind to - * @param port the port to bind to - * @param clazz the class containing the provider methods - */ - public static void startRestServer(String name, String host, int port, Class<?> clazz) { - ServletContextHandler context = - new ServletContextHandler(ServletContextHandler.SESSIONS); - context.setContextPath("/"); - - final Server jettyServer = new Server(); - - ServerConnector connector = new ServerConnector(jettyServer); - connector.setName(name); - connector.setReuseAddress(true); - connector.setPort(port); - connector.setHost(host); - - jettyServer.addConnector(connector); - jettyServer.setHandler(context); - - ServletHolder holder = - context.addServlet(org.glassfish.jersey.servlet.ServletContainer.class.getName(), "/*"); - holder.setInitParameter( - "jersey.config.server.provider.classnames", - "org.onap.policy.common.gson.GsonMessageBodyHandler" - + "," + clazz.getName()); - - synchronized (runningServers) { - runningServers.add(jettyServer); - } - - new Thread(() -> { - try { - jettyServer.start(); - jettyServer.join(); - logger.info("{}: back from jettyServer.join()", name); - } catch (Exception e) { - logger.info(name + ": Exception starting jettyServer", e); - } - }, "REST Server: " + name).start(); - } - - private static boolean initNeeded = true; - - /** - * This method starts services shared by all of the tests. The services are - * started the first time it is invoked -- subsequent invocations have no - * effect. - */ - public static void commonInit() { - if (initNeeded) { - initNeeded = false; - - // start DMAAP Simulator - startRestServer("simdmaap", "127.0.0.1", 3904, SimDmaap.class); - - // start Guard Simulator - startRestServer("simguard", "127.0.0.1", 8443, SimGuard.class); - - // start PolicyEngine - PolicyEngineConstants.getManager().configure(new Properties()); - PolicyEngineConstants.getManager().start(); - } - } - - /** - * This method shuts down all of the servers that were started. - */ - public static void commonShutdown() { - synchronized (runningServers) { - for (Server server : runningServers) { - try { - server.stop(); - } catch (Exception e) { - logger.info("Exception shutting down server: {}", e); - } - } - runningServers.clear(); - initNeeded = true; - } - } - - /* ============================================================ */ - - /** - * This class is used to create an outgoing (publisher) topic message - * channel. 'topic' is the only parameter -- everything else is hard-wired. - */ - public static class Output { - CambriaBatchingPublisher publisher; - String topic; - - /** - * Constructor - create the outgoing topic message channel. - * - * @param topic a DMAAP or UEB topic name - */ - public Output(String topic) throws Exception { - this.topic = topic; - PublisherBuilder builder = - new CambriaClientBuilders.PublisherBuilder(); - builder - .usingHosts("127.0.0.1") - .onTopic(topic) - .withSocketTimeout(5000); - publisher = builder.build(); - } - - /** - * Send a JSON message out this channel. - * - * @param msg a 'JsonObject' containing the message to be sent - */ - public void send(JsonObject msg) throws Exception { - logger.info("Sending message, topic = {}\n{}", - topic, gson.toJson(msg)); - publisher.send("123", msg.toString()); - } - - /** - * Close the channel. - */ - public void close() { - publisher.close(); - } - } - - /* ============================================================ */ - - /** - * This class is used to create an incoming (consumer) topic message channel, - * as well as a Thread that reads from it. Incoming messages are placed in - * a 'LinkedBlockingQueue', which may be polled for messages. - */ - public static class Input extends Thread { - CambriaConsumer consumer; - String topic; - LinkedBlockingQueue<JsonObject> queue = new LinkedBlockingQueue<>(); - volatile boolean running = true; - - /** - * Constructor - create the incoming topic message channel. - * - * @param topic a DMAAP or UEB topic name - */ - public Input(String topic) throws Exception { - this.topic = topic; - - // initialize reader - ConsumerBuilder builder = new CambriaClientBuilders.ConsumerBuilder(); - builder - .knownAs(UUID.randomUUID().toString(), "1") - .usingHosts("127.0.0.1") - .onTopic(topic) - .waitAtServer(15000) - .receivingAtMost(100) - .withSocketTimeout(20000); - consumer = builder.build(); - start(); - } - - /** - * This is the Thread main loop. It fetches messages, and queues them. - */ - @Override - public void run() { - while (running) { - try { - for (String message : consumer.fetch()) { - // a message was received -- parse it as JSON - JsonObject msg = coder.decode(message, JsonObject.class); - - // construct a message to print, and print it - logger.info("Received message, topic = {}\n{}", - topic, gson.toJson(msg)); - - // queue the message - queue.add(msg); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - /** - * Return the first message in the queue. If none are available, wait up - * to 30 seconds for one to appear. - * - * @return a 'JsonObject' if a message has been received, and 'null' if not - */ - public JsonObject poll() throws InterruptedException { - return queue.poll(30, TimeUnit.SECONDS); - } - - /** - * Stop the thread, and close the channel. - */ - public void close() { - running = false; - consumer.close(); - } - } -} diff --git a/controlloop/m2/test/src/test/resources/appclcm/CLRulevUSPAPPCLCMGuardTemplate.yaml b/controlloop/m2/test/src/test/resources/appclcm/CLRulevUSPAPPCLCMGuardTemplate.yaml deleted file mode 100644 index ee25b03bb..000000000 --- a/controlloop/m2/test/src/test/resources/appclcm/CLRulevUSPAPPCLCMGuardTemplate.yaml +++ /dev/null @@ -1,83 +0,0 @@ -controlLoop: - version: 2.0.0 - controlLoopName: ControlLoop-vUSP-vCTS-cbed919f-2212-4ef7-8051-fe6308da1bda - services: - - serviceName: vUSP - resources: - - resourceName: vCTS - resourceType: VF - - resourceName: vCOM - resourceType: VF - - resourceName: vRAR - resourceType: VF - - resourceName: vLCS - resourceType: VF - - resourceName: v3CB - resourceType: VF - trigger_policy: unique-policy-id-1-restart - timeout: 60 - -policies: - - id: unique-policy-id-1-restart - name: Restart Policy - description: - actor: APPCLCM - recipe: Restart - target: - type: VM - retry: 1 - timeout: 35 - success: final_success - failure: unique-policy-id-2-rebuild - failure_timeout: unique-policy-id-2-rebuild - failure_retries: unique-policy-id-2-rebuild - failure_guard: unique-policy-id-2-rebuild - failure_exception: final_failure_exception - - - id: unique-policy-id-2-rebuild - name: Rebuild Policy - description: - actor: APPCLCM - recipe: Rebuild - target: - type: VM - retry: 0 - timeout: 35 - success: final_success - failure: unique-policy-id-3-migrate - failure_timeout: unique-policy-id-3-migrate - failure_retries: unique-policy-id-3-migrate - failure_guard: unique-policy-id-3-migrate - failure_exception: final_failure_exception - - - id: unique-policy-id-3-migrate - name: Migrate Policy - description: - actor: APPCLCM - recipe: Migrate - target: - type: VM - retry: 0 - timeout: 35 - success: final_success - failure: unique-policy-id-4-evacuate - failure_timeout: unique-policy-id-4-evacuate - failure_retries: unique-policy-id-4-evacuate - failure_guard: unique-policy-id-4-evacuate - failure_exception: final_failure_exception - - - id: unique-policy-id-4-evacuate - name: Evacuate Policy - description: - actor: APPCLCM - recipe: Evacuate - target: - type: VM - retry: 0 - timeout: 35 - success: final_success - failure: final_failure - failure_timeout: final_failure_timeout - failure_retries: final_failure_retries - failure_guard: final_failure_guard - failure_exception: final_failure_exception diff --git a/controlloop/m2/test/src/test/resources/appclcm/M2CLRulevUSPAPPCLCMGuardTemplate.drl b/controlloop/m2/test/src/test/resources/appclcm/M2CLRulevUSPAPPCLCMGuardTemplate.drl deleted file mode 100644 index 0e947c8e1..000000000 --- a/controlloop/m2/test/src/test/resources/appclcm/M2CLRulevUSPAPPCLCMGuardTemplate.drl +++ /dev/null @@ -1,649 +0,0 @@ -/*- - * ============LICENSE_START======================================================= - * m2/test - * ================================================================================ - * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - * ================================================================================ - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * 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.controlloop.p_${unique}; - -import org.drools.core.spi.KnowledgeHelper; - -import org.onap.policy.appclcm.AppcLcmDmaapWrapper; -import org.onap.policy.controlloop.VirtualControlLoopEvent; -import org.onap.policy.controlloop.ControlLoopEventStatus; -import org.onap.policy.controlloop.ControlLoopException; -import org.onap.policy.controlloop.ControlLoopNotification; -import org.onap.policy.controlloop.ControlLoopNotificationType; -import org.onap.policy.controlloop.VirtualControlLoopNotification; -import org.onap.policy.controlloop.compiler.ControlLoopCompiler; -import org.onap.policy.controlloop.policy.ControlLoop; -import org.onap.policy.controlloop.policy.ControlLoopPolicy; -import org.onap.policy.drools.core.PolicySession; -import org.onap.policy.drools.droolsinit.DroolsInitFeature; -import org.onap.policy.drools.system.PolicyController; -import org.onap.policy.drools.system.PolicyEngineConstants; -import org.onap.policy.guard.GuardContext; -import org.onap.policy.guard.PolicyGuardResponse; - -import org.onap.policy.m2.base.GuardAdjunct; -import org.onap.policy.m2.base.Transaction; -import org.onap.policy.m2.base.Util; -import org.onap.policy.m2.appclcm.AppcLcmOperation; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayInputStream; -import java.net.URLDecoder; -import java.time.Instant; -import java.util.LinkedList; -import java.util.Properties; - -declare Params - closedLoopControlName : String - controlLoopYaml : String - notificationTopic : String - operationTopic : String -end - -declare Context - logger : Logger - metricsLogger : Logger - auditLogger : Logger - policy : ControlLoopPolicy - guardContext : GuardContext - maxObjectCount : long - closedLoopControlName : String - controlLoopYaml : String - notificationTopic : String - operationTopic : String -end - -// this object is to provide support for timeouts -// due to a bug in drools' built in timers -declare ControlLoopTimer - closedLoopControlName : String - requestId : String - delay : String - expired : boolean - //timerType is the type of timer: either "ClosedLoop" or "Operation" - timerType : String -end - -function void sendNotification(Context context, - KnowledgeHelper drools, - ControlLoopNotification notification) -{ - if (notification != null) - { - notification.setFrom("policy"); - notification.setPolicyName(drools.getRule().getName()); - notification.setPolicyScope("${policyScope}"); - notification.setPolicyVersion("${policyVersion}"); - - Util.deliver(context.getNotificationTopic(), notification); - } -} - -function Context setParams(Context context) -{ - context.setClosedLoopControlName("${closedLoopControlName}"); - context.setControlLoopYaml("${controlLoopYaml}"); - context.setNotificationTopic("${notificationTopic}"); - context.setOperationTopic("${operationTopic}"); - context.setPolicy(ControlLoopCompiler.compile - (new ByteArrayInputStream - (URLDecoder.decode(context.getControlLoopYaml(), - "UTF-8").getBytes()), null)); - return context; -} - -rule "${policyName}.INIT" - salience 100 - when - $init : DroolsInitFeature.Init() - not(Context(closedLoopControlName == "${closedLoopControlName}")) - then - { - Logger logger = LoggerFactory.getLogger("${policyName}.drl"); - Logger metricsLogger = LoggerFactory.getLogger("com.att.eelf.metrics"); - Logger auditLogger = LoggerFactory.getLogger("com.att.eelf.audit"); - logger.info("This is ${policyName}.INIT"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - - Context context = new Context(); - context.setLogger(logger); - // add metricsLogger to context - context.setMetricsLogger(metricsLogger); - context.setAuditLogger(auditLogger); - context = setParams(context); - - PolicySession session = PolicySession.getCurrentSession(); - - context.setGuardContext(new GuardContext(session)); - - try - { - // initially, set a default maximum object count of 1000 - context.setMaxObjectCount(1000); - - // 'IllegalArgumentException' if the properties can't be found - PolicyController policyController = - Util.getPolicyController(session); - Properties properties = policyController.getProperties(); - - String maxObjectCount = - properties.getProperty("overload.maxObjectCount","").trim(); - if (!maxObjectCount.isEmpty()) - { - // A value has been specified in the properties file -- - // 'NumberFormatException' if the value is bad - context.setMaxObjectCount(Long.valueOf(maxObjectCount)); - } - } - catch (IllegalArgumentException e) - { - logger.error("${policyName}.INIT: Can't locate properties", e); - } - catch (Exception e) - { - logger.error - ("${policyName}.INIT: Can't decode 'overload.maxObjectCount'", e); - } - - insert(context); - } -end - -/* - * This rule fires when a drools update occurs. Its purpose is to - * update the expandable parameters of the context object to reflect - * the new state of the policy. - */ -rule "${policyName}.REINIT" - salience 100 - when - $init : DroolsInitFeature.Init() - $context : Context(closedLoopControlName == "${closedLoopControlName}" - && (controlLoopYaml != "${controlLoopYaml}" - || notificationTopic != "${notificationTopic}" || operationTopic != "${operationTopic}")) - then - { - Logger logger = $context.getLogger(); - // get metricsLogger from context - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.REINIT"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - - $context = setParams($context); - - modify($context) - { - } - } -end - -/* - * Fires when an incoming 'ONSET' event occurs, without an associated - * 'Transaction' instance - */ -rule "${policyName}.EVENT.NO-TRANSACTION" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $event : VirtualControlLoopEvent(closedLoopControlName == $context.closedLoopControlName, closedLoopEventStatus == ControlLoopEventStatus.ONSET) - not(Transaction(closedLoopControlName == $context.closedLoopControlName, requestId == $event.requestId)) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.info("This is ${policyName}.EVENT.NO-TRANSACTION"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - - // check for overload - if (drools.getWorkingMemory().getFactCount() > - $context.getMaxObjectCount()) - { - // send 'Overload' notification - ControlLoopNotification notification = - new VirtualControlLoopNotification($event); - notification.setNotification(ControlLoopNotificationType.REJECTED); - notification.setMessage("Overload in progress"); - sendNotification($context, drools, notification); - - // discard event, and return - auditLogger.info(Instant.now() + "Event End: FAIL: Overload in progress"); - retract($event); - return; - } - - Transaction transaction = - new Transaction(drools.getWorkingMemory(), - $context.getClosedLoopControlName(), - $event.getRequestId(), - $context.getPolicy()); - - // - // Setup the Overall Control Loop timer - // - ControlLoopTimer clTimer = - new ControlLoopTimer($event.getClosedLoopControlName(), $event.getRequestId().toString(), - transaction.getTimeout(), false, "ClosedLoop"); - - insert(clTimer); - - // check that the event and a&ai is valid - if (!transaction.isControlLoopEventValid($event) || - !AppcLcmOperation.isAaiValid(transaction, $event)) { - ControlLoopNotification notification = - new VirtualControlLoopNotification($event); - notification.setNotification(ControlLoopNotificationType.REJECTED); - notification.setMessage(transaction.getNotificationMessage()); - sendNotification($context, drools, notification); - - // discard event, and return - auditLogger.info(Instant.now() + "Event End: FAIL: Invalid event/AAI"); - retract($event); - return; - } - - // this adjunct needs to be in place before the first 'Operation' - // is created - GuardAdjunct.create(transaction, $context.getGuardContext()); - insert(transaction); - - // this creates the initial 'Operation' - transaction.setControlLoopEvent($event); - retract($event); - - // send out an active notification - ControlLoopNotification notification = transaction.getNotification(null); - notification.setNotification(ControlLoopNotificationType.ACTIVE); - sendNotification($context, drools, notification); - } -end - -/* - * Fires when 'ONSET' and 'ABATED' events have occured before an appc request was processed - */ -rule "${policyName}.TRANSACTION.ABATED.NO-REQUEST" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state != AppcLcmOperation.LCM_PENDING && - state != "COMPLETE" && state != AppcLcmOperation.LCM_COMPLETE) - $event : VirtualControlLoopEvent(closedLoopControlName == $context.closedLoopControlName, closedLoopEventStatus == ControlLoopEventStatus.ABATED, requestId == $transaction.requestId) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("${policyName}.TRANSACTION.ABATED.NO-REQUEST"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - - $transaction.incomingMessage($event); - modify($transaction) - { - } - } -end - -rule "${policyName}.TRANSACTION.LCM.GUARD_PENDING.RESPONSE" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == AppcLcmOperation.LCM_GUARD_PENDING) - $response : PolicyGuardResponse(requestId == $transaction.getRequestId()) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.TRANSACTION.LCM.GUARD_PENDING.RESPONSE"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - sendNotification($context, drools, - $transaction.incomingMessage($response)); - // - // insert operation timeout object - // - ControlLoopTimer opTimer = - new ControlLoopTimer($transaction.getClosedLoopControlName(), $transaction.getRequestId().toString(), - $transaction.getOperationTimeout(), false, "Operation"); - insert(opTimer); - - modify($transaction) - { - } - retract($response); - } -end - -/* - * Initial state for LCM operations (Restart/Rebuild/Migrate) - */ -rule "${policyName}.TRANSACTION.LCM.BEGIN" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction : Transaction(closedLoopControlName == $context.closedLoopControlName, state == AppcLcmOperation.LCM_BEGIN) - ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), !expired, timerType == "Operation") - not(VirtualControlLoopEvent(closedLoopControlName == $context.closedLoopControlName, closedLoopEventStatus == ControlLoopEventStatus.ABATED, requestId == $transaction.requestId)) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.TRANSACTION.LCM.BEGIN"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - Object request = null; - try { - request = $transaction.getCurrentOperation().getRequest(); - } catch (ControlLoopException e) { - logger.error("request could not be formed due to: "+e.getMessage()); - return; - } - Util.deliver($context.getOperationTopic(), request); - - // send notification - sendNotification($context, drools, - $transaction.initialOperationNotification()); - - modify($transaction) - { - } - } -end - -/* - * We are waiting for an LCM response, and one has occurred - * (it may or may not be the one we were expecting) - */ -rule "${policyName}.TRANSACTION.LCM.PENDING.RESPONSE" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == AppcLcmOperation.LCM_PENDING) - $opTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), !expired, timerType == "Operation") - $response : AppcLcmDmaapWrapper(body.output.commonHeader.requestId == $transaction.getRequestId()) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.TRANSACTION.LCM.PENDING.RESPONSE"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - ControlLoopNotification notification = $transaction.incomingMessage($response); - sendNotification($context, drools, notification); - if (notification != null) { - retract($opTimer); - } - modify($transaction) - { - } - retract($response); - } -end - -/* -* -* This is the timer that manages the timeout for an individual operation. -* Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause -* -*/ -rule "${policyName}.LCM.OPERATION.TIMER.FIRED" - timer (expr: $timeout) - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $opTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, $timeout : delay, !expired, timerType == "Operation") - then - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - modify($opTimer){setExpired(true)}; - end - -/* - * We are waiting for an LCM response, but the timer expired before - * receiving one. - */ -rule "${policyName}.TRANSACTION.LCM.PENDING.TIMEOUT" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == AppcLcmOperation.LCM_PENDING, $timeout : getOperationTimeout()) - $opTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), expired, timerType == "Operation") - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.TRANSACTION.LCM.PENDING.TIMEOUT: " - + $transaction.getOperationTimeout()); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - sendNotification($context, drools, $transaction.timeout()); - retract($opTimer); - modify($transaction) - { - } - } -end - -rule "${policyName}.TRANSACTION.LCM.PENDING.ERROR" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == AppcLcmOperation.LCM_ERROR) - $timers : LinkedList() - from collect (ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), timerType == "Operation")) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.TRANSACTION.LCM.ERROR"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - $transaction.processError(); - for (Object timer : $timers) { - retract(timer); - } - modify($transaction) - { - } - } -end - -/* - * We are in the 'LCM_COMPLETE' state, meaning no operations are in progress, - * and no 'ABATED' message is expected so the transaction can complete. - */ -rule "${policyName}.TRANSACTION.COMPLETE.NOT-ABATED" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}", getPolicy().getControlLoop().getAbatement() == false) - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == "COMPLETE") - $clTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), timerType == "ClosedLoop") - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.info("This is ${policyName}.TRANSACTION.COMPLETE.NOT-ABATED"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - auditLogger.info(Instant.now() + " Event End: SUCCESS: NOT-ABATED"); - retract($transaction); - retract($clTimer); - $transaction.cleanup(); - - sendNotification($context, drools, $transaction.finalNotification()); - } -end - -/* - * We are in the 'COMPLETE' state, meaning no operations are in progress, - * and we have received an 'ABATED' message. - */ -rule "${policyName}.TRANSACTION.COMPLETE.ABATED" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}", getPolicy().getControlLoop().getAbatement() == true) - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == "COMPLETE") - $event : VirtualControlLoopEvent(closedLoopControlName == $context.closedLoopControlName, closedLoopEventStatus == ControlLoopEventStatus.ABATED, requestId == $transaction.requestId) - $clTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), timerType == "ClosedLoop") - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.info("This is ${policyName}.TRANSACTION.COMPLETE.ABATED"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - auditLogger.info(Instant.now() + "Event End: SUCCESS: ABATED"); - retract($event); - retract($transaction); - retract($clTimer); - $transaction.cleanup(); - - sendNotification($context, drools, $transaction.finalNotification()); - } -end - -/* - * We are in the 'COMPLETE' state, meaning no operations are in progress, - * and the overall transaction failed, so no ABATED message is expected. - */ -rule "${policyName}.TRANSACTION.COMPLETE.FAILED" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName, state == "COMPLETE", finalResultFailure) - $clTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), timerType == "ClosedLoop") - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.info("This is ${policyName}.TRANSACTION.COMPLETE.FAILED"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - auditLogger.info(Instant.now() + "Transaction End: FAIL: Final Result Failure"); - retract($transaction); - retract($clTimer); - $transaction.cleanup(); - - sendNotification($context, drools, $transaction.finalNotification()); - } -end - -/* -* -* This is the timer that manages the overall control loop timeout. -* Due to a bug in the drools code, the drools timer needed to be split from most of the objects in the when clause -* -*/ -rule "${policyName}.CLOSED_LOOP.TIMER.FIRED" - timer (expr: $timeout) - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $clTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, $timeout : delay, !expired, timerType == "ClosedLoop") - then - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - logger.info("This is ${policyName}.CLOSED_LOOP.TIMER.FIRED"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - modify($clTimer){setExpired(true)}; - end - -/* - * The overall transaction has timed out. - */ -rule "${policyName}.TRANSACTION.TIMEOUT" - when - $context : Context(closedLoopControlName == "${closedLoopControlName}") - $transaction: Transaction(closedLoopControlName == $context.closedLoopControlName) - $clTimer : ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), expired, timerType == "ClosedLoop") - $opTimers : LinkedList() - from collect (ControlLoopTimer(closedLoopControlName == $context.closedLoopControlName, requestId == $transaction.getRequestId().toString(), timerType == "Operation")) - then - { - Logger logger = $context.getLogger(); - Logger metricsLogger = $context.getMetricsLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.info("This is ${policyName}.TRANSACTION.TIMEOUT"); - metricsLogger.info("{} {} {}", Instant.now(), drools.getRule().getName(), drools.getRule().getPackage()); - auditLogger.info(Instant.now() + "Transaction End: FAIL: Transaction Timeout"); - retract($transaction); - retract($clTimer); - // Drools does not support generics, so the time of the objects in opTimers - // can't be set to OperationTimer. Therefore, timer must be an Object. - for (Object timer : $opTimers) { - retract(timer); - } - $transaction.cleanup(); - $transaction.clTimeout(); - - sendNotification($context, drools, $transaction.finalNotification()); - } -end - -/* ============================================================ */ - -/* - * This rule is an audit runs at a low priority, and cleans up any unclaimed - * 'ControlLoopEvent' instances. The assumption is that all other rules are - * structured so that incoming messages will be processed, and retracted - * from Drools memory (whether or not they are retained within the - * transaction). - */ -rule "${policyName}.UNCLAIMED-EVENT" - salience -1000 - when - $context : Context() - $event : VirtualControlLoopEvent() - then - { - Logger logger = $context.getLogger(); - Logger auditLogger = $context.getAuditLogger(); - logger.debug("${policyName}.UNCLAIMED-EVENT: " + $event); - auditLogger.info(Instant.now() + "Event End: FAIL: UNCLAIMED-EVENT - See error log"); - retract($event); - } -end - -/* - * This rule is an audit runs at a low priority, and cleans up any unclaimed - * 'PolicyGuardResponse' instances. The assumption is that all other rules are - * structured so that incoming messages will be processed, and retracted - * from Drools memory (whether or not they are retained within the - * transaction). - */ -rule "${policyName}.UNCLAIMED-POLICY-GUARD-RESPONSE" - salience -1000 - when - $context : Context() - $response : PolicyGuardResponse() - then - { - Logger logger = $context.getLogger(); - logger.error("${policyName}.UNCLAIMED-POLICY-GUARD-RESPONSE: " - + $response); - retract($response); - } -end - -/* - * This rule is an audit runs at a low priority, and cleans up any unclaimed - * 'Response' instances. The assumption is that all other rules are - * structured so that incoming messages will be processed, and retracted - * from Drools memory (whether or not they are retained within the - * transaction). - */ -rule "${policyName}.UNCLAIMED-LCM-RESPONSE" - salience -1000 - when - $context : Context() - $response : AppcLcmDmaapWrapper() - then - { - Logger logger = $context.getLogger(); - logger.error("${policyName}.UNCLAIMED-LCM-RESPONSE: " + $response); - retract($response); - } -end diff --git a/controlloop/m2/test/src/test/resources/appclcm/controller.properties b/controlloop/m2/test/src/test/resources/appclcm/controller.properties deleted file mode 100644 index 6eca45733..000000000 --- a/controlloop/m2/test/src/test/resources/appclcm/controller.properties +++ /dev/null @@ -1,58 +0,0 @@ -### -# ============LICENSE_START======================================================= -# ONAP -# ================================================================================ -# Modifications Copyright (C) 2020 Bell Canada. -# ================================================================================ -# 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========================================================= -### - -# CONTROLLER section -controller.name=appclcm - -persistence.type=auto - -dmaap.source.topics=org.onap.DCAE-APPCLCM-TOPIC - -dmaap.source.topics.org.onap.DCAE-APPCLCM-TOPIC.events=org.onap.policy.controlloop.VirtualControlLoopEvent -dmaap.source.topics.org.onap.DCAE-APPCLCM-TOPIC.events.org.onap.policy.controlloop.VirtualControlLoopEvent.filter=[?($.closedLoopControlName =~ /.*/)] -dmaap.source.topics.org.onap.DCAE-APPCLCM-TOPIC.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gson -dmaap.source.topics.org.onap.DCAE-APPCLCM-TOPIC.servers=127.0.0.1 - -ueb.source.topics=APPC-RESPONSE-APPCLCM-TOPIC - -ueb.source.topics.APPC-RESPONSE-APPCLCM-TOPIC.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper -ueb.source.topics.APPC-RESPONSE-APPCLCM-TOPIC.events.org.onap.policy.appclcm.AppcLcmDmaapWrapper.filter=[?($.type == 'response')] -ueb.source.topics.APPC-RESPONSE-APPCLCM-TOPIC.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson -ueb.source.topics.APPC-RESPONSE-APPCLCM-TOPIC.servers=127.0.0.1 - -ueb.sink.topics=NOTIFICATION-APPCLCM-TOPIC,APPC-REQUEST-APPCLCM-TOPIC - -ueb.sink.topics.APPC-REQUEST-APPCLCM-TOPIC.events=org.onap.policy.appclcm.AppcLcmDmaapWrapper -ueb.sink.topics.APPC-REQUEST-APPCLCM-TOPIC.events.custom.gson=org.onap.policy.appclcm.util.Serialization,gson -ueb.sink.topics.APPC-REQUEST-APPCLCM-TOPIC.servers=127.0.0.1 - -ueb.sink.topics.NOTIFICATION-APPCLCM-TOPIC.events=org.onap.policy.controlloop.VirtualControlLoopNotification -ueb.sink.topics.NOTIFICATION-APPCLCM-TOPIC.events.custom.gson=org.onap.policy.controlloop.util.Serialization,gson -ueb.sink.topics.NOTIFICATION-APPCLCM-TOPIC.servers=127.0.0.1 - -guard.javax.persistence.jdbc.driver=org.h2.Driver -#guard.javax.persistence.jdbc.url=jdbc:h2:file:./H2DB -#guard.javax.persistence.jdbc.user=sa -#guard.javax.persistence.jdbc.password= -#guard.pdp.rest.url=http\://127.0.0.1\:8443/pdp/ - -rules.artifactId=appclcm -rules.groupId=org.onap.policy.m2.test -##rules.version=1.0.0-SNAPSHOT diff --git a/controlloop/m2/test/src/test/resources/appclcm/kmodule.xml b/controlloop/m2/test/src/test/resources/appclcm/kmodule.xml deleted file mode 100644 index fc9b66f3e..000000000 --- a/controlloop/m2/test/src/test/resources/appclcm/kmodule.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ============LICENSE_START======================================================= - ONAP Policy Engine - Drools PDP - ================================================================================ - Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - ================================================================================ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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========================================================= - --> - -<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule"> - <kbase name="rules"> - <ksession name="appclcm"/> - </kbase> -</kmodule> diff --git a/controlloop/m2/test/src/test/resources/appclcm/pom.xml b/controlloop/m2/test/src/test/resources/appclcm/pom.xml deleted file mode 100644 index 0cf8b7b92..000000000 --- a/controlloop/m2/test/src/test/resources/appclcm/pom.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<!-- - ============LICENSE_START======================================================= - ONAP Policy Engine - Drools PDP - ================================================================================ - Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. - ================================================================================ - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - 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========================================================= - --> - -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <groupId>org.onap.policy.m2.test</groupId> - <artifactId>appclcm</artifactId> - <version>${project.version}</version> -</project> |