From 104df2c5a55ea57201038531b4f318590f04d7ed Mon Sep 17 00:00:00 2001 From: Joseph Chou Date: Fri, 13 Mar 2020 14:15:35 -0400 Subject: ONAP server pool code update Fix server-pool junit hang due to hardcoded IP Issue-ID: POLICY-2425 Change-Id: Icaf54c0bbd81fa755a031df91ee6cf5cdee98f27 Signed-off-by: Joseph Chou --- .../feature/config/feature-server-pool.properties | 10 +- .../onap/policy/drools/serverpool/AdapterImpl.java | 69 +++++----- .../onap/policy/drools/serverpooltest/Adapter.java | 50 ++++---- .../policy/drools/serverpooltest/SimDmaap.java | 32 +++-- .../resources/TestController-controller.properties | 2 +- .../resources/feature-server-pool-test.properties | 142 +++++++++++++++++++++ 6 files changed, 226 insertions(+), 79 deletions(-) create mode 100644 feature-server-pool/src/test/resources/feature-server-pool-test.properties diff --git a/feature-server-pool/src/main/feature/config/feature-server-pool.properties b/feature-server-pool/src/main/feature/config/feature-server-pool.properties index 7be2167f..00380294 100644 --- a/feature-server-pool/src/main/feature/config/feature-server-pool.properties +++ b/feature-server-pool/src/main/feature/config/feature-server-pool.properties @@ -22,8 +22,8 @@ # server binds to. The default will bind to all interfaces on the host, # and choose a port number at random. -server.pool.server.ipAddress=0.0.0.0 -server.pool.server.port=${envd:SERVER_POOL_PORT} +server.pool.server.ipAddress=${envd:SERVER_POOL_SERVER_IP} +server.pool.server.port=${envd:SERVER_POOL_PORT:20000} # The following properties determine whether HTTPS is used -- note that HTTPS # also requires that the 'java.net.ssl.*' parameters in 'system.properties' be @@ -76,7 +76,8 @@ server.pool.server.threads.keepAliveTime=5000 # keeps this channel open long-term. server.pool.discovery.servers=${envd:SERVER_POOL_DISCOVERY_SERVERS} -server.pool.discovery.topic=${envd:SERVER_POOL_DISCOVERY_TOPIC} +server.pool.discovery.port=${envd:SERVER_POOL_DISCOVERY_PORT:3904} +server.pool.discovery.topic=${envd:SERVER_POOL_DISCOVERY_TOPIC:DISCOVERY-TOPIC} server.pool.discovery.username=${envd:SERVER_POOL_DISCOVERY_USERNAME} server.pool.discovery.password=${envd:SERVER_POOL_DISCOVERY_PASSWORD} server.pool.discovery.https=${envd:DMAAP_USE_HTTPS} @@ -116,11 +117,14 @@ keyword.path=requestID,CommonHeader.RequestID,body.output.common-header.request- # by '.' that are used to locate the keyword # (e.g. 'method1().field2.method3()') +keyword.java.lang.String.lookup=toString() keyword.org.onap.policy.m2.base.Transaction.lookup=getRequestID() keyword.org.onap.policy.controlloop.ControlLoopEvent.lookup=requestID keyword.org.onap.policy.appclcm.LcmRequestWrapper.lookup=getBody().getCommonHeader().getRequestId() keyword.org.onap.policy.appclcm.LcmResponseWrapper.lookup=getBody().getCommonHeader().getRequestId() keyword.org.onap.policy.drools.serverpool.TargetLock.lookup=getOwnerKey() +keyword.org.onap.policy.drools.serverpooltest.TestDroolsObject.lookup=getKey() +keyword.org.onap.policy.drools.serverpooltest.Test1$KeywordWrapper.lookup=key # The following properties affect distributed 'TargetLock' behavior. # diff --git a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpool/AdapterImpl.java b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpool/AdapterImpl.java index bac13f18..70dc2114 100644 --- a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpool/AdapterImpl.java +++ b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpool/AdapterImpl.java @@ -27,27 +27,21 @@ import java.nio.file.Paths; import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; - import org.kie.api.runtime.KieSession; - import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.common.endpoints.event.comm.TopicListener; - import org.onap.policy.drools.core.PolicyContainer; import org.onap.policy.drools.core.PolicySession; import org.onap.policy.drools.core.PolicySessionFeatureApiConstants; - import org.onap.policy.drools.serverpooltest.Adapter; import org.onap.policy.drools.serverpooltest.BucketWrapper; import org.onap.policy.drools.serverpooltest.ServerWrapper; import org.onap.policy.drools.serverpooltest.TargetLockWrapper; - 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.powermock.reflect.Whitebox; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,10 +51,11 @@ import org.slf4j.LoggerFactory; */ public class AdapterImpl extends Adapter { private static Logger logger = LoggerFactory.getLogger(AdapterImpl.class); - - // Each 'AdapterImpl' instance has it's own class object, making it a - // singleton. There is only a single 'Adapter' class object, and all - // 'AdapterImpl' classes are derived from it. + /* + * Each 'AdapterImpl' instance has it's own class object, making it a + * singleton. There is only a single 'Adapter' class object, and all + * 'AdapterImpl' classes are derived from it. + */ private static AdapterImpl adapter = null; // this is the adapter index @@ -94,29 +89,30 @@ public class AdapterImpl extends Adapter { PolicyEngineConstants.getManager().configure(new Properties()); PolicyEngineConstants.getManager().start(); - - // Note that this method does basically what - // 'FeatureServerPool.afterStart(PolicyEngine)' does, but allows us to - // specify different properties for each of the 6 simulated hosts + /* + * Note that this method does basically what + * 'FeatureServerPool.afterStart(PolicyEngine)' does, but allows us to + * specify different properties for each of the 6 simulated hosts + */ logger.info("{}: Running: AdapterImpl.init({}), class hash code = {}", this, index, AdapterImpl.class.hashCode()); - - Properties prop = new Properties(); - prop.setProperty("server.pool.discovery.servers", "127.0.63.250"); - prop.setProperty("server.pool.discovery.topic", "DISCOVERY-TOPIC"); - prop.setProperty("server.pool.server.ipAddress", "127.0.63." + index); - prop.setProperty("server.pool.server.port", "20000"); - - prop.setProperty("keyword.path", "requestID,CommonHeader.RequestID,key"); - - prop.setProperty("keyword.org.onap.policy.m2.base.Transaction.lookup", - "getRequestID()"); - prop.setProperty("keyword.org.onap.policy.controlloop.ControlLoopEvent.lookup", "requestID"); - prop.setProperty("keyword.org.onap.policy.drools.serverpool.TargetLock.lookup", "getOwnerKey()"); - prop.setProperty("keyword.java.lang.String.lookup", "toString()"); - prop.setProperty("keyword.org.onap.policy.drools.serverpooltest.TestDroolsObject.lookup", - "getKey()"); - prop.setProperty("keyword.org.onap.policy.drools.serverpooltest.Test1$KeywordWrapper.lookup", "key"); + final String propertyFile = "src/test/resources/feature-server-pool-test.properties"; + Properties prop = PropertyUtil.getProperties(propertyFile); + if (System.getProperty("os.name").toLowerCase().indexOf("mac") < 0) { + // Window, Unix + String[] ipComponent = prop.getProperty("server.pool.server.ipAddress").split("[.]"); + String serverIP = ipComponent[0] + "." + ipComponent[1] + "." + ipComponent[2] + "." + + (Integer.parseInt(ipComponent[3]) + index); + prop.setProperty("server.pool.server.ipAddress", serverIP); + } else { + // Mac, use localhost and different ports + String port = Integer.toString(Integer.parseInt( + prop.getProperty("server.pool.server.port")) + index); + prop.setProperty("server.pool.server.port", port); + } + logger.info("server={}, serverIP={}, port={}", index, + prop.getProperty("server.pool.server.ipAddress"), + prop.getProperty("server.pool.server.port")); TargetLock.startup(); Server.startup(prop); @@ -181,8 +177,6 @@ public class AdapterImpl extends Adapter { while (bucket.getOwner() == null) { Thread.sleep(Math.min(endTime - System.currentTimeMillis(), 100L)); } - //await().atMost(endTime - System.currentTimeMillis(), - //TimeUnit.MILLISECONDS).until(() -> bucket.getOwner() != null); } } catch (IllegalArgumentException e) { // 'Thread.sleep()' was passed a negative time-out value -- @@ -253,10 +247,11 @@ public class AdapterImpl extends Adapter { @Override public String createController() { Properties properties; - - // set the thread class loader to be the same as the one associated - // with the 'AdapterImpl' instance, so it will be inherited by any - // new threads created (the Drools session thread, in particular) + /* + * set the thread class loader to be the same as the one associated + * with the 'AdapterImpl' instance, so it will be inherited by any + * new threads created (the Drools session thread, in particular) + */ ClassLoader saveClassLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(AdapterImpl.class.getClassLoader()); diff --git a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/Adapter.java b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/Adapter.java index 03b970b5..d5d836b4 100644 --- a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/Adapter.java +++ b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/Adapter.java @@ -23,21 +23,16 @@ package org.onap.policy.drools.serverpooltest; import static org.junit.Assert.assertTrue; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; import java.io.PrintStream; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; -import java.util.Arrays; +import java.util.Properties; import java.util.concurrent.LinkedBlockingQueue; - import org.kie.api.runtime.KieSession; import org.onap.policy.common.utils.network.NetworkUtil; import org.onap.policy.drools.serverpool.Util; +import org.onap.policy.drools.utils.PropertyUtil; /** * This is a common base class for 6 'AdapterImpl' instances, all running @@ -53,11 +48,12 @@ import org.onap.policy.drools.serverpool.Util; public abstract class Adapter { // 'true' indicates that initialization is still needed private static boolean initNeeded = true; - - // Each 'Adapter' instance is implemented by 'AdapterImpl', but loaded - // with a different class loader that provides each with a different copy - // of the set of classes with packages in the list below (see references to - // 'BlockingClassLoader'). + /* + * Each 'Adapter' instance is implemented by 'AdapterImpl', but loaded + * with a different class loader that provides each with a different copy + * of the set of classes with packages in the list below (see references to + * 'BlockingClassLoader'). + */ public static Adapter[] adapters = new Adapter[6]; /** @@ -76,8 +72,11 @@ public abstract class Adapter { } }, "DMAAP Simulator").start(); - // wait 1 second to allow time for the port 3904 listener - assertTrue(NetworkUtil.isTcpPortOpen(SimDmaap.HOSTNAME, 3904, 50, 1000)); + // wait 200 millisecond to allow time for the port 3904 listener + final String propertyFile = "src/test/resources/feature-server-pool-test.properties"; + Properties prop = PropertyUtil.getProperties(propertyFile); + assertTrue(NetworkUtil.isTcpPortOpen(prop.getProperty("server.pool.discovery.servers"), + Integer.parseInt(prop.getProperty("server.pool.discovery.port")), 250, 200)); // build 'BlockingClassLoader' BlockingClassLoader bcl = new BlockingClassLoader( @@ -113,18 +112,21 @@ public abstract class Adapter { } try { for (int i = 0 ; i < adapters.length ; i += 1) { - // Build a new 'ClassLoader' for this adapter. The - // 'ClassLoader' hierarchy is: - // - // AdapterClassLoader(one copy per Adapter) -> - // BlockingClassLoader -> - // base ClassLoader (with the complete URL list) + /* + * Build a new 'ClassLoader' for this adapter. The + * 'ClassLoader' hierarchy is: + * + * AdapterClassLoader(one copy per Adapter) -> + * BlockingClassLoader -> + * base ClassLoader (with the complete URL list) + */ ClassLoader classLoader = new AdapterClassLoader(i, urls, bcl); - - // set the current thread class loader, which should be - // inherited by any child threads created during - // the initialization of the adapter + /* + * set the current thread class loader, which should be + * inherited by any child threads created during + * the initialization of the adapter + */ Thread.currentThread().setContextClassLoader(classLoader); // now, build the adapter -- it is not just a new instance, diff --git a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/SimDmaap.java b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/SimDmaap.java index 74fef07f..8513c1f0 100644 --- a/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/SimDmaap.java +++ b/feature-server-pool/src/test/java/org/onap/policy/drools/serverpooltest/SimDmaap.java @@ -21,6 +21,7 @@ package org.onap.policy.drools.serverpooltest; import java.util.Map; +import java.util.Properties; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; @@ -39,7 +40,7 @@ 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.drools.utils.PropertyUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -50,7 +51,6 @@ import org.slf4j.LoggerFactory; @Path("/") public class SimDmaap { private static Logger logger = LoggerFactory.getLogger(SimDmaap.class); - public static final String HOSTNAME = "127.0.63.250"; // miscellaneous Jetty/Servlet parameters private static ServletContextHandler context; @@ -73,8 +73,10 @@ public class SimDmaap { connector = new ServerConnector(jettyServer); connector.setName("simdmaap"); connector.setReuseAddress(true); - connector.setPort(3904); - connector.setHost("127.0.63.250"); + final String propertyFile = "src/test/resources/feature-server-pool-test.properties"; + Properties prop = PropertyUtil.getProperties(propertyFile); + connector.setPort(Integer.parseInt(prop.getProperty("server.pool.discovery.port"))); + connector.setHost(prop.getProperty("server.pool.discovery.servers")); jettyServer.addConnector(connector); jettyServer.setHandler(context); @@ -166,11 +168,12 @@ public class SimDmaap { 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). - + /* + * 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 @@ -182,11 +185,12 @@ public class SimDmaap { // determine length of message, and advance current position int length = Integer.valueOf(prefix[1]); cur = leftBrace + length; - - // extract message, and update count -- 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 + /* + * extract message, and update count -- 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"); diff --git a/feature-server-pool/src/test/resources/TestController-controller.properties b/feature-server-pool/src/test/resources/TestController-controller.properties index 89414b5e..7d645588 100644 --- a/feature-server-pool/src/test/resources/TestController-controller.properties +++ b/feature-server-pool/src/test/resources/TestController-controller.properties @@ -7,7 +7,7 @@ rules.groupId=org.onap.policy.drools-pdp rules.version=1.0.0 ueb.source.topics=JUNIT-TEST-TOPIC -ueb.source.topics.JUNIT-TEST-TOPIC.servers=127.0.63.250 +ueb.source.topics.JUNIT-TEST-TOPIC.servers=127.0.0.1 ueb.source.topics.JUNIT-TEST-TOPIC.events=org.onap.policy.drools.serverpooltest.TestDroolsObject ueb.source.topics.JUNIT-TEST-TOPIC.events.org.onap.policy.drools.serverpooltest.TestDroolsObject.filter= [?($.key =~ /.*/)] \ No newline at end of file diff --git a/feature-server-pool/src/test/resources/feature-server-pool-test.properties b/feature-server-pool/src/test/resources/feature-server-pool-test.properties new file mode 100644 index 00000000..70fed3ff --- /dev/null +++ b/feature-server-pool/src/test/resources/feature-server-pool-test.properties @@ -0,0 +1,142 @@ +### +# ============LICENSE_START======================================================= +# feature-server-pool +# ================================================================================ +# 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========================================================= +### + +# The following properties control the IP address and port that a given +# server binds to. The default will bind to all interfaces on the host, +# and choose a port number at random. + +server.pool.server.ipAddress=127.0.0.1 +server.pool.server.port=20000 + +# The following properties determine whether HTTPS is used -- note that HTTPS +# also requires that the 'java.net.ssl.*' parameters in 'system.properties' be +# specified, and the key store and trust store be configured, as appropriate. +server.pool.server.https= +server.pool.server.selfSignedCerts=false + +# The IP address and port that servers on the geo-redundant site +# should use to connect to servers on this site. +server.pool.server.site.ip= +server.pool.server.site.port= + +# A comma-separated list of host names -- if an entry is found that refers +# to an HTTP/HTTPS destination IP address, the host name will used as the +# destination, instead of the IP address +server.pool.server.hostlist= + +# The servers send 'pings' to each other once per main loop cycle. They +# also measure the gap between 'pings' from each server, and calculate +# an allowed time gap based upon this. 'server.pool.server.allowedGap' is the initial +# allowed gap prior to receiving any pings (default=30 seconds), and +# 'server.pool.server.adaptiveGapAdjust' is a value that is added to the calculated +# gap "just in case" (default=5 seconds) + +server.pool.server.allowedGap=30000 +server.pool.server.adaptiveGapAdjust=5000 + +# 'connectTimeout' and 'readTimeout' affect the client end of a REST +# connection (default=10 seconds each) + +server.pool.server.connectTimeout=10000 +server.pool.server.readTimeout=10000 + +# Each server has a thread pool per remote server, which is used when +# sending HTTP REST messages -- the following parameters determine the +# configuration. + +server.pool.server.threads.corePoolSize=5 +server.pool.server.threads.maximumPoolSize=10 +server.pool.server.threads.keepAliveTime=5000 + +# The server pool members use a UEB/DMAAP topic to connect with other +# servers in the pool. The following set of parameters are passed to +# the CambriaClient library, and are used in setting up the consumer and +# publisher ends of the connection. 'discovery.servers' and 'discovery.topic' +# are the minimum values that need to be specified. The last parameter in +# this set, 'discovery.publisherLoopCycleTime' isn't passed to the +# CambriaClient library; instead, it controls how frequently the 'ping' +# messages are sent out on this channel. Note that only the lead server +# keeps this channel open long-term. + +server.pool.discovery.servers=127.0.0.1 +server.pool.discovery.port=3904 +server.pool.discovery.topic=DISCOVERY-TOPIC +server.pool.discovery.username= +server.pool.discovery.password= +server.pool.discovery.https= +server.pool.discovery.apiKey= +server.pool.discovery.apiSecret= +#server.pool.discovery.publisherSocketTimeout=5000 +#server.pool.discovery.consumerSocketTimeout=70000 +server.pool.discovery.fetchTimeout=60000 +server.pool.discovery.fetchLimit=100 +server.pool.discovery.selfSignedCertificates=false +server.pool.discovery.publisherLoopCycleTime=5000 + +# The 'leader.*' parameters affect behavior during an election. The value of +# 'mainLoop.cycle' determines the actual time delay. 'leader.stableIdCycles' +# is the required minimum number of "stable" cycles before voting can start +# (in this case, "stable" means no servers added or failing). Once voting has +# started, "leader.stableVotingCycles' is the minimum number of "stable" +# cycles needed before declaring a winner (in this case, "stable" means no +# votes changing). + +server.pool.leader.stableIdleCycles=5 +server.pool.leader.stableVotingCycles=5 + +# The value of 'mainLoop.cycle' (default = 1 second) determines how frequently +# various events occur, such as the sending of 'ping' messages, and the +# duration of a "cycle" while voting for a lead server. + +server.pool.mainLoop.cycle=1000 + +# 'keyword.path' is used when looking for "keywords" within JSON messages. +# The first keyword located is hashed to determine which bucket to route +# through. + +keyword.path=requestID,CommonHeader.RequestID,body.output.common-header.request-id,result-info.request-id:uuid +# 'keyword..lookup' is used to locate "keywords" within objects. +# The 'value' field contains a list of method calls or field names separated +# by '.' that are used to locate the keyword +# (e.g. 'method1().field2.method3()') + +keyword.java.lang.String.lookup=toString() +keyword.org.onap.policy.m2.base.Transaction.lookup=getRequestID() +keyword.org.onap.policy.controlloop.ControlLoopEvent.lookup=requestID +keyword.org.onap.policy.appclcm.LcmRequestWrapper.lookup=getBody().getCommonHeader().getRequestId() +keyword.org.onap.policy.appclcm.LcmResponseWrapper.lookup=getBody().getCommonHeader().getRequestId() +keyword.org.onap.policy.drools.serverpool.TargetLock.lookup=getOwnerKey() +keyword.org.onap.policy.drools.serverpooltest.TestDroolsObject.lookup=getKey() +keyword.org.onap.policy.drools.serverpooltest.Test1$KeywordWrapper.lookup=key + +# The following properties affect distributed 'TargetLock' behavior. +# +# server.pool.lock.ttl - controls how many hops a 'TargetLock' message can take +# server.pool.lock.audit.period - how frequently should the audit run? +# server.pool.lock.audit.gracePeriod - how long to wait after bucket reassignments +# before running the audit again +# server.pool.lock.audit.retryDelay - mismatches can occur due to the transient nature +# of the lock state: this property controls how long to wait before +# trying again + +server.pool.lock.ttl=3 +server.pool.lock.audit.period=300000 +server.pool.lock.audit.gracePeriod=60000 +server.pool.lock.audit.retryDelay=5000 \ No newline at end of file -- cgit 1.2.3-korg