diff options
Diffstat (limited to 'policy-persistence/src')
33 files changed, 7738 insertions, 0 deletions
diff --git a/policy-persistence/src/assembly/assemble_zip.xml b/policy-persistence/src/assembly/assemble_zip.xml new file mode 100644 index 00000000..e0e22f5b --- /dev/null +++ b/policy-persistence/src/assembly/assemble_zip.xml @@ -0,0 +1,85 @@ +<!-- + ============LICENSE_START======================================================= + policy-persistence + ================================================================================ + Copyright (C) 2017 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========================================================= + --> + +<!-- Defines how we build the .zip file which is our distribution. --> + +<assembly + xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd"> + <id>runtime</id> + <formats> + <format>zip</format> + </formats> + + <!-- we want "system" and related files right at the root level as this + file is suppose to be unzip on top of a karaf distro. --> + <includeBaseDirectory>false</includeBaseDirectory> + + <fileSets> + <fileSet> + <directory>target</directory> + <outputDirectory>lib/opt</outputDirectory> + <includes> + <include>policy-persistence-${project.version}.jar</include> + </includes> + </fileSet> + <fileSet> + <directory>target/assembly/</directory> + <outputDirectory>.</outputDirectory> + <excludes> + </excludes> + </fileSet> + <fileSet> + <directory>.</directory> + <outputDirectory>lib</outputDirectory> + <includes> + <include>*.jar</include> + </includes> + </fileSet> + <fileSet> + <directory>src/main/server-gen/bin</directory> + <outputDirectory>bin</outputDirectory> + <fileMode>0744</fileMode> + <excludes> + </excludes> + </fileSet> + <fileSet> + <directory>src/main/server/bin</directory> + <outputDirectory>bin</outputDirectory> + <fileMode>0744</fileMode> + <excludes> + </excludes> + </fileSet> + <fileSet> + <directory>src/main/server-gen/scripts</directory> + <outputDirectory>scripts</outputDirectory> + </fileSet> + <fileSet> + <directory>src/main/server/scripts</directory> + <outputDirectory>scripts</outputDirectory> + </fileSet> + <fileSet> + <directory>src/main/server/config</directory> + <outputDirectory>config</outputDirectory> + </fileSet> + </fileSets> + +</assembly> diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DbAudit.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DbAudit.java new file mode 100644 index 00000000..51e92aa9 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DbAudit.java @@ -0,0 +1,205 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.core; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.util.Properties; +import java.util.UUID; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.common.logging.eelf.MessageCodes; +import org.openecomp.policy.drools.persistence.DroolsPersistenceProperties; + +/** + * This class audits the database + */ +public class DbAudit extends DroolsPDPIntegrityMonitor.AuditBase +{ + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(DbAudit.class); + // single global instance of this audit object + static private DbAudit instance = new DbAudit(); + + // This indicates if 'CREATE TABLE IF NOT EXISTS Audit ...' should be + // invoked -- doing this avoids the need to create the table in advance. + static private boolean createTableNeeded = true; + + /** + * @return the single 'DbAudit' instance + */ + static DroolsPDPIntegrityMonitor.AuditBase getInstance() + { + return(instance); + } + + /** + * Constructor - set the name to 'Database' + */ + private DbAudit() + { + super("Database"); + } + + /** + * Invoke the audit + * + * @param properties properties to be passed to the audit + */ + @Override + public void invoke(Properties droolsPersistenceProperties) + { + logger.info("Running 'DbAudit.invoke'"); + boolean isActive = true; + String dbAuditIsActive = IntegrityMonitorProperties.getProperty("db.audit.is.active"); + logger.debug("DbAudit.invoke: dbAuditIsActive = " + dbAuditIsActive); + + if (dbAuditIsActive != null) { + try { + isActive = Boolean.parseBoolean(dbAuditIsActive.trim()); + } catch (NumberFormatException e) { + logger.warn("DbAudit.invoke: Ignoring invalid property: db.audit.is.active = " + dbAuditIsActive); + } + } + + if(!isActive){ + logger.info("DbAudit.invoke: exiting because isActive = " + isActive); + return; + } + + // fetch DB properties from properties file -- they are already known + // to exist, because they were verified by the 'IntegrityMonitor' + // constructor + String url = droolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_URL); + String user = droolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_USER); + String password = + droolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_PWD); + + // connection to DB + Connection connection = null; + + // supports SQL operations + PreparedStatement statement = null; + ResultSet rs = null; + + // operation phase currently running -- used to construct an error + // message, if needed + String phase = null; + + try + { + // create connection to DB + phase = "creating connection"; + logger.info("DbAudit: Creating connection to " + url); + + connection = DriverManager.getConnection(url, user, password); + + // create audit table, if needed + if (createTableNeeded) + { + phase = "create table"; + logger.info("DbAudit: Creating 'Audit' table, if needed"); + statement = connection.prepareStatement + ("CREATE TABLE IF NOT EXISTS Audit (\n" + + " name varchar(64) DEFAULT NULL,\n" + + " UNIQUE KEY name (name)\n" + + ") DEFAULT CHARSET=latin1;"); + statement.execute(); + createTableNeeded = false; + } + + // insert an entry into the table + phase = "insert entry"; + String key = UUID.randomUUID().toString(); + statement = connection.prepareStatement + ("INSERT INTO Audit (name) VALUES (?)"); + statement.setString(1, key); + statement.executeUpdate(); + + // fetch the entry from the table + phase = "fetch entry"; + statement = connection.prepareStatement + ("SELECT name FROM Audit WHERE name = ?"); + statement.setString(1, key); + rs = statement.executeQuery(); + if (rs.first()) + { + // found entry + logger.info("DbAudit: Found key " + rs.getString(1)); + } + else + { + logger.error + ("DbAudit: can't find newly-created entry with key " + key); + setResponse("Can't find newly-created entry"); + } + + // delete entries from table + phase = "delete entry"; + statement = connection.prepareStatement + ("DELETE FROM Audit WHERE name = ?"); + statement.setString(1, key); + statement.executeUpdate(); + } + catch (Exception e) + { + String message = "DbAudit: Exception during audit, phase = " + phase; + logger.error(MessageCodes.EXCEPTION_ERROR, e, message); + setResponse(message); + } + finally + { + if (rs != null) + { + try + { + rs.close(); + } + catch (Exception e) + { + } + } + if (statement != null) + { + try + { + statement.close(); + } + catch (Exception e) + { + } + } + if (connection != null) + { + try + { + connection.close(); + } + catch (Exception e) + { + } + } + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DroolsPDPIntegrityMonitor.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DroolsPDPIntegrityMonitor.java new file mode 100644 index 00000000..2b6058fd --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/DroolsPDPIntegrityMonitor.java @@ -0,0 +1,485 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.util.LinkedList; +import java.util.Properties; +import java.util.concurrent.Callable; + +import org.openecomp.policy.common.im.IntegrityMonitor; +import org.openecomp.policy.common.logging.flexlogger.PropertyUtil; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.common.logging.eelf.MessageCodes; +import org.openecomp.policy.drools.persistence.DroolsPdpsElectionHandler; +import org.openecomp.policy.drools.persistence.XacmlPersistenceProperties; +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpHandler; +import com.sun.net.httpserver.HttpServer; + +/** + * This class extends 'IntegrityMonitor' for use in the 'Drools PDP' + * virtual machine. The included audits are 'Database' and 'Repository'. + */ +public class DroolsPDPIntegrityMonitor extends IntegrityMonitor +{ + + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(DroolsPDPIntegrityMonitor.class); + + // static global instance + static private DroolsPDPIntegrityMonitor im = null; + + // list of audits to run + static private AuditBase[] audits = + new AuditBase[]{DbAudit.getInstance(), RepositoryAudit.getInstance()}; + + // save initialization properties + private Properties droolsPersistenceProperties = null; + + /** + * Static initialization -- create Drools Integrity Monitor, and + * an HTTP server to handle REST 'test' requests + */ + static public DroolsPDPIntegrityMonitor init(String configDir) throws Exception + { + + logger.info("init: Entering and invoking PropertyUtil.getProperties() on '" + + configDir + "'"); + + // read in properties + Properties integrityMonitorProperties = + PropertyUtil.getProperties(configDir + "/IntegrityMonitor.properties"); + Properties droolsPersistenceProperties = + PropertyUtil.getProperties(configDir + "/droolsPersistence.properties"); + Properties xacmlPersistenceProperties = + PropertyUtil.getProperties(configDir + "/xacmlPersistence.properties"); + + // fetch and verify definitions of some properties + // (the 'IntegrityMonitor' constructor does some additional verification) + String resourceName = integrityMonitorProperties.getProperty("resource.name"); + String hostPort = integrityMonitorProperties.getProperty("hostPort"); + String fpMonitorInterval = integrityMonitorProperties.getProperty("fp_monitor_interval"); + String failedCounterThreshold = integrityMonitorProperties.getProperty("failed_counter_threshold"); + String testTransInterval = integrityMonitorProperties.getProperty("test_trans_interval"); + String writeFpcInterval = integrityMonitorProperties.getProperty("write_fpc_interval"); + String siteName = integrityMonitorProperties.getProperty("site_name"); + String nodeType = integrityMonitorProperties.getProperty("node_type"); + String dependencyGroups = integrityMonitorProperties.getProperty("dependency_groups"); + String droolsJavaxPersistenceJdbcDriver = droolsPersistenceProperties.getProperty("javax.persistence.jdbc.driver"); + String droolsJavaxPersistenceJdbcUrl = droolsPersistenceProperties.getProperty("javax.persistence.jdbc.url"); + String droolsJavaxPersistenceJdbcUser = droolsPersistenceProperties.getProperty("javax.persistence.jdbc.user"); + String droolsJavaxPersistenceJdbcPassword = droolsPersistenceProperties.getProperty("javax.persistence.jdbc.password"); + String xacmlJavaxPersistenceJdbcDriver = xacmlPersistenceProperties.getProperty("javax.persistence.jdbc.driver"); + String xacmlJavaxPersistenceJdbcUrl = xacmlPersistenceProperties.getProperty("javax.persistence.jdbc.url"); + String xacmlJavaxPersistenceJdbcUser = xacmlPersistenceProperties.getProperty("javax.persistence.jdbc.user"); + String xacmlJavaxPersistenceJdbcPassword = xacmlPersistenceProperties.getProperty("javax.persistence.jdbc.password"); + + if (resourceName == null) + { + logger.error("init: Missing IntegrityMonitor property: 'resource.name'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'resource.name'")); + } + if (hostPort == null) + { + logger.error("init: Missing IntegrityMonitor property: 'hostPort'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'hostPort'")); + } + if (fpMonitorInterval == null) + { + logger.error("init: Missing IntegrityMonitor property: 'fp_monitor_interval'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'fp_monitor_interval'")); + } + if (failedCounterThreshold == null) + { + logger.error("init: Missing IntegrityMonitor property: 'failed_counter_threshold'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'failed_counter_threshold'")); + } + if (testTransInterval == null) + { + logger.error("init: Missing IntegrityMonitor property: 'test_trans_interval'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'test_trans_interval'")); + } + if (writeFpcInterval == null) + { + logger.error("init: Missing IntegrityMonitor property: 'write_fpc_interval'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'write_fpc_interval'")); + } + if (siteName == null) + { + logger.error("init: Missing IntegrityMonitor property: 'site_name'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'site_name'")); + } + if (nodeType == null) + { + logger.error("init: Missing IntegrityMonitor property: 'node_type'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'node_type'")); + } + if (dependencyGroups == null) + { + logger.error("init: Missing IntegrityMonitor property: 'dependency_groups'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'dependency_groups'")); + } + if (droolsJavaxPersistenceJdbcDriver == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for drools DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for drools DB'")); + } + if (droolsJavaxPersistenceJdbcUrl == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.url for drools DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.url for drools DB'")); + } + if (droolsJavaxPersistenceJdbcUser == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for drools DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for drools DB'")); + } + if (droolsJavaxPersistenceJdbcPassword == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.password for drools DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.password for drools DB'")); + } + if (xacmlJavaxPersistenceJdbcDriver == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for xacml DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.driver for xacml DB'")); + } + if (xacmlJavaxPersistenceJdbcUrl == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.url for xacml DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.url for xacml DB'")); + } + if (xacmlJavaxPersistenceJdbcUser == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for xacml DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.user for xacml DB'")); + } + if (xacmlJavaxPersistenceJdbcPassword == null) + { + logger.error("init: Missing IntegrityMonitor property: 'javax.persistence.jbdc.password for xacml DB'"); + throw(new Exception + ("Missing IntegrityMonitor property: 'javax.persistence.jbdc.password' for xacml DB'")); + } + + logger.info("init: loading consolidatedProperties"); + Properties consolidatedProperties = new Properties(); + consolidatedProperties.load(new FileInputStream(new File(configDir + "/IntegrityMonitor.properties"))); + consolidatedProperties.load(new FileInputStream(new File(configDir + "/xacmlPersistence.properties"))); + // verify that consolidatedProperties has properties from both properties files. + logger.info("init: PDP_INSTANCE_ID=" + consolidatedProperties.getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID)); + logger.info("init: DB_URL=" + consolidatedProperties.getProperty(XacmlPersistenceProperties.DB_URL)); + + // Now that we've validated the properties, create Drools Integrity Monitor + // with these properties. + im = new DroolsPDPIntegrityMonitor(resourceName, + consolidatedProperties, droolsPersistenceProperties); + logger.info("init: New DroolsPDPIntegrityMonitor instantiated, hostPort=" + hostPort); + + // determine host and port for HTTP server + int index = hostPort.lastIndexOf(':'); + InetSocketAddress addr; + + if (index < 0) + { + addr = new InetSocketAddress(Integer.valueOf(hostPort)); + } + else + { + addr = new InetSocketAddress + (hostPort.substring(0, index), + Integer.valueOf(hostPort.substring(index + 1))); + } + + // create http server + try { + logger.info("init: Starting HTTP server, addr=" + addr); + HttpServer server = HttpServer.create(addr, 0); + server.createContext("/test", new TestHandler()); + server.setExecutor(null); + server.start(); + System.out.println("init: Started server on hostPort=" + hostPort); + } catch (Exception e) { + if (PolicyContainer.isUnitTesting) { + System.out + .println("init: Caught Exception attempting to start server on hostPort=" + + hostPort + ", message=" + e.getMessage()); + } else { + throw e; + } + } + + logger.info("init: Exiting and returning DroolsPDPIntegrityMonitor"); + return im; + } + + /** + * Constructor - pass arguments to superclass, but remember properties + * @param resourceName unique name of this Integrity Monitor + * @param url the JMX URL of the MBean server + * @param properties properties used locally, as well as by + * 'IntegrityMonitor' + * @throws Exception (passed from superclass) + */ + private DroolsPDPIntegrityMonitor(String resourceName, + Properties consolidatedProperties, + Properties droolsPersistenceProperties) throws Exception { + super(resourceName, consolidatedProperties); + this.droolsPersistenceProperties = droolsPersistenceProperties; + } + + /** + * Run tests (audits) unique to Drools PDP VM (Database + Repository) + */ + @Override + public void subsystemTest() throws Exception + { + logger.info("DroolsPDPIntegrityMonitor.subsystemTest called"); + + // clear all responses (non-null values indicate an error) + for (AuditBase audit : audits) + { + audit.setResponse(null); + } + + // invoke all of the audits + for (AuditBase audit : audits) + { + try + { + // invoke the audit (responses are stored within the audit object) + audit.invoke(droolsPersistenceProperties); + } + catch (Exception e) + { + logger.error(MessageCodes.EXCEPTION_ERROR, e, + audit.getName() + " audit error"); + if (audit.getResponse() == null) + { + // if there is no current response, use the exception message + audit.setResponse(e.getMessage()); + } + } + } + + // will contain list of subsystems where the audit failed + String responseMsg = ""; + + // Loop through all of the audits, and see which ones have failed. + // NOTE: response information is stored within the audit objects + // themselves -- only one can run at a time. + for (AuditBase audit : audits) + { + String response = audit.getResponse(); + if (response != null) + { + // the audit has failed -- add subsystem and + // and 'responseValue' with the new information + responseMsg = responseMsg.concat("\n" + audit.getName() + ": " + response); + } + } + + if(!responseMsg.isEmpty()){ + throw new Exception(responseMsg); + } + } + + /* ============================================================ */ + + /** + * This is the base class for audits invoked in 'subsystemTest' + */ + static public abstract class AuditBase + { + // name of the audit + protected String name; + + // non-null indicates the error response + protected String response; + + /** + * Constructor - initialize the name, and clear the initial response + * @param name name of the audit + */ + public AuditBase(String name) + { + this.name = name; + this.response = null; + } + + /** + * @return the name of this audit + */ + public String getName() + { + return(name); + } + + /** + * @return the response String (non-null indicates the error message) + */ + public String getResponse() + { + return(response); + } + + /** + * Set the response string to the specified value + * @param value the new value of the response string (null = no errors) + */ + public void setResponse(String value) + { + response = value; + } + + /** + * Abstract method to invoke the audit + * @param droolsPersistenceProperties Used for DB access + * @throws Exception passed in by the audit + */ + abstract void invoke(Properties droolsPersistenceProperties) throws Exception; + } + + /* ============================================================ */ + + /** + * This class is the HTTP handler for the REST 'test' invocation + */ + static class TestHandler implements HttpHandler + { + /** + * Handle an incoming REST 'test' invocation + * @param ex used to pass incoming and outgoing HTTP information + */ + @Override + public void handle(HttpExchange ex) throws IOException + { + + System.out.println("TestHandler.handle: Entering"); + + // The responses are stored within the audit objects, so we need to + // invoke the audits and get responses before we handle another + // request. + synchronized(TestHandler.class) + { + // will include messages associated with subsystem failures + StringBuilder body = new StringBuilder(); + + // 200=SUCCESS, 500=failure + int responseValue = 200; + + if (im != null) + { + try + { + // call 'IntegrityMonitor.evaluateSanity()' + im.evaluateSanity(); + } + catch (Exception e) + { + // this exception isn't coming from one of the audits, + // because those are caught in 'subsystemTest()' + logger.error + (MessageCodes.EXCEPTION_ERROR, e, + "DroolsPDPIntegrityMonitor.evaluateSanity()"); + + // include exception in HTTP response + body.append("\nException: " + e + "\n"); + responseValue = 500; + } + } +/* + * Audit failures are being logged. A string will be generated which captures the + * the audit failures. This string will be included in an exception coming from im.evaluateSanity(). + * + // will contain list of subsystems where the audit failed + LinkedList<String> subsystems = new LinkedList<String>(); + + // Loop through all of the audits, and see which ones have failed. + // NOTE: response information is stored within the audit objects + // themselves -- only one can run at a time. + for (AuditBase audit : audits) + { + String response = audit.getResponse(); + if (response != null) + { + // the audit has failed -- update 'subsystems', 'body', + // and 'responseValue' with the new information + subsystems.add(audit.getName()); + body + .append('\n') + .append(audit.getName()) + .append(":\n") + .append(response) + .append('\n'); + responseValue = 500; + } + } + + if (subsystems.size() != 0) + { + // there is at least one failure -- add HTTP headers + ex.getResponseHeaders().put("X-ECOMP-SubsystemFailure", + subsystems); + } +*/ + // send response, including the contents of 'body' + // (which is empty if everything is successful) + ex.sendResponseHeaders(responseValue, body.length()); + OutputStream os = ex.getResponseBody(); + os.write(body.toString().getBytes()); + os.close(); + System.out.println("TestHandler.handle: Exiting"); + } + } + } + public static DroolsPDPIntegrityMonitor getInstance() throws Exception{ + logger.info("getInstance() called"); + if (im == null) { + String msg = "No DroolsPDPIntegrityMonitor instance exists." + + " Please use the method DroolsPDPIntegrityMonitor init(String configDir)"; + throw new Exception(msg); + }else{ + return im; + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/core/IntegrityMonitorProperties.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/IntegrityMonitorProperties.java new file mode 100644 index 00000000..d1b1ad6d --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/IntegrityMonitorProperties.java @@ -0,0 +1,68 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.core; + +import java.util.Properties; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + +public class IntegrityMonitorProperties { + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(IntegrityMonitorProperties.class); + + public static final String PDP_INSTANCE_ID = "resource.name"; + + public static final String PDP_CHECK_INVERVAL = "pdp.checkInterval"; + public static final String PDP_UPDATE_INTERVAL = "pdp.updateInterval"; + public static final String PDP_TIMEOUT = "pdp.timeout"; + public static final String PDP_INITIAL_WAIT_PERIOD = "pdp.initialWait"; + + public static final String SITE_NAME = "site_name"; + + private static Properties properties = null; + /* + * Initialize the parameter values from the droolsPersitence.properties file values + * + * This is designed so that the Properties object is obtained from the droolsPersistence.properties + * file and then is passed to this method to initialize the value of the parameters. + * This allows the flexibility of JUnit tests using getProperties(filename) to get the + * properties while runtime methods can use getPropertiesFromClassPath(filename). + * + */ + public static void initProperties (Properties prop){ + logger.info("IntegrityMonitorProperties.initProperties(Properties): entry"); + logger.info("\n\nIntegrityMonitorProperties.initProperties: Properties = \n" + prop + "\n\n"); + + properties = prop; + } + + public static String getProperty(String key){ + return properties.getProperty(key); + } + + public static Properties getProperties() { + return properties; + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/core/RepositoryAudit.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/RepositoryAudit.java new file mode 100644 index 00000000..86c672e2 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/core/RepositoryAudit.java @@ -0,0 +1,524 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.Files; +import java.nio.file.FileVisitor; +import java.nio.file.FileVisitResult; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.util.LinkedList; +import java.util.Properties; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + + +/** + * This class audits the Maven repository + */ +public class RepositoryAudit extends DroolsPDPIntegrityMonitor.AuditBase +{ + private static final long DEFAULT_TIMEOUT = 60; // timeout in 60 seconds + + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(RepositoryAudit.class); + // single global instance of this audit object + static private RepositoryAudit instance = new RepositoryAudit(); + + /** + * @return the single 'RepositoryAudit' instance + */ + static DroolsPDPIntegrityMonitor.AuditBase getInstance() + { + return(instance); + } + + /** + * Constructor - set the name to 'Repository' + */ + private RepositoryAudit() + { + super("Repository"); + } + + /** + * Invoke the audit + * + * @param properties properties to be passed to the audit + */ + @Override + public void invoke(Properties properties) + throws IOException, InterruptedException + { + logger.info("Running 'RepositoryAudit.invoke'"); + + boolean isActive = true; + String repoAuditIsActive = IntegrityMonitorProperties.getProperty("repository.audit.is.active"); + logger.debug("RepositoryAudit.invoke: repoAuditIsActive = " + repoAuditIsActive); + + if (repoAuditIsActive != null) { + try { + isActive = Boolean.parseBoolean(repoAuditIsActive.trim()); + } catch (NumberFormatException e) { + logger.warn("RepositoryAudit.invoke: Ignoring invalid property: repository.audit.is.active = " + repoAuditIsActive); + } + } + + if(!isActive){ + logger.info("RepositoryAudit.invoke: exiting because isActive = " + isActive); + return; + } + + // Fetch repository information from 'IntegrityMonitorProperties' + String repositoryId = + IntegrityMonitorProperties.getProperty("repository.audit.id"); + String repositoryUrl = + IntegrityMonitorProperties.getProperty("repository.audit.url"); + String repositoryUsername = + IntegrityMonitorProperties.getProperty("repository.audit.username"); + String repositoryPassword = + IntegrityMonitorProperties.getProperty("repository.audit.password"); + boolean upload = + (repositoryId != null && repositoryUrl != null + && repositoryUsername != null && repositoryPassword != null); + + // used to incrementally construct response as problems occur + // (empty = no problems) + StringBuilder response = new StringBuilder(); + + long timeoutInSeconds = DEFAULT_TIMEOUT; + String timeoutString = + IntegrityMonitorProperties.getProperty("repository.audit.timeout"); + if (timeoutString != null && !timeoutString.isEmpty()) + { + try + { + timeoutInSeconds = Long.valueOf(timeoutString); + } + catch (NumberFormatException e) + { + logger.error + ("RepositoryAudit: Invalid 'repository.audit.timeout' value: '" + + timeoutString + "'"); + response.append("Invalid 'repository.audit.timeout' value: '") + .append(timeoutString).append("'\n"); + setResponse(response.toString()); + } + } + + // artifacts to be downloaded + LinkedList<Artifact> artifacts = new LinkedList<Artifact>(); + + /* + * 1) create temporary directory + */ + Path dir = Files.createTempDirectory("auditRepo"); + logger.info("RepositoryAudit: temporary directory = " + dir); + + // nested 'pom.xml' file and 'repo' directory + Path pom = dir.resolve("pom.xml"); + Path repo = dir.resolve("repo"); + + /* + * 2) Create test file, and upload to repository + * (only if repository information is specified) + */ + String groupId = null; + String artifactId = null; + String version = null; + if (upload) + { + groupId = "org.openecomp.policy.audit"; + artifactId = "repository-audit"; + version = "0." + System.currentTimeMillis(); + + if (repositoryUrl.toLowerCase().contains("snapshot")) + { + // use SNAPSHOT version + version += "-SNAPSHOT"; + } + + // create text file to write + FileOutputStream fos = + new FileOutputStream(dir.resolve("repository-audit.txt").toFile()); + try + { + fos.write(version.getBytes()); + } + finally + { + fos.close(); + } + + // try to install file in repository + if (runProcess + (timeoutInSeconds, dir.toFile(), null, + "mvn", "deploy:deploy-file", + "-DrepositoryId=" + repositoryId, + "-Durl=" + repositoryUrl, + "-Dfile=repository-audit.txt", + "-DgroupId=" + groupId, + "-DartifactId=" + artifactId, + "-Dversion=" + version, + "-Dpackaging=txt", + "-DgeneratePom=false") != 0) + { + logger.error + ("RepositoryAudit: 'mvn deploy:deploy-file' failed"); + response.append("'mvn deploy:deploy-file' failed\n"); + setResponse(response.toString()); + } + else + { + logger.info + ("RepositoryAudit: 'mvn deploy:deploy-file succeeded"); + + // we also want to include this new artifact in the download + // test (steps 3 and 4) + artifacts.add(new Artifact(groupId, artifactId, version, "txt")); + } + } + + /* + * 3) create 'pom.xml' file in temporary directory + */ + artifacts.add(new Artifact("org.apache.maven/maven-embedder/3.2.2")); + + StringBuilder sb = new StringBuilder(); + sb.append + ("<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + + " xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">\n" + + "\n" + + " <modelVersion>4.0.0</modelVersion>\n" + + " <groupId>empty</groupId>\n" + + " <artifactId>empty</artifactId>\n" + + " <version>1.0-SNAPSHOT</version>\n" + + " <packaging>pom</packaging>\n" + + "\n" + + " <build>\n" + + " <plugins>\n" + + " <plugin>\n" + + " <groupId>org.apache.maven.plugins</groupId>\n" + + " <artifactId>maven-dependency-plugin</artifactId>\n" + + " <version>2.10</version>\n" + + " <executions>\n" + + " <execution>\n" + + " <id>copy</id>\n" + + " <goals>\n" + + " <goal>copy</goal>\n" + + " </goals>\n" + + " <configuration>\n" + + " <localRepositoryDirectory>") + .append(repo) + .append("</localRepositoryDirectory>\n") + .append(" <artifactItems>\n"); + for (Artifact artifact : artifacts) + { + // each artifact results in an 'artifactItem' element + sb.append + (" <artifactItem>\n" + + " <groupId>") + .append(artifact.groupId) + .append + ("</groupId>\n" + + " <artifactId>") + .append(artifact.artifactId) + .append + ("</artifactId>\n" + + " <version>") + .append(artifact.version) + .append + ("</version>\n" + + " <type>") + .append(artifact.type) + .append + ("</type>\n" + + " </artifactItem>\n"); + } + sb.append + (" </artifactItems>\n" + + " </configuration>\n" + + " </execution>\n" + + " </executions>\n" + + " </plugin>\n" + + " </plugins>\n" + + " </build>\n" + + "</project>\n"); + FileOutputStream fos = new FileOutputStream(pom.toFile()); + try + { + fos.write(sb.toString().getBytes()); + } + finally + { + fos.close(); + } + + /* + * 4) Invoke external 'mvn' process to do the downloads + */ + + // output file = ${dir}/out (this supports step '4a') + File output = dir.resolve("out").toFile(); + + // invoke process, and wait for response + int rval = runProcess + (timeoutInSeconds, dir.toFile(), output, "mvn", "compile"); + logger.info("RepositoryAudit: 'mvn' return value = " + rval); + if (rval != 0) + { + logger.error + ("RepositoryAudit: 'mvn compile' invocation failed"); + response.append("'mvn compile' invocation failed\n"); + setResponse(response.toString()); + } + + /* + * 4a) Check attempted and successful downloads from output file + * Note: at present, this step just generates log messages, + * but doesn't do any verification. + */ + if (rval == 0) + { + // place output in 'fileContents' (replacing the Return characters + // with Newline) + byte[] outputData = new byte[(int)output.length()]; + FileInputStream fis = new FileInputStream(output); + fis.read(outputData); + String fileContents = new String(outputData).replace('\r','\n'); + fis.close(); + + // generate log messages from 'Downloading' and 'Downloaded' + // messages within the 'mvn' output + int index = 0; + while ((index = fileContents.indexOf("\nDown", index)) > 0) + { + index += 5; + if (fileContents.regionMatches(index, "loading: ", 0, 9)) + { + index += 9; + int endIndex = fileContents.indexOf('\n', index); + logger.info + ("RepositoryAudit: Attempted download: '" + + fileContents.substring(index, endIndex) + "'"); + index = endIndex; + } + else if (fileContents.regionMatches(index, "loaded: ", 0, 8)) + { + index += 8; + int endIndex = fileContents.indexOf(' ', index); + logger.info + ("RepositoryAudit: Successful download: '" + + fileContents.substring(index, endIndex) + "'"); + index = endIndex; + } + } + } + + /* + * 5) Check the contents of the directory to make sure the downloads + * were successful + */ + for (Artifact artifact : artifacts) + { + if (repo.resolve(artifact.groupId.replace('.','/')) + .resolve(artifact.artifactId) + .resolve(artifact.version) + .resolve(artifact.artifactId + "-" + artifact.version + "." + + artifact.type).toFile().exists()) + { + // artifact exists, as expected + logger.info("RepositoryAudit: " + + artifact.toString() + ": exists"); + } + else + { + // Audit ERROR: artifact download failed for some reason + logger.error("RepositoryAudit: " + + artifact.toString() + ": does not exist"); + response.append("Failed to download artifact: ") + .append(artifact).append('\n'); + setResponse(response.toString()); + } + } + + /* + * 6) Use 'curl' to delete the uploaded test file + * (only if repository information is specified) + */ + if (upload) + { + if (runProcess + (timeoutInSeconds, dir.toFile(), null, + "curl", + "--request", "DELETE", + "--user", repositoryUsername + ":" + repositoryPassword, + (repositoryUrl + "/" + groupId.replace('.', '/') + "/" + + artifactId + "/" + version)) + != 0) + { + logger.error + ("RepositoryAudit: delete of uploaded artifact failed"); + response.append("delete of uploaded artifact failed\n"); + setResponse(response.toString()); + } + else + { + logger.info + ("RepositoryAudit: delete of uploaded artifact succeeded"); + artifacts.add(new Artifact(groupId, artifactId, version, "txt")); + } + } + + /* + * 7) Remove the temporary directory + */ + Files.walkFileTree + (dir, + new SimpleFileVisitor<Path>() + { + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) + { + // logger.info("RepositoryAudit: Delete " + file); + file.toFile().delete(); + return(FileVisitResult.CONTINUE); + } + + public FileVisitResult postVisitDirectory(Path file, IOException e) + throws IOException + { + if (e == null) + { + // logger.info("RepositoryAudit: Delete " + file); + file.toFile().delete(); + return(FileVisitResult.CONTINUE); + } + else + { + throw(e); + } + } + }); + } + + /** + * Run a process, and wait for the response + * + * @param timeoutInSeconds the number of seconds to wait for the + * process to terminate + * @param directory the execution directory of the process + * (null = current directory) + * @param stdout the file to contain the standard output + * (null = discard standard output) + * @param command command and arguments + * @return the return value of the process + * @throws IOException, InterruptedException + */ + static int runProcess(long timeoutInSeconds, + File directory, File stdout, String... command) + throws IOException, InterruptedException + { + ProcessBuilder pb = new ProcessBuilder(command); + if (directory != null) + { + pb.directory(directory); + } + if (stdout != null) + { + pb.redirectOutput(stdout); + } + + Process process = pb.start(); + if (process.waitFor(timeoutInSeconds, TimeUnit.SECONDS)) + { + // process terminated before the timeout + return(process.exitValue()); + } + + // process timed out -- kill it, and return -1 + process.destroyForcibly(); + return(-1); + } + + /* ============================================================ */ + + /** + * An instance of this class exists for each artifact that we are trying + * to download. + */ + static class Artifact + { + String groupId, artifactId, version, type; + + /** + * Constructor - populate the 'Artifact' instance + * + * @param groupId groupId of artifact + * @param artifactId artifactId of artifact + * @param version version of artifact + * @param type type of the artifact (e.g. "jar") + */ + Artifact(String groupId, String artifactId, String version, String type) + { + this.groupId = groupId; + this.artifactId = artifactId; + this.version = version; + this.type = type; + } + + /** + * Constructor - populate an 'Artifact' instance + * + * @param artifact a string of the form: + * "<groupId>/<artifactId>/<version>[/<type>]" + * @throws IllegalArgumentException if 'artifact' has the incorrect format + */ + Artifact(String artifact) + { + String[] segments = artifact.split("/"); + if (segments.length != 4 && segments.length != 3) + { + throw(new IllegalArgumentException("groupId/artifactId/version/type")); + } + groupId = segments[0]; + artifactId = segments[1]; + version = segments[2]; + type = (segments.length == 4 ? segments[3] : "jar"); + } + + /** + * @return the artifact id in the form: + * "<groupId>/<artifactId>/<version>/<type>" + */ + public String toString() + { + return(groupId + "/" + artifactId + "/" + version + "/" + type); + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/im/PMStandbyStateChangeNotifier.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/im/PMStandbyStateChangeNotifier.java new file mode 100644 index 00000000..46e5a5e6 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/im/PMStandbyStateChangeNotifier.java @@ -0,0 +1,280 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.im; + +/* + * Per MultiSite_v1-10.ppt: + * + * Extends the StateChangeNotifier class and overwrites the abstract handleStateChange() method to get state changes + * and do the following: + * + * When the Standby Status changes (from providingservice) to hotstandby or coldstandby, + * the Active/Standby selection algorithm must stand down if the PDP-D is currently the lead/active node + * and allow another PDP-D to take over. It must also call lock on all engines in the engine management. + * + * When the Standby Status changes from (hotstandby) to coldstandby, the Active/Standby algorithm must NOT assume + * the active/lead role. + * + * When the Standby Status changes (from coldstandby or providingservice) to hotstandby, + * the Active/Standby algorithm may assume the active/lead role if the active/lead fails. + * + * When the Standby Status changes to providingservice (from hotstandby or coldstandby) call unlock on all + * engines in the engine management layer. + */ +import java.util.Date; +import java.util.Timer; +import java.util.TimerTask; + +import org.openecomp.policy.common.im.StateChangeNotifier; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.drools.controller.internal.MavenDroolsController; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.drools.event.comm.TopicEndpoint; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.drools.persistence.DroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.PersistenceFeature; +import org.openecomp.policy.drools.system.PolicyEngine; + +/* + * Some background: + * + * Originally, there was a "StandbyStateChangeNotifier" that belonged to policy-core, and this class's handleStateChange() method + * used to take care of invoking conn.standDownPdp(). But testing revealed that when a state change to hot standby occurred + * from a demote() operation, first the PMStandbyStateChangeNotifier.handleStateChange() method would be invoked and then the + * StandbyStateChangeNotifier.handleStateChange() method would be invoked, and this ordering was creating the following problem: + * + * When PMStandbyStateChangeNotifier.handleStateChange() was invoked it would take a long time to finish, because it would result + * in SingleThreadedUebTopicSource.stop() being invoked, which can potentially do a 5 second sleep for each controller being stopped. + * Meanwhile, as these controller stoppages and their associated sleeps were occurring, the election handler would discover the + * demoted PDP in hotstandby (but still designated!) and promote it, resulting in the standbyStatus going from hotstandby + * to providingservice. So then, by the time that PMStandbyStateChangeNotifier.handleStateChange() finished its work and + * StandbyStateChangeNotifier.handleStateChange() started executing, the standbyStatus was no longer hotstandby (as effected by + * the demote), but providingservice (as reset by the election handling logic) and conn.standDownPdp() would not get called! + * + * To fix this bug, we consolidated StandbyStateChangeNotifier and PMStandbyStateChangeNotifier, with the standDownPdp() always + * being invoked prior to the TopicEndpoint.manager.lock(). In this way, when the election handling logic is invoked + * during the controller stoppages, the PDP is in hotstandby and the standdown occurs. + * + */ +public class PMStandbyStateChangeNotifier extends StateChangeNotifier { + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(PMStandbyStateChangeNotifier.class); + private Timer delayActivateTimer; + private int pdpUpdateInterval; + private boolean isWaitingForActivation; + private long startTimeWaitingForActivationMs; + private long waitInterval; + private boolean isNowActivating; + + public PMStandbyStateChangeNotifier(){ + pdpUpdateInterval = Integer.parseInt(IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_UPDATE_INTERVAL)); + isWaitingForActivation = false; + startTimeWaitingForActivationMs = new Date().getTime(); + //delay the activate so the DesignatedWaiter can run twice - give it an extra 2 seconds + waitInterval = 2*pdpUpdateInterval + 2000; + isNowActivating=false; + } + + @Override + public void handleStateChange() { + /* + * A note on synchronization: This method is not synchronized because the caller, stateManagememt, + * has synchronize all of its methods. Only one stateManagement operation can occur at a time. Thus, + * only one handleStateChange() call will ever be made at a time. + */ + + logger.info("handleStateChange: Entering, message='" + + super.getMessage() + "', standbyStatus='" + + super.getStateManagement().getStandbyStatus() + "'"); + + String standbyStatus = super.getStateManagement().getStandbyStatus(); + String pdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + DroolsPdpsConnector conn = PersistenceFeature + .getDroolsPdpsConnector("ncompPU"); + + if (standbyStatus == null) { + logger.info("handleStateChange: standbyStatus is null; standing down PDP=" + pdpId); + isWaitingForActivation = false; + try{ + try{ + logger.info("handleStateChange: null: cancelling delayActivationTimer."); + delayActivateTimer.cancel(); + }catch(Exception e){ + logger.info("handleStateChange: null no delayActivationTimer existed."); + //If you end of here, there was no active timer + } + conn.standDownPdp(pdpId); + //Only want to lock the endpoints, not the controllers. + PolicyEngine.manager.deactivate(); + }catch(Exception e){ + logger.warn("handleStateChange: standbyStatus == null caught exception: " + e); + e.printStackTrace(); + } + + } else if (standbyStatus.equals("null")) { + logger.info("handleStateChange: standbyStatus equals 'null'; standing down PDP=" + pdpId); + isWaitingForActivation = false; + try{ + try{ + logger.info("handleStateChange: NULL_VALUE: cancelling delayActivationTimer."); + delayActivateTimer.cancel(); + }catch(Exception e){ + logger.info("handleStateChange: NULL_VALUE no delayActivationTimer existed."); + //If you end of here, there was no active timer + } + conn.standDownPdp(pdpId); + //Only want to lock the endpoints, not the controllers. + PolicyEngine.manager.deactivate(); + }catch(Exception e){ + logger.warn("handleStateChange: standbyStatus == \"null\" caught exception: " + e); + e.printStackTrace(); + } + } else if (standbyStatus.equals(StateManagement.HOT_STANDBY) || standbyStatus.equals(StateManagement.COLD_STANDBY)) { + logger.info("handleStateChange: standbyStatus=" + standbyStatus + "; standing down PDP=" + pdpId); + isWaitingForActivation = false; + try{ + try{ + logger.info("handleStateChange: HOT_STNDBY || COLD_STANDBY: cancelling delayActivationTimer."); + delayActivateTimer.cancel(); + }catch(Exception e){ + logger.info("handleStateChange: HOT_STANDBY || COLD_STANDBY no delayActivationTimer existed."); + //If you end of here, there was no active timer + } + //Only want to lock the endpoints, not the controllers. + conn.standDownPdp(pdpId); + PolicyEngine.manager.deactivate(); + }catch(Exception e){ + logger.warn("handleStateChange: standbyStatus == " + standbyStatus + " caught exception: " + e); + e.printStackTrace(); + } + + } else if (standbyStatus.equals(StateManagement.PROVIDING_SERVICE)) { + try{ + //UnLock all the endpoints + logger.info("handleStateChange: standbyStatus=" + standbyStatus + "; controllers must be unlocked."); + /* + * Only endpoints should be unlocked. Controllers have not been locked. + * Because, sometimes, it is possible for more than one PDP-D to become active (race conditions) + * we need to delay the activation of the topic endpoint interfaces to give the election algorithm + * time to resolve the conflict. + */ + logger.info("handleStateChange: PROVIDING_SERVICE isWaitingForActivation= " +isWaitingForActivation); + //Delay activation for 2*pdpUpdateInterval+2000 ms in case of an election handler conflict. + //You could have multiple election handlers thinking they can take over. + + // First let's check that the timer has not died + if(isWaitingForActivation){ + logger.info("handleStateChange: PROVIDING_SERVICE isWaitingForActivation = " + isWaitingForActivation); + long now = new Date().getTime(); + long waitTimeMs = now - startTimeWaitingForActivationMs; + if(waitTimeMs > 3*waitInterval){ + logger.info("handleStateChange: PROVIDING_SERVICE looks like the activation wait timer may be hung," + + " waitTimeMs = " + waitTimeMs + " and allowable waitInterval = " + waitInterval + + " Checking whether it is currently in activation. isNowActivating = " + isNowActivating); + //Now check that it is not currently executing an activation + if(!isNowActivating){ + logger.info("handleStateChange: PROVIDING_SERVICE looks like the activation wait timer died"); + // This will assure the timer is cancelled and rescheduled. + isWaitingForActivation = false; + } + } + + } + + if(!isWaitingForActivation){ + try{ + //Just in case there is an old timer hanging around + logger.info("handleStateChange: PROVIDING_SERVICE cancelling delayActivationTimer."); + delayActivateTimer.cancel(); + }catch(Exception e){ + logger.info("handleStateChange: PROVIDING_SERVICE no delayActivationTimer existed."); + //If you end of here, there was no active timer + } + delayActivateTimer = new Timer(); + //delay the activate so the DesignatedWaiter can run twice + delayActivateTimer.schedule(new DelayActivateClass(), waitInterval); + isWaitingForActivation = true; + startTimeWaitingForActivationMs = new Date().getTime(); + logger.info("handleStateChange: PROVIDING_SERVICE scheduling delayActivationTimer in " + waitInterval + " ms"); + }else{ + logger.info("handleStateChange: PROVIDING_SERVICE delayActivationTimer is waiting for activation."); + } + + }catch(Exception e){ + logger.warn("handleStateChange: PROVIDING_SERVICE standbyStatus == providingservice caught exception: " + e); + e.printStackTrace(); + } + + } else { + logger.error("handleStateChange: Unsupported standbyStatus=" + standbyStatus + "; standing down PDP=" + pdpId); + //Only want to lock the endpoints, not the controllers. + isWaitingForActivation = false; + try{ + try{ + logger.info("handleStateChange: unsupported standbystatus: cancelling delayActivationTimer."); + delayActivateTimer.cancel(); + }catch(Exception e){ + logger.info("handleStateChange: unsupported standbystatus: no delayActivationTimer existed."); + //If you end of here, there was no active timer + } + conn.standDownPdp(pdpId); + PolicyEngine.manager.deactivate(); + }catch(Exception e){ + logger.warn("handleStateChange: Unsupported standbyStatus == " + standbyStatus + "caught exception: " + e); + e.printStackTrace(); + } + } + + //if (logger.isDebugEnabled()) { + logger.info("handleStateChange: Exiting"); + //} + } + + private class DelayActivateClass extends TimerTask{ + + private Object delayActivateLock = new Object(); + + + @Override + public void run() { + isNowActivating = true; + try{ + logger.info("DelayActivateClass.run: entry"); + synchronized(delayActivateLock){ + PolicyEngine.manager.activate(); + // We want to set this to false here because the activate call can take a while + isWaitingForActivation = false; + isNowActivating = false; + } + logger.info("DelayActivateClass.run.exit"); + }catch(Exception e){ + isWaitingForActivation = false; + isNowActivating = false; + logger.warn("DelayActivateClass.run: caught an unexpected exception " + + "calling PolicyEngine.manager.activate: " + e); + System.out.println(new Date() + " DelayActivateClass.run: caught an unexpected exception"); + e.printStackTrace(); + } + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdp.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdp.java new file mode 100644 index 00000000..11cc8788 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdp.java @@ -0,0 +1,45 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Date; +import java.util.List; + +public interface DroolsPdp { + + public List<DroolsSessionEntity> getSessions(); + public void addSession(DroolsSession session); + public void removeSession(DroolsSession session); + public String getPdpId(); + public boolean isDesignated(); + public int getPriority(); + public Date getUpdatedDate(); + public void setDesignated(boolean isDesignated); + public void setUpdatedDate(Date updatedDate); + public int comparePriority(DroolsPdp other); + public int comparePriority(DroolsPdp other,String previousSite); + public DroolsSession getSession(String sessionName); + public void setSessionId(String sessionName, long sessionId); + public String getSiteName(); + public void setSiteName(String siteName); + public Date getDesignatedDate(); + public void setDesignatedDate(Date designatedDate); +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpEntity.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpEntity.java new file mode 100644 index 00000000..87b58723 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpEntity.java @@ -0,0 +1,171 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.OneToMany; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; + +import org.openecomp.policy.drools.persistence.DroolsPdpObject; + +@Entity +//@Table(name="DroolsPdpEntity") + +@NamedQueries({ + @NamedQuery(name="DroolsPdpEntity.findAll", query="SELECT e FROM DroolsPdpEntity e "), + @NamedQuery(name="DroolsPdpEntity.deleteAll", query="DELETE FROM DroolsPdpEntity WHERE 1=1") +}) +public class DroolsPdpEntity extends DroolsPdpObject implements Serializable{ + + private static final long serialVersionUID = 1L; + + @Id + @Column(name="pdpId", nullable=false) + private String pdpId="-1"; + + @Column(name="designated", nullable=false) + private boolean designated=false; + + @Column(name="priority", nullable=false) + private int priority=0; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="updatedDate", nullable=false) + private Date updatedDate; + + @Temporal(TemporalType.TIMESTAMP) + @Column(name="designatedDate",nullable=false) + private Date designatedDate; + + @Column(name="site", nullable=true, length = 50) + private String site; + + + @OneToMany(mappedBy="pdpEntity") + //@OneToMany + //@JoinColumn(name="pdpId", referencedColumnName="pdpId") + //@JoinColumn(name="pdpId") + private List<DroolsSessionEntity> sessions; + + + public DroolsPdpEntity(){ + updatedDate = new Date(); + //When this is translated to a TimeStamp in MySQL, it assumes the date is relative + //to the local timezone. So, a value of Date(0) is actually Dec 31 18:00:00 CST 1969 + //which is an invalid value for the MySql TimeStamp + designatedDate = new Date(864000000); + } + + @Override + public String getPdpId() { + return this.pdpId; + } + + public void setPdpId(String pdpId) { + this.pdpId = pdpId; + } + + @Override + public boolean isDesignated() { + return this.designated; + } + + @Override + public int getPriority() { + return this.priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public Date getUpdatedDate() { + return this.updatedDate; + } + + @Override + public void setDesignated(boolean isDesignated) { + this.designated=isDesignated; + } + + @Override + public void setUpdatedDate(Date updatedDate) { + this.updatedDate=updatedDate; + } + + + public List<DroolsSessionEntity> getSessions() { + return sessions; + } + + public void addSession(DroolsSessionEntity session) { + sessions.add(session); + } + + public void removeSession(DroolsSessionEntity session) { + sessions.remove(session); + + } + + @Override + public void addSession(DroolsSession session) { + // TODO Auto-generated method stub + + } + + @Override + public void removeSession(DroolsSession session) { + // TODO Auto-generated method stub + + } + + @Override + public String getSiteName() { + return site; + } + + @Override + public void setSiteName(String siteName) { + site = siteName; + + } + + @Override + public Date getDesignatedDate() { + return designatedDate; + } + + @Override + public void setDesignatedDate(Date designatedDate) { + this.designatedDate = designatedDate; + } + +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpImpl.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpImpl.java new file mode 100644 index 00000000..e0f5d816 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpImpl.java @@ -0,0 +1,115 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + + +public class DroolsPdpImpl extends DroolsPdpObject { + + private boolean designated; + private int priority; + private Date updatedDate; + private Date designatedDate; + private String pdpId; + private String site; + private List<DroolsSessionEntity> sessions; + + public DroolsPdpImpl(String pdpId, boolean designated, int priority, Date updatedDate){ + this.pdpId = pdpId; + this.designated = designated; + this.priority = priority; + this.updatedDate = updatedDate; + //When this is translated to a TimeStamp in MySQL, it assumes the date is relative + //to the local timezone. So, a value of Date(0) is actually Dec 31 18:00:00 CST 1969 + //which is an invalid value for the MySql TimeStamp + this.designatedDate = new Date(864000000); + sessions = new LinkedList<DroolsSessionEntity>(); + + } + @Override + public boolean isDesignated() { + + return designated; + } + + @Override + public int getPriority() { + return priority; + } + @Override + public void setUpdatedDate(Date date){ + this.updatedDate = date; + } + @Override + public Date getUpdatedDate() { + return updatedDate; + } + + @Override + public String getPdpId() { + return pdpId; + } + @Override + public void setDesignated(boolean isDesignated) { + this.designated = isDesignated; + + } + + + @Override + public List<DroolsSessionEntity> getSessions() { + // TODO Auto-generated method stub + return sessions; + } + @Override + public void addSession(DroolsSession session) { + + + } + @Override + public void removeSession(DroolsSession session) { + // TODO Auto-generated method stub + + } + @Override + public String getSiteName() { + return site; + } + @Override + public void setSiteName(String siteName) { + this.site = siteName; + + } + @Override + public Date getDesignatedDate() { + return designatedDate; + } + @Override + public void setDesignatedDate(Date designatedDate) { + this.designatedDate = designatedDate; + + } + + +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpObject.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpObject.java new file mode 100644 index 00000000..7a219148 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpObject.java @@ -0,0 +1,97 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + + +public abstract class DroolsPdpObject implements DroolsPdp{ + + @Override + public boolean equals(Object other){ + if(other instanceof DroolsPdp){ + return this.getPdpId().equals(((DroolsPdp)other).getPdpId()); + }else{ + return false; + } + } + private int nullSafeCompare(Comparable one, Comparable two){ + if(one != null && two != null){ + return one.compareTo(two); + } + if(one == null && two != null){ + return -1; + } + if(one != null && two == null){ + return 1; + } + return 0; + } + @Override + public int comparePriority(DroolsPdp other){ + if(nullSafeCompare(this.getSiteName(),other.getSiteName()) == 0){ + if(this.getPriority() != other.getPriority()){ + return this.getPriority() - other.getPriority(); + } + return this.getPdpId().compareTo(other.getPdpId()); + } else { + return nullSafeCompare(this.getSiteName(),other.getSiteName()); + } + } + @Override + public int comparePriority(DroolsPdp other, String previousSite){ + if(previousSite == null || previousSite.equals("")){ + return comparePriority(other); + } + if(nullSafeCompare(this.getSiteName(),other.getSiteName()) == 0){ + if(this.getPriority() != other.getPriority()){ + return this.getPriority() - other.getPriority(); + } + return this.getPdpId().compareTo(other.getPdpId()); + } else { + return nullSafeCompare(this.getSiteName(),other.getSiteName()); + } + } + @Override + public DroolsSession getSession(String sessionName){ + for(DroolsSession session : getSessions()){ + if(session.getSessionName().equals(sessionName)){ + return session; + } + } + return null; + } + @Override + public void setSessionId(String sessionName, long sessionId){ + for(DroolsSession session : getSessions()){ + if(session.getSessionName().equals(sessionName)){ + session.setSessionId(sessionId); + return; + } + } + DroolsSessionEntity newSession = new DroolsSessionEntity(); + DroolsPdpEntity pdpEntityWithPdpId = new DroolsPdpEntity(); + pdpEntityWithPdpId.setPdpId(this.getPdpId()); + newSession.setPdpEntity(pdpEntityWithPdpId); + newSession.setPdpId(getPdpId()); + newSession.setSessionName(sessionName); + newSession.setSessionId(sessionId); + getSessions().add(newSession); + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsConnector.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsConnector.java new file mode 100644 index 00000000..fa75c2e7 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsConnector.java @@ -0,0 +1,67 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Collection; + +public interface DroolsPdpsConnector { + + + //return a list of PDPs, NOT including this PDP + public Collection<DroolsPdp> getDroolsPdps(); + + public void update(DroolsPdp pdp); + + //determines if the DroolsPdp parameter is considered "current" or expired (has it been too long since the Pdp sent an update) + public boolean isPdpCurrent(DroolsPdp pdp); + + // Updates DESIGNATED boolean in PDP record. + public void setDesignated(DroolsPdp pdp, boolean designated); + + // Marks droolspdpentity.DESIGNATED=false, so another PDP-D will go active. + public void standDownPdp(String pdpId); + + // This is used in a JUnit test environment to manually + // insert a PDP + public void insertPdp(DroolsPdp pdp); + + // This is used in a JUnit test environment to manually + // delete a PDP + public void deletePdp(String pdpId); + + // This is used in a JUnit test environment to manually + // clear the droolspdpentity table. + public void deleteAllPdps(); + + // This is used in a JUnit test environment to manually + // clear the droolspdpentity table. + public void deleteAllSessions(); + + // This is used in a JUnit test environment to manually + // get a PDP + public DroolsPdpEntity getPdp(String pdpId); + + // Used by DroolsPdpsElectionHandler to determine if the currently designated + // PDP has failed. + public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps); + + +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsElectionHandler.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsElectionHandler.java new file mode 100644 index 00000000..82ee5d1d --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPdpsElectionHandler.java @@ -0,0 +1,948 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +import org.openecomp.policy.common.im.StandbyStatusException; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.drools.core.DroolsPDPIntegrityMonitor; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.common.logging.eelf.MessageCodes; + +public class DroolsPdpsElectionHandler implements ThreadRunningChecker { + // get an instance of logger + private final static Logger logger = FlexLogger.getLogger(DroolsPdpsElectionHandler.class); + private DroolsPdpsConnector pdpsConnector; + private Object pdpsConnectorLock = new Object(); + private Object checkUpdateWorkerLock = new Object(); + private Object checkWaitTimerLock = new Object(); + private Object designationWaiterLock = new Object(); + + /* + * Must be static, so it can be referenced by JpaDroolsPdpsConnector, + * without requiring a reference to the election handler instantiation. + */ + private static DroolsPdp myPdp; + + private DesignationWaiter designationWaiter; + private Timer updateWorker; + private Timer waitTimer; + private Date updateWorkerLastRunDate; + private Date waitTimerLastRunDate; + private int pdpCheckInterval; + private int pdpUpdateInterval; + private volatile boolean isDesignated; + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor; + StateManagement stateManagement; + + public DroolsPdpsElectionHandler(DroolsPdpsConnector pdps, DroolsPdp myPdp, DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor){ + this.pdpsConnector = pdps; + DroolsPdpsElectionHandler.myPdp = myPdp; + this.isDesignated = false; + this.droolsPdpIntegrityMonitor = droolsPdpIntegrityMonitor; + this.stateManagement = droolsPdpIntegrityMonitor.getStateManager(); + pdpCheckInterval = 3000; + try{ + pdpCheckInterval = Integer.parseInt(IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_CHECK_INVERVAL)); + }catch(Exception e){ + logger.error + //System.out.println + (MessageCodes.EXCEPTION_ERROR ,e, "Could not get pdpCheckInterval property. Using default"); + } + pdpUpdateInterval = 2000; + try{ + pdpUpdateInterval = Integer.parseInt(IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_UPDATE_INTERVAL)); + }catch(Exception e){ + logger.error + //System.out.println + (MessageCodes.EXCEPTION_ERROR, e, "Could not get pdpUpdateInterval property. Using default"); + } + + Date now = new Date(); + + // Retrieve the ms since the epoch + long nowMs = now.getTime(); + + // Create the timer which will update the updateDate in DroolsPdpEntity table. + // This is the heartbeat + updateWorker = new Timer(); + + // Schedule the heartbeat to start in 100 ms and run at pdpCheckInterval ms thereafter + updateWorker.scheduleAtFixedRate(new TimerUpdateClass(), 100, pdpCheckInterval); + updateWorkerLastRunDate = new Date(nowMs + 100); + + // Create the timer which will run the election algorithm + waitTimer = new Timer(); + + // Schedule it to start in startMs ms (so it will run after the updateWorker and run at pdpUpdateInterval ms thereafter + long startMs = getDWaiterStartMs(); + designationWaiter = new DesignationWaiter(); + waitTimer.scheduleAtFixedRate(designationWaiter, startMs, pdpUpdateInterval); + waitTimerLastRunDate = new Date(nowMs + startMs); + } + + public List<DroolsSessionEntity> waitForDesignation(){ + while(isDesignated == false){ + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + return null; + } + } + return designationWaiter.getSessions(); + + } + public List<DroolsSessionEntity> getSessions(){ + return designationWaiter.getSessions(); + } + public void updateMyPdp(){ + synchronized(pdpsConnectorLock){ + myPdp.setUpdatedDate(new Date()); + pdpsConnector.update(myPdp); + } + } + + /* + * When the JpaDroolsPdpsConnector.standDown() method is invoked, it needs + * access to myPdp, so it can keep its designation status in sync with the + * DB. + */ + public static void setMyPdpDesignated(boolean designated) { + logger.debug + //System.out.println + ("setMyPdpDesignated: designated=" + designated); + myPdp.setDesignated(designated); + } + + private class DesignationWaiter extends TimerTask { + // get an instance of logger + private Logger logger = FlexLogger.getLogger(DesignationWaiter.class); + private List<DroolsSessionEntity> sessions = null; + + public List<DroolsSessionEntity> getSessions(){ + if(sessions != null){ + return sessions; + } + return new LinkedList<DroolsSessionEntity>(); + } + public void run() { + try{ + logger.debug + //System.out.println + ("DesignatedWaiter.run: Entering"); + + // just here initially so code still works + if (pdpsConnector == null) { + waitTimerLastRunDate = new Date(); + logger.info("DesignatedWaiter.run (pdpsConnector==null) waitTimerLastRunDate = " + waitTimerLastRunDate); + + return; + } + + synchronized (designationWaiterLock) { + + logger.debug + //System.out.println + ("DesignatedWaiter.run: Entering synchronized block"); + + checkUpdateWorkerTimer(); + + //It is possible that multiple PDPs are designated lead. So, we will make a list of all designated + //PDPs and then decide which one really should be designated at the end. + ArrayList<DroolsPdp> listOfDesignated = new ArrayList<DroolsPdp>(); + + Collection<DroolsPdp> pdps = pdpsConnector.getDroolsPdps(); + DroolsPdp designatedPdp = null; + DroolsPdp lowestPriorityPdp = null; + + logger.debug + //System.out.println + ("DesignatedWaiter.run: pdps.size=" + + pdps.size()); + + //This is only true if all designated PDPs have failed + boolean designatedPdpHasFailed = pdpsConnector.hasDesignatedPdpFailed(pdps); + logger.debug + //System.out.println + ("DesignatedWaiter.run: designatedPdpHasFailed=" + + designatedPdpHasFailed); + for (DroolsPdp pdp : pdps) { + logger.debug + //System.out.println + ("DesignatedWaiter.run: evaluating pdp ID: " + pdp.getPdpId()); + + /* + * Note: side effect of isPdpCurrent is that any stale but + * designated PDPs will be marked as un-designated. + */ + boolean isCurrent = pdpsConnector.isPdpCurrent(pdp); + + /* + * We can't use stateManagement.getStandbyStatus() here, because + * we need the standbyStatus, not for this PDP, but for the PDP + * being processed by this loop iteration. + */ + String standbyStatus = stateManagement.getStandbyStatus(pdp.getPdpId()); + if(standbyStatus==null){ + // Treat this case as a cold standby -- if we + // abort here, no sessions will be created in a + // single-node test environment. + standbyStatus = StateManagement.COLD_STANDBY; + } + + logger.debug + //System.out.println + ("DesignatedWaiter.run: PDP=" + + pdp.getPdpId() + ", isCurrent=" + isCurrent); + + /* + * There are 4 combinations of isDesignated and isCurrent. We will examine each one in-turn + * and evaluate the each pdp in the list of pdps against each combination. + * + * This is the first combination of isDesignated and isCurrent + */ + if (pdp.isDesignated() && isCurrent) { + //It is current, but it could have a standbystatus=coldstandby / hotstandby + //If so, we need to stand it down and demote it + if(!standbyStatus.equals(StateManagement.PROVIDING_SERVICE)){ + if(pdp.getPdpId().equals(myPdp.getPdpId())){ + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp " + myPdp.getPdpId() + " is current and designated, " + + "butstandbystatus is not providingservice. " + + " Executing stateManagement.demote()" + "\n\n"); + // So, we must demote it + try { + //Keep the order like this. StateManagement is last since it triggers controller shutdown + //This will change isDesignated and it can enter another if(combination) below + pdpsConnector.standDownPdp(pdp.getPdpId()); + myPdp.setDesignated(false); + isDesignated = false; + if(!(standbyStatus.equals(StateManagement.HOT_STANDBY) || + standbyStatus.equals(StateManagement.COLD_STANDBY))){ + /* + * Only demote it if it appears it has not already been demoted. Don't worry + * about synching with the topic endpoint states. That is done by the + * refreshStateAudit + */ + stateManagement.demote(); + } + //update the standbystatus to check in a later combination of isDesignated and isCurrent + standbyStatus=stateManagement.getStandbyStatus(pdp.getPdpId()); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " Caught Exception attempting to demote myPdp'" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.demote()"); + e.printStackTrace(); + } + }else{ + // Don't demote a remote PDP that is current. It should catch itself + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp " + myPdp.getPdpId() + " is current and designated, " + + "but standbystatus is not providingservice. " + + " Cannot execute stateManagement.demote() since it it is not myPdp\n\n"); + } + + }else{ + // If we get here, it is ok to be on the list + logger.debug + //System.out.println + ("DesignatedWaiter.run: PDP=" + + pdp.getPdpId() + + " is designated, current and " + standbyStatus +". Noting PDP as designated. standbyStatus=" + standbyStatus); + listOfDesignated.add(pdp); + } + + + } + + + /* + * The second combination of isDesignated and isCurrent + * + * PDP is designated but not current; it has failed. So we stand it down (it doesn't matter what + * its standbyStatus is). None of these go on the list. + */ + if (pdp.isDesignated() && !isCurrent) { + logger.info + //System.out.println + ("INFO: DesignatedWaiter.run: PDP=" + + pdp.getPdpId() + + " is currently designated but is not current; it has failed. Standing down. standbyStatus=" + standbyStatus); + + /* + * Changes designated to 0 but it is still potentially providing service + * Will affect isDesignated, so, it can enter an if(combination) below + */ + pdpsConnector.standDownPdp(pdp.getPdpId()); + + //need to change standbystatus to coldstandby + if (pdp.getPdpId().equals(myPdp.getPdpId())){ + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp " + myPdp.getPdpId() + " is not Current. " + + " Executing stateManagement.disableFailed()" + "\n\n"); + // We found that myPdp is designated but not current + // So, we must cause it to disableFail + try { + myPdp.setDesignated(false); + //pdpsConnector.setDesignated(myPdp, false);//not needed? + isDesignated = false; + stateManagement.disableFailed(); + //stateManagement.demote(); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " Caught Exception attempting to disableFail myPdp'" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.disableFailed()"); + e.printStackTrace(); + } + } else { //it is a remote PDP that is failed + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: PDP " + pdp.getPdpId() + " is not Current. " + + " Executing stateManagement.disableFailed(otherResourceName)" + "\n\n"); + // We found a PDP is designated but not current + // We already called standdown(pdp) which will change designated to false + // Now we need to disableFail it to get its states in synch. The standbyStatus + // should equal coldstandby + try { + stateManagement.disableFailed(pdp.getPdpId()); + //stateManagement.demote(pdp.getPdpId()); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: for PDP" + pdp.getPdpId() + + " Caught Exception attempting to disableFail(" + pdp.getPdpId() + ")'" + + pdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.disableFailed()"); + e.printStackTrace(); + } + + } + continue; //we are not going to do anything else with this pdp + } + + /* + * The third combination of isDesignated and isCurrent + * /* + * If a PDP is not currently designated but is providing service (erroneous, but recoverable) or hot standby + * we can add it to the list of possible designated if all the designated have failed + */ + if (!pdp.isDesignated() && isCurrent){ + if(!(standbyStatus.equals(StateManagement.HOT_STANDBY) || + standbyStatus.equals(StateManagement.COLD_STANDBY))){ + logger.info("\n\nDesignatedWaiter.run: PDP " + pdp.getPdpId() + + " is NOT designated but IS current and" + + " has a standbystatus=" + standbyStatus); + // Since it is current, we assume it can adjust its own state. + // We will demote if it is myPdp + if(pdp.getPdpId().equals(myPdp.getPdpId())){ + //demote it + logger.info("DesignatedWaiter.run: PDP " + pdp.getPdpId() + " going to " + + "setDesignated = false and calling stateManagement.demote"); + try { + //Keep the order like this. StateManagement is last since it triggers controller shutdown + pdpsConnector.setDesignated(myPdp, false); + myPdp.setDesignated(false); + isDesignated = false; + //This is definitely not a redundant call. It is attempting to correct a problem + stateManagement.demote(); + //recheck the standbystatus + standbyStatus = stateManagement.getStandbyStatus(pdp.getPdpId()); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " Caught Exception attempting to demote myPdp'" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.demote()"); + e.printStackTrace(); + } + + } + } + if(standbyStatus.equals(StateManagement.HOT_STANDBY) && designatedPdpHasFailed){ + //add it to the list + logger.info + //System.out.println + ("INFO: DesignatedWaiter.run: PDP=" + pdp.getPdpId() + + " is not designated but is " + standbyStatus + " and designated PDP has failed. standbyStatus=" + + standbyStatus); + logger.info + //System.out.println + ("DesignatedWaiter.run: Designating PDP=" + pdp.getPdpId()); + listOfDesignated.add(pdp); + } + continue; //done with this one + } + + /* + * The fourth combination of isDesignated and isCurrent + * + * We are not going to put any of these on the list since it appears they have failed. + + * + */ + if(!pdp.isDesignated() && !isCurrent) { + logger.info + //System.out.println + ("INFO: DesignatedWaiter.run: PDP=" + + pdp.getPdpId() + ", designated=" + + pdp.isDesignated() + ", current=" + + isCurrent + + ", designatedPdpHasFailed=" + + designatedPdpHasFailed + + ", standbyStatus=" + standbyStatus); + if(!standbyStatus.equals(StateManagement.COLD_STANDBY)){ + //stand it down + //disableFail it + pdpsConnector.standDownPdp(pdp.getPdpId()); + if(pdp.getPdpId().equals(myPdp.getPdpId())){ + /* + * I don't actually know how this condition could happen, but if it did, we would want + * to declare it failed. + */ + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp " + myPdp.getPdpId() + " is !current and !designated, " + + " Executing stateManagement.disableFailed()" + "\n\n"); + // So, we must disableFail it + try { + //Keep the order like this. StateManagement is last since it triggers controller shutdown + myPdp.setDesignated(false); + isDesignated = false; + stateManagement.disableFailed(); + //stateManagement.demote(); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " Caught Exception attempting to disableFail myPdp'" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.disableFailed()"); + e.printStackTrace(); + } + }else{//it is remote + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp " + myPdp.getPdpId() + " is !current and !designated, " + + " Executing stateManagement.disableFailed(" + pdp.getPdpId() + ")" + "\n\n"); + // We already called standdown(pdp) which will change designated to false + // Now we need to disableFail it to get its states in sync. StandbyStatus = coldstandby + try { + stateManagement.disableFailed(pdp.getPdpId()); + //stateManagement.demote(pdp.getPdpId()); + } catch (Exception e) { + logger.error + //System.out.println + ("DesignatedWaiter.run: for PDP" + pdp.getPdpId() + + " Caught Exception attempting to disableFail(" + pdp.getPdpId() + ")'" + + pdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.disableFailed()"); + e.printStackTrace(); + } + } + } + } + + + } // end pdps loop + + /* + * We have checked the four combinations of isDesignated and isCurrent. Where appropriate, + * we added the PDPs to the potential list of designated pdps + * Check if listOfDesignated is empty, has one entry or has multiple entries + * If it has multiple designated PDPs, then we must determine if myPdp is on the list and if + * it is the lowest priority. If it is on the list and it is not the lowest + * priority, it must be demoted. Then, we must find the lowest priority + * PDP so we can get the right list of sessions + */ + //we need to give priority to pdps on the same site that is currently being used + + + //we need to figure out the last pdp that was the primary so we can get the last site name and the last session numbers + DroolsPdp mostRecentPrimary = new DroolsPdpImpl(null, true, 1, new Date(0)); + mostRecentPrimary.setSiteName(null); + for(DroolsPdp pdp : pdps){ + if(pdp.getDesignatedDate().compareTo(mostRecentPrimary.getDesignatedDate()) > 0){ + mostRecentPrimary = pdp; + } + } + + if(listOfDesignated.size() > 1){ + logger.debug + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " listOfDesignated.size(): " + listOfDesignated.size()); + DroolsPdp rejectedPdp = null; + DroolsPdp lowestPrioritySameSite = null; + DroolsPdp lowestPriorityDifferentSite = null; + for(DroolsPdp pdp : listOfDesignated){ + // We need to determine if another PDP is the lowest priority + if(nullSafeEquals(pdp.getSiteName(),mostRecentPrimary.getSiteName())){ + if(lowestPrioritySameSite == null){ + if(lowestPriorityDifferentSite != null){ + rejectedPdp = lowestPriorityDifferentSite; + } + lowestPrioritySameSite = pdp; + }else{ + if(pdp.getPdpId().equals((lowestPrioritySameSite.getPdpId()))){ + continue;//nothing to compare + } + if(pdp.comparePriority(lowestPrioritySameSite) <0){ + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp" + myPdp.getPdpId() + " listOfDesignated pdp ID: " + pdp.getPdpId() + + " has lower priority than pdp ID: " + lowestPrioritySameSite.getPdpId()); + + //we need to reject lowestPrioritySameSite + rejectedPdp = lowestPrioritySameSite; + lowestPrioritySameSite = pdp; + } else{ + //we need to reject pdp and keep lowestPrioritySameSite + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp" + myPdp.getPdpId() + " listOfDesignated pdp ID: " + pdp.getPdpId() + + " has higher priority than pdp ID: " + lowestPrioritySameSite.getPdpId()); + rejectedPdp = pdp; + } + } + } else{ + if(lowestPrioritySameSite != null){ + //if we already have a candidate for same site, we don't want to bother with different sites + rejectedPdp = pdp; + } else{ + if(lowestPriorityDifferentSite == null){ + lowestPriorityDifferentSite = pdp; + continue; + } + if(pdp.getPdpId().equals((lowestPriorityDifferentSite.getPdpId()))){ + continue;//nothing to compare + } + if(pdp.comparePriority(lowestPriorityDifferentSite) <0){ + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp" + myPdp.getPdpId() + " listOfDesignated pdp ID: " + pdp.getPdpId() + + " has lower priority than pdp ID: " + lowestPriorityDifferentSite.getPdpId()); + + //we need to reject lowestPriorityDifferentSite + rejectedPdp = lowestPriorityDifferentSite; + lowestPriorityDifferentSite = pdp; + } else{ + //we need to reject pdp and keep lowestPriorityDifferentSite + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp" + myPdp.getPdpId() + " listOfDesignated pdp ID: " + pdp.getPdpId() + + " has higher priority than pdp ID: " + lowestPriorityDifferentSite.getPdpId()); + rejectedPdp = pdp; + } + } + } + // If the rejectedPdp is myPdp, we need to stand it down and demote it. Each pdp is responsible + // for demoting itself + if(rejectedPdp != null && nullSafeEquals(rejectedPdp.getPdpId(),myPdp.getPdpId())){ + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " listOfDesignated myPdp ID: " + myPdp.getPdpId() + + " is NOT the lowest priority. Executing stateManagement.demote()" + "\n\n"); + // We found that myPdp is on the listOfDesignated and it is not the lowest priority + // So, we must demote it + try { + //Keep the order like this. StateManagement is last since it triggers controller shutdown + myPdp.setDesignated(false); + pdpsConnector.setDesignated(myPdp, false); + isDesignated = false; + String standbyStatus = stateManagement.getStandbyStatus(); + if(!(standbyStatus.equals(StateManagement.HOT_STANDBY) || + standbyStatus.equals(StateManagement.COLD_STANDBY))){ + /* + * Only call demote if it is not already in the right state. Don't worry about + * synching the lower level topic endpoint states. That is done by the + * refreshStateAudit. + */ + stateManagement.demote(); + } + } catch (Exception e) { + myPdp.setDesignated(false); + pdpsConnector.setDesignated(myPdp, false); + isDesignated = false; + logger.error + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " Caught Exception attempting to demote myPdp'" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.demote()"); + e.printStackTrace(); + } + } + } //end: for(DroolsPdp pdp : listOfDesignated) + if(lowestPrioritySameSite != null){ + lowestPriorityPdp = lowestPrioritySameSite; + } else { + lowestPriorityPdp = lowestPriorityDifferentSite; + } + //now we have a valid value for lowestPriorityPdp + logger.debug + //System.out.println + ("\n\nDesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " listOfDesignated found the LOWEST priority pdp ID: " + + lowestPriorityPdp.getPdpId() + + " It is now the designatedPpd from the perspective of myPdp ID: " + myPdp + "\n\n"); + designatedPdp = lowestPriorityPdp; + this.sessions = mostRecentPrimary.getSessions(); + + } else if(listOfDesignated.isEmpty()){ + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " listOfDesignated is: EMPTY."); + designatedPdp = null; + } else{ //only one in listOfDesignated + logger.debug + //System.out.println + ("\nDesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + " listOfDesignated has ONE entry. PDP ID: " + + listOfDesignated.get(0).getPdpId()); + designatedPdp = listOfDesignated.get(0); + this.sessions = mostRecentPrimary.getSessions(); + } + + + if (designatedPdp == null) { + logger.warn + //System.out.println + ("WARNING: DesignatedWaiter.run: No viable PDP found to be Designated. designatedPdp still null."); + // Just to be sure the parameters are correctly set + myPdp.setDesignated(false); + pdpsConnector.setDesignated(myPdp,false); + isDesignated = false; + + waitTimerLastRunDate = new Date(); + logger.info("DesignatedWaiter.run (designatedPdp == null) waitTimerLastRunDate = " + waitTimerLastRunDate); + + return; + + } else if (designatedPdp.getPdpId().equals(myPdp.getPdpId())) { + logger.debug + //System.out.println + ("DesignatedWaiter.run: designatedPdp is PDP=" + myPdp.getPdpId()); + /* + * update function expects myPdp.isDesignated to be true. + */ + try { + //Keep the order like this. StateManagement is last since it triggers controller init + myPdp.setDesignated(true); + pdpsConnector.setDesignated(myPdp, true); + isDesignated = true; + String standbyStatus = stateManagement.getStandbyStatus(); + if(!standbyStatus.equals(StateManagement.PROVIDING_SERVICE)){ + /* + * Only call promote if it is not already in the right state. Don't worry about + * synching the lower level topic endpoint states. That is done by the + * refreshStateAudit. + */ + stateManagement.promote(); + } + } catch (StandbyStatusException e) { + logger.error + //System.out.println + ("ERROR: DesignatedWaiter.run: Caught StandbyStatusException attempting to promote PDP='" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + myPdp.setDesignated(false); + pdpsConnector.setDesignated(myPdp,false); + isDesignated = false; + //If you can't promote it, demote it + try { + String standbyStatus = stateManagement.getStandbyStatus(); + if(!(standbyStatus.equals(StateManagement.HOT_STANDBY) || + standbyStatus.equals(StateManagement.COLD_STANDBY))){ + /* + * Only call demote if it is not already in the right state. Don't worry about + * synching the lower level topic endpoint states. That is done by the + * refreshStateAudit. + */ + stateManagement.demote(); + } + } catch (Exception e1) { + logger.error + //System.out.println + ("ERROR: DesignatedWaiter.run: Caught StandbyStatusException attempting to promote then demote PDP='" + + myPdp.getPdpId() + + "', message=" + + e1.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.demote()"); + e1.printStackTrace(); + } + + } catch (Exception e) { + logger.error + //System.out.println + ("ERROR: DesignatedWaiter.run: Caught Exception attempting to promote PDP='" + + myPdp.getPdpId() + + "', message=" + + e.getMessage()); + myPdp.setDesignated(false); + pdpsConnector.setDesignated(myPdp,false); + isDesignated = false; + //If you can't promote it, demote it + try { + String standbyStatus = stateManagement.getStandbyStatus(); + if(!(standbyStatus.equals(StateManagement.HOT_STANDBY) || + standbyStatus.equals(StateManagement.COLD_STANDBY))){ + /* + * Only call demote if it is not already in the right state. Don't worry about + * synching the lower level topic endpoint states. That is done by the + * refreshStateAudit. + */ + stateManagement.demote(); + } + } catch (Exception e1) { + logger.error + //System.out.println + ("ERROR: DesignatedWaiter.run: Caught StandbyStatusException attempting to promote then demote PDP='" + + myPdp.getPdpId() + + "', message=" + + e1.getMessage()); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception " + + "from stateManagement.demote()"); + e1.printStackTrace(); + } + + } + waitTimerLastRunDate = new Date(); + logger.info("DesignatedWaiter.run (designatedPdp.getPdpId().equals(myPdp.getPdpId())) waitTimerLastRunDate = " + waitTimerLastRunDate); + + return; + } + isDesignated = false; + + } // end synchronized + + logger.debug + //System.out.println + ("DesignatedWaiter.run: myPdp: " + myPdp.getPdpId() + "; Returning, isDesignated=" + isDesignated); + + Date tmpDate = new Date(); + logger.info("DesignatedWaiter.run (end of run) waitTimerLastRunDate = " + tmpDate); + + waitTimerLastRunDate = tmpDate; + + }catch(Exception e){ + logger.error("DesignatedWaiter.run caught an unexpected exception: " + e); + System.out.println(new Date() + " DesignatedWaiter.run: caught unexpected exception"); + e.printStackTrace(); + } + } // end run + } + + private class TimerUpdateClass extends TimerTask{ + + @Override + public void run() { + try{ + logger.info("TimerUpdateClass.run: entry"); + checkWaitTimer(); + synchronized(pdpsConnectorLock){ + + myPdp.setUpdatedDate(new Date()); + if(myPdp.isDesignated()){ + myPdp.setDesignatedDate(new Date()); + } + pdpsConnector.update(myPdp); + + Date tmpDate = new Date(); + logger.info("TimerUpdateClass.run: updateWorkerLastRunDate = " + tmpDate); + + updateWorkerLastRunDate = tmpDate; + } + logger.info("TimerUpdateClass.run.exit"); + }catch(Exception e){ + logger.error("TimerUpdateClass.run caught an unexpected exception: " + e); + System.out.println(new Date() + " TimerUpdateClass.run caught an unexpected exception"); + e.printStackTrace(); + } + } + } + @Override + public void checkThreadStatus() { + checkUpdateWorkerTimer(); + checkWaitTimer(); + } + + private void checkUpdateWorkerTimer(){ + synchronized(checkUpdateWorkerLock){ + try{ + logger.debug("checkUpdateWorkerTimer: entry"); + Date now = new Date(); + long nowMs = now.getTime(); + long updateWorkerMs = updateWorkerLastRunDate.getTime(); + //give it 2 second cushion + if((nowMs - updateWorkerMs) > pdpCheckInterval + 2000){ + logger.error("checkUpdateWorkerTimer: nowMs - updateWorkerMs = " + (nowMs - updateWorkerMs) + + ", exceeds pdpCheckInterval + 2000 = " + (pdpCheckInterval + 2000) + " Will reschedule updateWorker timer"); + + try{ + updateWorker.cancel(); + // Recalculate the time because this is a synchronized section and the thread could have + // been blocked. + now = new Date(); + nowMs = now.getTime(); + updateWorker = new Timer(); + // reset the updateWorkerLastRunDate + updateWorkerLastRunDate = new Date(nowMs + 100); + //execute the first time in 100 ms + updateWorker.scheduleAtFixedRate(new TimerUpdateClass(), 100, pdpCheckInterval); + logger.info("checkUpdateWorkerTimer: Scheduling updateWorker timer to start in 100 ms "); + }catch(Exception e){ + logger.error("checkUpdateWorkerTimer: Caught unexpected Exception: " + e); + System.out.println(new Date() + " checkUpdateWorkerTimer caught an unexpected exception"); + e.printStackTrace(); + // Recalculate the time because this is a synchronized section and the thread could have + // been blocked. + now = new Date(); + nowMs = now.getTime(); + updateWorker = new Timer(); + updateWorkerLastRunDate = new Date(nowMs + 100); + updateWorker.scheduleAtFixedRate(new TimerUpdateClass(), 100, pdpCheckInterval); + logger.info("checkUpdateWorkerTimer: Attempting to schedule updateWorker timer in 100 ms"); + } + + } + logger.debug("checkUpdateWorkerTimer: exit"); + }catch(Exception e){ + logger.error("checkUpdateWorkerTimer: caught unexpected exception: " + e); + System.out.println(new Date() + " checkUpdateWorkerTimer - top level - caught an unexpected exception"); + e.printStackTrace(); + } + } + } + + private void checkWaitTimer(){ + synchronized(checkWaitTimerLock){ + try{ + logger.debug("checkWaitTimer: entry"); + Date now = new Date(); + long nowMs = now.getTime(); + long waitTimerMs = waitTimerLastRunDate.getTime(); + + //give it 2 times leeway + if((nowMs - waitTimerMs) > 2*pdpUpdateInterval){ + logger.error("checkWaitTimer: nowMs - waitTimerMs = " + (nowMs - waitTimerMs) + + ", exceeds pdpUpdateInterval + 2000 = " + (2*pdpUpdateInterval) + " Will reschedule waitTimer timer"); + + + try{ + // Recalculate since the thread could have been stalled on the synchronize() + nowMs = (new Date()).getTime(); + // Time to the start of the next pdpUpdateInterval multiple + long startMs = getDWaiterStartMs(); + waitTimer.cancel(); + designationWaiter = new DesignationWaiter(); + waitTimer = new Timer(); + waitTimerLastRunDate = new Date(nowMs + startMs); + waitTimer.scheduleAtFixedRate(designationWaiter, startMs, pdpUpdateInterval); + logger.info("checkWaitTimer: Scheduling waitTimer timer to start in " + startMs + " ms"); + }catch(Exception e){ + logger.error("checkWaitTimer: Caught unexpected Exception: " + e); + System.out.println(new Date() + " checkWaitTimer caught an unexpected exception"); + e.printStackTrace(); + // Recalculate since the thread could have been stalled on the synchronize() + nowMs = (new Date()).getTime(); + // Time to the start of the next pdpUpdateInterval multiple + long startMs = getDWaiterStartMs(); + designationWaiter = new DesignationWaiter(); + waitTimer = new Timer(); + waitTimerLastRunDate = new Date(nowMs + startMs); + waitTimer.scheduleAtFixedRate(designationWaiter, startMs, pdpUpdateInterval); + logger.info("checkWaitTimer: Scheduling waitTimer timer in " + startMs + " ms"); + } + + } + logger.debug("checkWaitTimer: exit"); + }catch(Exception e){ + logger.error("checkWaitTimer: caught unexpected exception: " + e); + System.out.println(new Date() + " checkWaitTimer caught an unexpected exception"); + e.printStackTrace(); + } + } + } + + private long getDWaiterStartMs(){ + Date now = new Date(); + + // Retrieve the ms since the epoch + long nowMs = now.getTime(); + + // Time since the end of the last pdpUpdateInterval multiple + long nowModMs = nowMs % pdpUpdateInterval; + + // Time to the start of the next pdpUpdateInterval multiple + long startMs = pdpUpdateInterval - nowModMs; + + // Give the start time a minimum of a 5 second cushion + if(startMs < 5000){ + // Start at the beginning of following interval + startMs = pdpUpdateInterval + startMs; + } + return startMs; + } + + private boolean nullSafeEquals(Object one, Object two){ + if(one == null && two == null){ + return true; + } + if(one != null && two != null){ + return one.equals(two); + } + return false; + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPersistenceProperties.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPersistenceProperties.java new file mode 100644 index 00000000..63af53cb --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsPersistenceProperties.java @@ -0,0 +1,64 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Properties; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + +public class DroolsPersistenceProperties { + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(DroolsPersistenceProperties.class); + /* + * droolsPersistence.properties parameter key values + */ + public static final String DB_DRIVER = "javax.persistence.jdbc.driver"; + public static final String DB_DATA_SOURCE = "hibernate.dataSource"; + public static final String DB_URL = "javax.persistence.jdbc.url"; + public static final String DB_USER = "javax.persistence.jdbc.user"; + public static final String DB_PWD = "javax.persistence.jdbc.password"; + + private static Properties properties = null; + /* + * Initialize the parameter values from the droolsPersitence.properties file values + * + * This is designed so that the Properties object is obtained from the droolsPersistence.properties + * file and then is passed to this method to initialize the value of the parameters. + * This allows the flexibility of JUnit tests using getProperties(filename) to get the + * properties while runtime methods can use getPropertiesFromClassPath(filename). + * + */ + public static void initProperties (Properties prop){ + logger.info("DroolsPersistenceProperties.initProperties(Properties): entry"); + logger.info("\n\nDroolsPersistenceProperties.initProperties: Properties = \n" + prop + "\n\n"); + + properties = prop; + } + + public static String getProperty(String key){ + return properties.getProperty(key); + } + + public static Properties getProperties() { + return properties; + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSession.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSession.java new file mode 100644 index 00000000..21a480d9 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSession.java @@ -0,0 +1,31 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +public interface DroolsSession { + + public String getPdpId(); + public void setPdpId(String pdpId); + public String getSessionName(); + public void setSessionName(String sessionName); + public long getSessionId(); + public void setSessionId(long sessionId); +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSessionEntity.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSessionEntity.java new file mode 100644 index 00000000..89e310f0 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/DroolsSessionEntity.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.io.Serializable; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +@Entity +public class DroolsSessionEntity implements Serializable, DroolsSession { + @Id + @Column(name="pdpId", nullable=false) + private String pdpId="-1"; + @Id + @Column(name="sessionName", nullable=false) + private String sessionName="-1"; + + @Column(name="sessionId", nullable=false) + private long sessionId=-1L; + + @ManyToOne + private DroolsPdpEntity pdpEntity; + public DroolsSessionEntity(){ + + } + @Override + public String getPdpId() { + return pdpId; + } + @Override + public void setPdpId(String pdpId) { + this.pdpId = pdpId; + } + @Override + public String getSessionName() { + return sessionName; + } + @Override + public void setSessionName(String sessionName) { + this.sessionName = sessionName; + } + @Override + public long getSessionId() { + return sessionId; + } + + @Override + public void setSessionId(long sessionId) { + this.sessionId = sessionId; + } + public void setPdpEntity(DroolsPdpEntity pdpEntity){ + this.pdpEntity = pdpEntity; + } + @Override + public boolean equals(Object other){ + if(other instanceof DroolsSession){ + return this.getPdpId().equals(((DroolsSession)other).getPdpId()) && this.getSessionName().equals(((DroolsSession)other).getSessionName()); + }else{ + return false; + } + } + + @Override + public int hashCode(){ + String combinedId = this.getPdpId().concat(":").concat(this.getSessionName()); + return combinedId.hashCode(); + } + + +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/JpaDroolsPdpsConnector.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/JpaDroolsPdpsConnector.java new file mode 100644 index 00000000..ac9255a2 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/JpaDroolsPdpsConnector.java @@ -0,0 +1,688 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Collection; +import java.util.Date; +import java.util.LinkedList; +import java.util.List; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.LockModeType; +import javax.persistence.Query; + +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.common.logging.eelf.MessageCodes; + + +public class JpaDroolsPdpsConnector implements DroolsPdpsConnector { + + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(JpaDroolsPdpsConnector.class); + private EntityManagerFactory emf; + + + //not sure if we want to use the same entity manager factory for drools session and pass it in here, or create a new one + public JpaDroolsPdpsConnector(EntityManagerFactory emf){ + this.emf = emf; + } + @Override + public Collection<DroolsPdp> getDroolsPdps() { + //return a list of all the DroolsPdps in the database + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p"); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.PESSIMISTIC_READ).getResultList(); + LinkedList<DroolsPdp> droolsPdpsReturnList = new LinkedList<DroolsPdp>(); + for(Object o : droolsPdpsList){ + if(o instanceof DroolsPdp){ + //Make sure it is not a cached version + em.refresh((DroolsPdpEntity)o); + droolsPdpsReturnList.add((DroolsPdp)o); + if (logger.isDebugEnabled()) { + DroolsPdp droolsPdp = (DroolsPdp)o; + logger.debug("getDroolsPdps: PDP=" + droolsPdp.getPdpId() + + ", isDesignated=" + droolsPdp.isDesignated() + + ", updatedDate=" + droolsPdp.getUpdatedDate() + + ", priority=" + droolsPdp.getPriority()); + } + } + } + try{ + em.getTransaction().commit(); + }catch(Exception e){ + logger.error + (MessageCodes.EXCEPTION_ERROR, e,"Cannot commit getDroolsPdps() transaction"); + } + return droolsPdpsReturnList; + } finally { + cleanup(em, "getDroolsPdps"); + } + } + + private boolean nullSafeEquals(Object one, Object two){ + if(one == null && two == null){ + return true; + } + if(one != null && two != null){ + return one.equals(two); + } + return false; + } + + @Override + public void update(DroolsPdp pdp) { + + if (logger.isDebugEnabled()) { + logger.debug("update: Entering, pdpId=" + pdp.getPdpId()); + } + + //this is to update our own pdp in the database + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId"); + droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId()); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.PESSIMISTIC_WRITE).getResultList(); + //em.getTransaction().begin(); + DroolsPdpEntity droolsPdpEntity; + if(droolsPdpsList.size() == 1 && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)){ + droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0); + //if(pdp.getSessionId() < 0){ + //if its less than 0, then we know it is not a real session number so we want to save the one that the database has for us, to avoid information loss + //pdp.setSessionId(droolsPdpEntity.getSessionId()); + //} + Date currentDate = new Date(); + long difference = currentDate.getTime()-droolsPdpEntity.getUpdatedDate().getTime(); + //just set some kind of default here + long pdpTimeout = 15000; + try{ + pdpTimeout = Long.parseLong(IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_TIMEOUT)); + }catch(Exception e){ + logger.error + (MessageCodes.EXCEPTION_ERROR, e,"Could not get PDP timeout property, using default."); + } + boolean isCurrent = difference<pdpTimeout; + if (logger.isDebugEnabled()) { + logger.debug("update: PDP=" + pdp.getPdpId() + ", isCurrent=" + + isCurrent + ", difference=" + difference + + ", pdpTimeout=" + pdpTimeout + ", designated=" + + droolsPdpEntity.isDesignated()); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("update: For PDP=" + pdp.getPdpId() + + ", instantiating new DroolsPdpEntity"); + } + droolsPdpEntity = new DroolsPdpEntity(); + em.persist(droolsPdpEntity); + droolsPdpEntity.setPdpId(pdp.getPdpId()); + } + if(droolsPdpEntity.getPriority() != pdp.getPriority()){ + droolsPdpEntity.setPriority(pdp.getPriority()); + } + if(!droolsPdpEntity.getUpdatedDate().equals(pdp.getUpdatedDate())){ + droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate()); + } + if(!droolsPdpEntity.getDesignatedDate().equals(pdp.getDesignatedDate())){ + droolsPdpEntity.setDesignatedDate(pdp.getDesignatedDate()); + } + if(!nullSafeEquals(droolsPdpEntity.getSiteName(),pdp.getSiteName())){ + droolsPdpEntity.setSiteName(pdp.getSiteName()); + } + List<DroolsSessionEntity> sessionsToAdd = new LinkedList<DroolsSessionEntity>(); + for(DroolsSessionEntity localSession : pdp.getSessions()){ + boolean found = false; + for(DroolsSessionEntity dbSession : droolsPdpEntity.getSessions()){ + if(localSession.equals(dbSession)){ + found = true; + dbSession.setSessionId(localSession.getSessionId()); + } + } + if(!found){ + sessionsToAdd.add(localSession); + } + + } + for(DroolsSessionEntity sessionToAdd : sessionsToAdd){ + em.persist(sessionToAdd); + droolsPdpEntity.getSessions().add(sessionToAdd); + } + + + if(droolsPdpEntity.isDesignated() != pdp.isDesignated()){ + if (logger.isDebugEnabled()) { + logger.debug("update: pdpId=" + pdp.getPdpId() + + ", pdp.isDesignated=" + pdp.isDesignated() + + ", droolsPdpEntity.pdpId=" + + droolsPdpEntity.getPdpId() + + ", droolsPdpEntity.isDesignated=" + + droolsPdpEntity.isDesignated()); + } + droolsPdpEntity.setDesignated(pdp.isDesignated()); + } + em.getTransaction().commit(); + } finally { + cleanup(em, "update"); + } + + if (logger.isDebugEnabled()) { + logger.debug("update: Exiting"); + } + + } + + /* + * Note: A side effect of this boolean method is that if the PDP is designated but not current, the + * droolspdpentity.DESIGNATED column will be set to false (the PDP will be un-designated, i.e. marked as + * being in standby mode) + */ + @Override + public boolean isPdpCurrent(DroolsPdp pdp) { + + boolean isCurrent = isCurrent(pdp); + + EntityManager em = emf.createEntityManager(); + try{ + if(!isCurrent && pdp.isDesignated()){ + em.getTransaction().begin(); + Query droolsPdpsListQuery = em.createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId"); + droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId()); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode(LockModeType.PESSIMISTIC_WRITE).getResultList(); + if(droolsPdpsList.size() == 1 && droolsPdpsList.get(0) instanceof DroolsPdpEntity){ + if (logger.isDebugEnabled()) { + logger.debug("isPdpCurrent: PDP=" + pdp.getPdpId() + " designated but not current; setting designated to false"); + } + DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity)droolsPdpsList.get(0); + droolsPdpEntity.setDesignated(false); + em.getTransaction().commit(); + } else { + logger.warn("isPdpCurrent: PDP=" + pdp.getPdpId() + " is designated but not current; however it does not have a DB entry, so cannot set DESIGNATED to false!"); + } + } else { + if (logger.isDebugEnabled()) { + logger.debug("isPdpCurrent: For PDP=" + pdp.getPdpId() + + ", designated=" + + pdp.isDesignated() + ", isCurrent=" + isCurrent); + } + } + }catch(Exception e){ + logger.error + (MessageCodes.EXCEPTION_ERROR, e,"Could not update expired record marked as designated in the database"); + } finally { + cleanup(em, "isPdpCurrent"); + } + return isCurrent; + + } + + @Override + public void setDesignated(DroolsPdp pdp, boolean designated) { + + if (logger.isDebugEnabled()) { + logger.debug("setDesignated: Entering, pdpId='" + pdp.getPdpId() + + "', designated=" + designated); + } + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + Query droolsPdpsListQuery = em + .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId"); + droolsPdpsListQuery.setParameter("pdpId", pdp.getPdpId()); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode( + LockModeType.PESSIMISTIC_WRITE).getResultList(); + if (droolsPdpsList.size() == 1 + && droolsPdpsList.get(0) instanceof DroolsPdpEntity) { + DroolsPdpEntity droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList + .get(0); + if (logger.isDebugEnabled()) { + logger.debug("setDesignated: PDP=" + pdp.getPdpId() + + " found, designated=" + + droolsPdpEntity.isDesignated() + ", setting to " + + designated); + } + droolsPdpEntity.setDesignated(designated); + em.getTransaction().commit(); + } else { + logger.error("setDesignated: PDP=" + pdp.getPdpId() + + " not in DB; cannot update designation"); + } + } catch (Exception e) { + logger.error("setDesignated: Caught Exception, message='" + + e.getMessage() + "'"); + } finally { + cleanup(em, "setDesignated"); + } + + if (logger.isDebugEnabled()) { + logger.debug("setDesignated: Exiting"); + } + + } + + + @Override + public void standDownPdp(String pdpId) { + + logger.info("standDownPdp: Entering, pdpId='" + pdpId + "'"); + + EntityManager em = null; + try { + /* + * Start transaction. + */ + em = emf.createEntityManager(); + em.getTransaction().begin(); + + /* + * Get droolspdpentity record for this PDP and mark DESIGNATED as + * false. + */ + Query droolsPdpsListQuery = em + .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId"); + droolsPdpsListQuery.setParameter("pdpId", pdpId); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode( + LockModeType.PESSIMISTIC_WRITE).getResultList(); + DroolsPdpEntity droolsPdpEntity; + if (droolsPdpsList.size() == 1 + && (droolsPdpsList.get(0) instanceof DroolsPdpEntity)) { + droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0); + droolsPdpEntity.setDesignated(false); + em.persist(droolsPdpEntity); + logger.info("standDownPdp: PDP=" + pdpId + " persisted as non-designated."); + } else { + logger.error("standDownPdp: Missing record in droolspdpentity for pdpId=" + + pdpId + "; cannot stand down PDP"); + } + + /* + * End transaction. + */ + em.getTransaction().commit(); + cleanup(em, "standDownPdp"); + em = null; + + // Keep the election handler in sync with the DB + DroolsPdpsElectionHandler.setMyPdpDesignated(false); + + } catch (Exception e) { + logger.error("standDownPdp: Unexpected Exception attempting to mark DESIGNATED as false for droolspdpentity, pdpId=" + + pdpId + + ". Cannot stand down PDP; message=" + + e.getMessage()); + } finally { + cleanup(em, "standDownPdp"); + } + + logger.info("standDownPdp: Exiting"); + + } + + /* + * Determines whether or not a designated PDP has failed. + * + * Note: The update method, which is run periodically by the + * TimerUpdateClass, will un-designate a PDP that is stale. + */ + @Override + public boolean hasDesignatedPdpFailed(Collection<DroolsPdp> pdps) { + + if (logger.isDebugEnabled()) { + logger.debug("hasDesignatedPdpFailed: Entering, pdps.size()=" + + pdps.size()); + } + + boolean failed = true; + boolean foundDesignatedPdp = false; + + for (DroolsPdp pdp : pdps) { + + /* + * Normally, the update method will un-designate any stale PDP, but + * we check here to see if the PDP has gone stale since the update + * method was run. + * + * Even if we determine that the designated PDP is current, we keep + * going (we don't break), so we can get visibility into the other + * PDPs, when in DEBUG mode. + */ + if (pdp.isDesignated() && isCurrent(pdp)) { + if (logger.isDebugEnabled()) { + logger.debug("hasDesignatedPdpFailed: Designated PDP=" + + pdp.getPdpId() + " is current"); + } + failed = false; + foundDesignatedPdp = true; + } else if (pdp.isDesignated() && !isCurrent(pdp)) { + logger.error("hasDesignatedPdpFailed: Designated PDP=" + + pdp.getPdpId() + " has failed"); + foundDesignatedPdp = true; + } else { + if (logger.isDebugEnabled()) { + logger.debug("hasDesignatedPdpFailed: PDP=" + + pdp.getPdpId() + " is not designated"); + } + } + } + + if (logger.isDebugEnabled()) { + logger.debug("hasDesignatedPdpFailed: Exiting and returning, foundDesignatedPdp=" + + foundDesignatedPdp); + } + return failed; + } + + + private boolean isCurrent(DroolsPdp pdp) { + + if (logger.isDebugEnabled()) { + logger.debug("isCurrent: Entering, pdpId=" + + pdp.getPdpId()); + } + + boolean current = false; + + // Return if the current PDP is considered "current" based on whatever + // time box that may be. + // If the the PDP is not current, we should mark it as not primary in + // the database + Date currentDate = new Date(); + long difference = currentDate.getTime() + - pdp.getUpdatedDate().getTime(); + // just set some kind of default here + long pdpTimeout = 15000; + try { + pdpTimeout = Long.parseLong(IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_TIMEOUT)); + if (logger.isDebugEnabled()) { + logger.debug("isCurrent: pdp.timeout=" + pdpTimeout); + } + } catch (Exception e) { + logger.error + (MessageCodes.EXCEPTION_ERROR, e, + "isCurrent: Could not get PDP timeout property, using default."); + } + current = difference < pdpTimeout; + + if (logger.isDebugEnabled()) { + logger.debug("isCurrent: Exiting, difference=" + + difference + ", pdpTimeout=" + pdpTimeout + + "; returning current=" + current); + } + + return current; + } + + + /* + * Currently this method is only used in a JUnit test environment. Gets a + * PDP record from droolspdpentity table. + */ + @Override + public DroolsPdpEntity getPdp(String pdpId) { + + if (logger.isDebugEnabled()) { + logger.debug("getPdp: Entering and getting PDP with pdpId='" + pdpId + + "'"); + } + + DroolsPdpEntity droolsPdpEntity = null; + + EntityManager em = null; + try { + em = emf.createEntityManager(); + em.getTransaction().begin(); + Query droolsPdpsListQuery = em + .createQuery("SELECT p FROM DroolsPdpEntity p WHERE p.pdpId=:pdpId"); + droolsPdpsListQuery.setParameter("pdpId", pdpId); + List<?> droolsPdpsList = droolsPdpsListQuery.setLockMode( + LockModeType.PESSIMISTIC_WRITE).getResultList(); + if (droolsPdpsList.size() == 1 + && droolsPdpsList.get(0) instanceof DroolsPdpEntity) { + droolsPdpEntity = (DroolsPdpEntity) droolsPdpsList.get(0); + if (logger.isDebugEnabled()) { + logger.debug("getPdp: PDP=" + pdpId + + " found, isDesignated=" + + droolsPdpEntity.isDesignated() + ", updatedDate=" + + droolsPdpEntity.getUpdatedDate() + ", priority=" + + droolsPdpEntity.getPriority()); + } + + // Make sure the droolsPdpEntity is not a cached version + em.refresh(droolsPdpEntity); + + em.getTransaction().commit(); + } else { + logger.error("getPdp: PDP=" + pdpId + " not found!?"); + } + } catch (Exception e) { + logger.error + (MessageCodes.EXCEPTION_ERROR, e,"getPdp: Caught Exception attempting to get PDP, message='" + + e.getMessage() + "'"); + } finally { + cleanup(em, "getPdp"); + } + + if (logger.isDebugEnabled()) { + logger.debug("getPdp: Returning droolsPdpEntity=" + droolsPdpEntity); + } + return droolsPdpEntity; + + } + + /* + * Normally this method should only be used in a JUnit test environment. + * Manually inserts a PDP record in droolspdpentity table. + */ + @Override + public void insertPdp(DroolsPdp pdp) { + + logger.info("insertPdp: Entering and manually inserting PDP"); + + /* + * Start transaction + */ + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + + /* + * Insert record. + */ + DroolsPdpEntity droolsPdpEntity = new DroolsPdpEntity(); + em.persist(droolsPdpEntity); + droolsPdpEntity.setPdpId(pdp.getPdpId()); + droolsPdpEntity.setDesignated(pdp.isDesignated()); + droolsPdpEntity.setPriority(pdp.getPriority()); + droolsPdpEntity.setUpdatedDate(pdp.getUpdatedDate()); + droolsPdpEntity.setSiteName(pdp.getSiteName()); + + /* + * End transaction. + */ + em.getTransaction().commit(); + } finally { + cleanup(em, "insertPdp"); + } + + logger.info("insertPdp: Exiting"); + + } + + /* + * Normally this method should only be used in a JUnit test environment. + * Manually deletes all PDP records in droolspdpentity table. + */ + @Override + public void deleteAllPdps() { + + logger.info("deleteAllPdps: Entering"); + + /* + * Start transaction + */ + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + + Query droolsPdpsListQuery = em + .createQuery("SELECT p FROM DroolsPdpEntity p"); + @SuppressWarnings("unchecked") + List<DroolsPdp> droolsPdpsList = droolsPdpsListQuery.setLockMode( + LockModeType.NONE).getResultList(); + logger.info("deleteAllPdps: Deleting " + droolsPdpsList.size() + " PDPs"); + for (DroolsPdp droolsPdp : droolsPdpsList) { + String pdpId = droolsPdp.getPdpId(); + deletePdp(pdpId); + } + + /* + * End transaction. + */ + em.getTransaction().commit(); + } finally { + cleanup(em, "deleteAllPdps"); + } + + logger.info("deleteAllPdps: Exiting"); + + } + + /* + * Normally this method should only be used in a JUnit test environment. + * Manually deletes a PDP record in droolspdpentity table. + */ + @Override + public void deletePdp(String pdpId) { + + logger.info("deletePdp: Entering and manually deleting pdpId='" + pdpId + + "'"); + + /* + * Start transaction + */ + EntityManager em = emf.createEntityManager(); + try { + em.getTransaction().begin(); + + /* + * Delete record. + */ + DroolsPdpEntity droolsPdpEntity = em.find(DroolsPdpEntity.class, pdpId); + if (droolsPdpEntity != null) { + logger.info("deletePdp: Removing PDP"); + em.remove(droolsPdpEntity); + } else { + logger.info("deletePdp: PDP with ID='" + pdpId + + "' not currently in DB"); + } + + /* + * End transaction. + */ + em.getTransaction().commit(); + } finally { + cleanup(em, "deletePdp"); + } + + logger.info("deletePdp: Exiting"); + + } + + /* + * Normally this method should only be used in a JUnit test environment. + * Manually deletes all records in droolsessionentity table. + */ + @Override + public void deleteAllSessions() { + + logger.info("deleteAllSessions: Entering"); + + /* + * Start transaction + */ + EntityManager em = emf.createEntityManager(); + + try { + em.getTransaction().begin(); + + Query droolsSessionListQuery = em + .createQuery("SELECT p FROM DroolsSessionEntity p"); + @SuppressWarnings("unchecked") + List<DroolsSession> droolsSessionsList = droolsSessionListQuery.setLockMode( + LockModeType.NONE).getResultList(); + logger.info("deleteAllSessions: Deleting " + droolsSessionsList.size() + " Sessions"); + for (DroolsSession droolsSession : droolsSessionsList) { + logger.info("deleteAllSessions: Deleting droolsSession with pdpId=" + + droolsSession.getPdpId() + " and sessionId=" + + droolsSession.getSessionId()); + em.remove(droolsSession); + } + + /* + * End transaction. + */ + em.getTransaction().commit(); + } finally { + cleanup(em, "deleteAllSessions"); + } + logger.info("deleteAllSessions: Exiting"); + + } + + + /* + * Close the specified EntityManager, rolling back any pending transaction + * + * @param em the EntityManager to close ('null' is OK) + * @param method the invoking Java method (used for log messages) + */ + private static void cleanup(EntityManager em, String method) + { + if (em != null) { + if (em.isOpen()) { + if (em.getTransaction().isActive()) { + // there is an active EntityTransaction -- roll it back + try { + em.getTransaction().rollback(); + } catch (Exception e) { + logger.error(method + ": Caught Exception attempting to rollback EntityTransaction, message='" + + e.getMessage() + "'"); + } + } + + // now, close the EntityManager + try { + em.close(); + } catch (Exception e) { + logger.error(method + ": Caught Exception attempting to close EntityManager, message='" + + e.getMessage() + "'"); + } + } + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/PersistenceFeature.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/PersistenceFeature.java new file mode 100644 index 00000000..e2c7f402 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/PersistenceFeature.java @@ -0,0 +1,614 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.io.IOException; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.eclipse.persistence.config.PersistenceUnitProperties; +import org.kie.api.KieServices; +import org.kie.api.runtime.Environment; +import org.kie.api.runtime.EnvironmentName; +import org.kie.api.runtime.KieSession; +import org.kie.api.runtime.KieSessionConfiguration; +import org.openecomp.policy.common.ia.IntegrityAudit; +import org.openecomp.policy.common.ia.IntegrityAuditProperties; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.common.logging.eelf.MessageCodes; +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; +import org.openecomp.policy.common.logging.flexlogger.PropertyUtil; +import org.openecomp.policy.drools.core.DroolsPDPIntegrityMonitor; +import org.openecomp.policy.drools.core.FeatureAPI; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.drools.core.PolicyContainer; +import org.openecomp.policy.drools.core.PolicySession; +import org.openecomp.policy.drools.im.PMStandbyStateChangeNotifier; +import org.openecomp.policy.drools.system.PolicyEngine; + +import bitronix.tm.Configuration; +import bitronix.tm.TransactionManagerServices; +import bitronix.tm.resource.jdbc.PoolingDataSource; + +/** + * If this feature is supported, there is a single instance of it. + * It adds persistence to Drools sessions, but it is also intertwined with + * active/standby state management and IntegrityMonitor. For now, they are + * all treated as a single feature, but it would be nice to separate them. + * + * The bulk of the code here was once in other classes, such as + * 'PolicyContainer' and 'Main'. It was moved here as part of making this + * a separate optional feature. + */ +public class PersistenceFeature implements FeatureAPI +{ + // get an instance of logger + private static Logger logger = + FlexLogger.getLogger(PersistenceFeature.class); + + // 'KieServices' singleton + static private KieServices kieServices = KieServices.Factory.get(); + + private static DroolsPdp myPdp; + private static Object myPdpSync = new Object(); + private static DroolsPdpsElectionHandler electionHandler; + + // indicates whether persistence has been disabled + private static boolean persistenceDisabled = false; + + /* + * Used by JUnit testing to verify whether or not audit is running. + */ + private static IntegrityAudit integrityAudit = null; + + /** + * Lookup the adjunct for this feature that is associated with the + * specified PolicyContainer. If not found, create one. + * + * @param policyContainer the container whose adjunct we are looking up, + * and possibly creating + * @return the associated 'ContainerAdjunct' instance, which may be new + */ + private ContainerAdjunct getContainerAdjunct(PolicyContainer policyContainer) + { + Object rval = policyContainer.getAdjunct(this); + if (rval == null || ! (rval instanceof ContainerAdjunct)) + { + // adjunct does not exist, or has the wrong type (should never happen) + rval = new ContainerAdjunct(policyContainer); + policyContainer.setAdjunct(this, rval); + } + return((ContainerAdjunct)rval); + } + + /**************************/ + /* 'FeatureAPI' interface */ + /**************************/ + + /** + * {@inheritDoc} + */ + @Override + public int getSequenceNumber() + { + return(1); + } + + /** + * {@inheritDoc} + */ + @Override + public void globalInit(String args[], String configDir) + { + // Initialization code associated with 'PolicyContainer' + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = null; + try + { + droolsPdpIntegrityMonitor = DroolsPDPIntegrityMonitor.init(configDir); + } + catch (Exception e) + { + logger.error(MessageCodes.EXCEPTION_ERROR, e, + "main", "DroolsPDPIntegrityMonitor.init()"); + } + + initializePersistence(configDir, droolsPdpIntegrityMonitor); + + // 1. Start Integrity Monitor (unless it was specifically disabled in the CORE layer + + + if (persistenceDisabled) { + System.out.println("WARNING: Starting Engine with Persistance disabled"); + logger.warn("Starting Engine with Persistance disabled"); + } else { + DroolsPDPIntegrityMonitor im = null; + //At this point the DroolsPDPIntegrityMonitor instance must exist + try { + im = DroolsPDPIntegrityMonitor.getInstance(); + } catch (Exception e1) { + String msg = "policy-core startup failed to get DroolsPDPIntegrityMonitor instance: \n" + e1; + System.out.println(msg); + e1.printStackTrace(); + } + //Now get the StateManagement instance so we can register our observer + StateManagement sm = im.getStateManager(); + + //Create an instance of the Observer + PMStandbyStateChangeNotifier pmNotifier = new PMStandbyStateChangeNotifier(); + + //Register the PMStandbyStateChangeNotifier Observer + sm.addObserver(pmNotifier); + } + } + + /** + * This is a hook to create a new persistent KieSession. + * + * {@inheritDoc} + */ + @Override + public KieSession activatePolicySession + (PolicyContainer policyContainer, String name, String kieBaseName) + { + return(getContainerAdjunct(policyContainer) + .newPersistentKieSession(name, kieBaseName)); + } + + /** + * {@inheritDoc} + */ + @Override + public void disposeKieSession(PolicySession policySession) + { + // TODO: There should be one data source per session + getContainerAdjunct(policySession.getPolicyContainer()) + .disposeKieSession(); + } + + /** + * {@inheritDoc} + */ + @Override + public void destroyKieSession(PolicySession policySession) + { + // TODO: There should be one data source per session + getContainerAdjunct(policySession.getPolicyContainer()) + .destroyKieSession(); + } + + + /** + * {@inheritDoc} + */ + @Override + public void beforeStartEngine() + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void afterStartEngine() + { + PolicyEngine.manager.lock(); + } + + /** + * {@inheritDoc} + */ + @Override + public void beforeShutdownEngine() + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void beforeCreateController(String name, Properties properties) + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void afterCreateController(String name) + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void afterShutdownEngine() + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void beforeStartController(String name) + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public void afterStartController(String name) + { + return; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isPersistenceEnabled() + { + return(!persistenceDisabled); + } + + /**************************/ + + /** + * @return 'true' if Drools persistence is disabled, and 'false' if not + */ + static public boolean getPersistenceDisabled() + { + return(persistenceDisabled); + } + + /** + * Read in the persistence properties, determine whether persistence is + * enabled or disabled, and initialize persistence if enabled. + */ + private static void initializePersistence(String configDir, DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor) + { + + try { + Properties pDrools = PropertyUtil.getProperties(configDir + + "/droolsPersistence.properties"); + DroolsPersistenceProperties.initProperties(pDrools); + Properties pXacml = PropertyUtil.getProperties(configDir + + "/xacmlPersistence.properties"); + XacmlPersistenceProperties.initProperties(pXacml); + if ("true".equals(pDrools.getProperty("persistenceDisabled"))) { + // 'persistenceDisabled' only relates to the 'drools' + // database. The fact that integrityMonitor/xacml depends upon + // persistence is an implementation detail there (which can't + // currently be disabled), and doesn't directly affect + // 'policy-core'. + persistenceDisabled = true; + } + } catch (IOException e1) { + logger.error(MessageCodes.MISS_PROPERTY_ERROR, e1, + "initializePersistence"); + } + + /* + * Might as well handle the Integrity Monitor properties here, too. + */ + try { + Properties pIm = + PropertyUtil.getProperties(configDir + "/IntegrityMonitor.properties"); + IntegrityMonitorProperties.initProperties(pIm); + logger.info("initializePersistence: resourceName=" + IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID)); + } catch (IOException e1) { + logger.error(MessageCodes.MISS_PROPERTY_ERROR, e1, "initializePersistence"); + } + + + if (persistenceDisabled) { + // The persistence design is tied to 'DroolsPdpsElectionHandler', + // so we should bypass that as well. This also means that we + // won't get active/standby notifications, so we need to go + // into the 'active' state in order to have any 'PolicySession' + // instances. + return; + } + + DroolsPdpsConnector conn = getDroolsPdpsConnector("ncompPU"); + String uniquePdpId = IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + if(uniquePdpId == null){ + throw new NullPointerException(); + } + + /* + * In a JUnit test environment, one or more PDPs may already have been + * inserted in the DB, so we need to check for this. + */ + DroolsPdp existingPdp = conn.getPdp(uniquePdpId); + if (existingPdp != null) { + System.out.println("Found existing PDP record, pdpId=" + + existingPdp.getPdpId() + ", isDesignated=" + + existingPdp.isDesignated() + ", updatedDate=" + + existingPdp.getUpdatedDate()); + myPdp = existingPdp; + } + + /* + * Kick off integrity audit for Drools DB. + */ + startIntegrityAudit(configDir); + + synchronized(myPdpSync){ + if(myPdp == null){ + + myPdp = new DroolsPdpImpl(uniquePdpId,false,4,new Date()); + } + if(myPdp != null){ + String site_name = ""; + site_name = IntegrityMonitorProperties.getProperty(IntegrityMonitorProperties.SITE_NAME); + if (site_name == null) { + site_name = ""; + }else{ + site_name = site_name.trim(); + } + myPdp.setSiteName(site_name); + } + if(electionHandler == null){ + electionHandler = new DroolsPdpsElectionHandler(conn,myPdp,droolsPdpIntegrityMonitor); + } + } + Configuration bitronixConfiguration = TransactionManagerServices.getConfiguration(); + bitronixConfiguration.setJournal(null); + bitronixConfiguration.setServerId(uniquePdpId); + System.out.println("\n\nThis controller is a standby, waiting to be chosen as primary...\n\n"); + logger.info("\n\nThis controller is a standby, waiting to be chosen as primary...\n\n"); + } + + private static void startIntegrityAudit(String configDir) { + + logger.info("startIntegrityAudit: Entering, configDir='" + configDir + + "'"); + + /* + * Initialize Integrity Audit properties. file. + */ + try { + + String resourceName = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + /* + * Load properties for auditing of Drools DB. + */ + Properties droolsPia = PropertyUtil.getProperties(configDir + + "/IntegrityMonitor.properties"); + + /* + * Supplement properties specific to the IntegrityMonitor (e.g. + * site_name, node_type, resource.name) with properties specific to + * persisting Drools DB entities (see + * ../policy-core/src/main/resources/persistence.xml) + * + * Note: integrity_audit_period_seconds is defined in + * IntegrityMonitor.properties, rather than creating a whole new + * "IntegrityAudit.properties" file for just one property. + */ + droolsPia + .setProperty( + IntegrityAuditProperties.DB_DRIVER, + DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_DRIVER)); + droolsPia.setProperty(IntegrityAuditProperties.DB_PWD, + DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_PWD)); + droolsPia.setProperty(IntegrityAuditProperties.DB_URL, + DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_URL)); + droolsPia.setProperty(IntegrityAuditProperties.DB_USER, + DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_USER)); + + /* + * Start audit for Drools DB. + */ + integrityAudit = new IntegrityAudit( + resourceName, "ncompPU", droolsPia); + integrityAudit.startAuditThread(); + + } catch (IOException e1) { + logger.error( + MessageCodes.MISS_PROPERTY_ERROR, + e1, + "initializePersistence: IntegrityAuditProperties: " + + e1.getMessage()); + } catch (Exception e2) { + logger.error( + MessageCodes.EXCEPTION_ERROR, + e2, + "initializePersistence: IntegrityAuditProperties: " + + e2.getMessage()); + } + + logger.debug("startIntegrityAudit: Exiting"); + + } + + /* + * Moved code to instantiate a JpaDroolsPdpsConnector object from main() to + * this method, so it can also be accessed from StandbyStateChangeNotifier + * class. + */ + public static DroolsPdpsConnector getDroolsPdpsConnector(String pu) { + + Map<String, Object> propMap = new HashMap<String, Object>(); + propMap.put("javax.persistence.jdbc.driver", DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_DRIVER)); + propMap.put("javax.persistence.jdbc.url", + DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_URL)); + propMap.put("javax.persistence.jdbc.user", DroolsPersistenceProperties + .getProperty(DroolsPersistenceProperties.DB_USER)); + propMap.put("javax.persistence.jdbc.password", + DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_PWD)); + + EntityManagerFactory emf = Persistence.createEntityManagerFactory( + pu, propMap); + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emf); + + return conn; + } + + /* + * IntegrityAudit instance is needed by JUnit testing to ascertain whether + * or not audit is running. + */ + public static IntegrityAudit getIntegrityAudit() { + + return integrityAudit; + + } + + /* ============================================================ */ + + /** + * Each instance of this class is a logical extension of a 'PolicyContainer' + * instance. It's reference is stored in the 'adjuncts' table within the + * 'PolicyContainer', and will be garbage-collected with the container. + */ + class ContainerAdjunct + { + // this is the 'PolicyContainer' instance that this adjunct is extending + private PolicyContainer policyContainer; + private PoolingDataSource ds = null; + + /** + * Constructor - initialize a new 'ContainerAdjunct' + * + * @param policyContainer the 'PolicyContainer' instance this adjunct + * is extending + */ + ContainerAdjunct(PolicyContainer policyContainer) + { + this.policyContainer = policyContainer; + } + + /** + * Create a new persistent KieSession. If there is already a corresponding + * entry in the database, it is used to initialize the KieSession. If not, + * a completely new session is created. + * + * @param name the name of the KieSession (which is also the name of + * the associated PolicySession) + * @param kieBaseName the name of the 'KieBase' instance containing + * this session + * @return a new KieSession with persistence enabled (if persistence is + * disabled, 'null' is returned + */ + private KieSession newPersistentKieSession(String name, String kieBaseName) + { + if (persistenceDisabled) + { + return(null); + } + long desiredSessionId = -1; + synchronized (myPdpSync) { + + + + for(DroolsSession droolsSession : electionHandler.getSessions()){ + if(droolsSession.getSessionName().equals(name)){ + desiredSessionId = droolsSession.getSessionId(); + } + } + } + System.out.println("\n\nThis controller is primary... coming up with session "+desiredSessionId+"\n\n"); + logger.info("\n\nThis controller is primary... coming up with session "+desiredSessionId+"\n\n"); + Map<String, Object> props = new HashMap<String, Object>(); + props.put("URL", DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_URL)); + props.put("user", DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_USER)); + props.put("password", DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_PWD)); + props.put("dataSource",DroolsPersistenceProperties.getProperty(DroolsPersistenceProperties.DB_DATA_SOURCE)); + logger.info("getPolicySession:session does not exist -- attempt to create one with name " + name); + // session does not exist -- attempt to create one + System.getProperties().put("java.naming.factory.initial","bitronix.tm.jndi.BitronixInitialContextFactory"); + Environment env = kieServices.newEnvironment(); + //kContainer.newKieBase(null); + ds = new PoolingDataSource(); + ds.setUniqueName("jdbc/BitronixJTADataSource"+name); + ds.setClassName( (String)props.remove("dataSource")); + //ds.setClassName( "org.h2.Driver" ); + ds.setMaxPoolSize( 3 ); + ds.setIsolationLevel("SERIALIZABLE"); + ds.setAllowLocalTransactions( true ); + //ds.getDriverProperties().put( "user", "sa" ); + //ds.getDriverProperties().put( "password", "" ); + //ds.getDriverProperties().put( "URL", "jdbc:h2:tcp://localhost/drools" ); + ds.getDriverProperties().putAll(props); + ds.init(); + Properties emfProperties = new Properties(); + emfProperties.setProperty(PersistenceUnitProperties.JTA_DATASOURCE, "jdbc/BitronixJTADataSource"+name); + env.set(EnvironmentName.ENTITY_MANAGER_FACTORY, Persistence.createEntityManagerFactory("ncompsessionsPU",emfProperties)); + env.set(EnvironmentName.TRANSACTION_MANAGER,TransactionManagerServices.getTransactionManager()); + KieSessionConfiguration kConf = KieServices.Factory.get().newKieSessionConfiguration(); + KieSession kieSession; + try{ + kieSession = kieServices.getStoreServices().loadKieSession(desiredSessionId, policyContainer.getKieContainer().getKieBase(kieBaseName), kConf, env); + System.out.println("LOADING We can load session "+desiredSessionId+", going to create a new one"); + logger.info("LOADING We can load session "+desiredSessionId+", going to create a new one"); + }catch(Exception e){ + System.out.println("LOADING We cannot load session "+desiredSessionId+", going to create a new one"); + + logger.info("LOADING We cannot load session "+desiredSessionId+", going to create a new one"); + kieSession = kieServices.getStoreServices().newKieSession(policyContainer.getKieContainer().getKieBase(kieBaseName), null, env); + System.out.println("LOADING CREATED "+kieSession.getIdentifier()); + logger.info("LOADING CREATED "+kieSession.getIdentifier()); + } + synchronized (myPdpSync) { + myPdp.setSessionId(name,kieSession.getIdentifier()); + electionHandler.updateMyPdp(); + } + return(kieSession); + } + + private void disposeKieSession() + { + if (ds != null) + { + ds.close(); + ds = null; + } + } + + private void destroyKieSession() + { + // does the same thing as 'dispose' + disposeKieSession(); + } + } +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/ThreadRunningChecker.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/ThreadRunningChecker.java new file mode 100644 index 00000000..ccec824c --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/ThreadRunningChecker.java @@ -0,0 +1,26 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +public interface ThreadRunningChecker { + public void checkThreadStatus(); + +} diff --git a/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/XacmlPersistenceProperties.java b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/XacmlPersistenceProperties.java new file mode 100644 index 00000000..7e2388e5 --- /dev/null +++ b/policy-persistence/src/main/java/org/openecomp/policy/drools/persistence/XacmlPersistenceProperties.java @@ -0,0 +1,65 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.persistence; + +import java.util.Properties; + +import org.openecomp.policy.common.logging.flexlogger.FlexLogger; +import org.openecomp.policy.common.logging.flexlogger.Logger; + + +public class XacmlPersistenceProperties { + // get an instance of logger + private static Logger logger = FlexLogger.getLogger(XacmlPersistenceProperties.class); + /* + * xacmlPersistence.properties parameter key values + */ + public static final String DB_DRIVER = "javax.persistence.jdbc.driver"; + public static final String DB_DATA_SOURCE = "hibernate.dataSource"; + public static final String DB_URL = "javax.persistence.jdbc.url"; + public static final String DB_USER = "javax.persistence.jdbc.user"; + public static final String DB_PWD = "javax.persistence.jdbc.password"; + + private static Properties properties = null; + /* + * Initialize the parameter values from the droolsPersitence.properties file values + * + * This is designed so that the Properties object is obtained from the xacmlPersistence.properties + * file and then is passed to this method to initialize the value of the parameters. + * This allows the flexibility of JUnit tests using getProperties(filename) to get the + * properties while runtime methods can use getPropertiesFromClassPath(filename). + * + */ + public static void initProperties (Properties prop){ + logger.info("XacmlPersistenceProperties.initProperties(Properties): entry"); + logger.info("\n\nXacmlPersistenceProperties.initProperties: Properties = \n" + prop + "\n\n"); + + properties = prop; + } + + public static String getProperty(String key){ + return properties.getProperty(key); + } + + public static Properties getProperties() { + return properties; + } +} diff --git a/policy-persistence/src/main/resources/META-INF/services/org.openecomp.policy.drools.core.FeatureAPI b/policy-persistence/src/main/resources/META-INF/services/org.openecomp.policy.drools.core.FeatureAPI new file mode 100644 index 00000000..540a4bd4 --- /dev/null +++ b/policy-persistence/src/main/resources/META-INF/services/org.openecomp.policy.drools.core.FeatureAPI @@ -0,0 +1 @@ +org.openecomp.policy.drools.persistence.PersistenceFeature diff --git a/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/IntegrityAuditIntegrationTest.java b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/IntegrityAuditIntegrationTest.java new file mode 100644 index 00000000..6b654732 --- /dev/null +++ b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/IntegrityAuditIntegrationTest.java @@ -0,0 +1,279 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.controller.test; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Date; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import org.openecomp.policy.common.logging.eelf.PolicyLogger; +import org.openecomp.policy.common.ia.IntegrityAudit; +import org.openecomp.policy.common.im.AdministrativeStateException; +import org.openecomp.policy.common.im.IntegrityMonitor; +import org.openecomp.policy.common.im.StandbyStatusException; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.drools.core.DroolsPDPIntegrityMonitor; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.drools.core.PolicyContainer; +import org.openecomp.policy.drools.im.PMStandbyStateChangeNotifier; +import org.openecomp.policy.drools.persistence.DroolsPdpEntity; +import org.openecomp.policy.drools.persistence.DroolsPdpImpl; +import org.openecomp.policy.drools.persistence.DroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.JpaDroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.DroolsPersistenceProperties; +import org.openecomp.policy.drools.persistence.PersistenceFeature; +import org.openecomp.policy.drools.persistence.XacmlPersistenceProperties; +import org.openecomp.policy.drools.system.Main; +import org.openecomp.policy.drools.system.PolicyEngine; + +/* + * Cloned from StandbyStateManagement.java in support of US673632. + * See MultiSite_v1-10.ppt, slide 38 + */ +public class IntegrityAuditIntegrationTest { + + + public static final String INTEGRITY_MONITOR_PROPERTIES_FILE="src/test/server/config/IntegrityMonitor.properties"; + + /* + * Currently, the DroolsPdpsElectionHandler.DesignationWaiter is invoked every ten seconds, starting + * at ten seconds after the minute boundary (e.g. 13:05:10). So, an 80 second sleep should be + * sufficient to ensure that we wait for the DesignationWaiter to do its job, before + * checking the results. + */ + private long sleepTime = 80000; + + /* + * Sleep 5 seconds after each test to allow interrupt (shutdown) recovery. + */ + private long interruptRecoveryTime = 5000; + + /* + * See the IntegrityMonitor.getJmxUrl() method for the rationale behind this jmx related processing. + */ + @BeforeClass + public static void setUpClass() throws Exception { + + PolicyLogger.info("setUpClass: Entering"); + + String userDir = System.getProperty("user.dir"); + PolicyLogger.debug("setUpClass: userDir=" + userDir); + System.setProperty("com.sun.management.jmxremote.port", "9980"); + System.setProperty("com.sun.management.jmxremote.authenticate","false"); + + // Make sure path to config directory is set correctly in PolicyContainer.main + // Also make sure we ignore HTTP server failures resulting from port conflicts. + PolicyContainer.isUnitTesting = true; + + /* + * Setting isUnitTesting to true ensures + * + * 1) That we load test version of properties files + * + * and + * + * 2) that we use dbAuditSimulate() method, because all we care about + * for this JUnit testing is that the audits are executed. + */ + IntegrityAudit.isUnitTesting = true; + + initializeDb(); + + PolicyLogger.info("setUpClass: Exiting"); + + } + + @AfterClass + public static void tearDownClass() throws Exception { + + } + + @Before + public void setUp() throws Exception { + + } + + @After + public void tearDown() throws Exception { + + } + + + /* + * Verifies that audit thread starts successfully. + */ + //@Ignore + @Test + public void testAuditInit() throws Exception { + + PolicyLogger.debug("\n\ntestAuditInit: Entering\n\n"); + + PolicyLogger.debug("testAuditInit: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + INTEGRITY_MONITOR_PROPERTIES_FILE))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testAuditInit: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testAuditInit: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testAuditInit: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testAuditInit: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testAuditInit: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as designated. Initial standby state will be + * either null or cold standby. + */ + PolicyLogger.debug("testAuditInit: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testAuditInit: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + PolicyLogger.debug("testAuditInit: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testAuditInit: Running policy-management.Main class, designated=" + + conn.getPdp(thisPdpId).isDesignated()); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testAuditInit: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + IntegrityAudit integrityAudit = PersistenceFeature.getIntegrityAudit(); + PolicyLogger.debug("testAuditInit: isThreadInitialized=" + integrityAudit.isThreadInitialized()); + assertTrue("AuditThread not initialized!?",integrityAudit.isThreadInitialized()); + + PolicyLogger.debug("testAuditInit: Stopping auditThread"); + integrityAudit.stopAuditThread(); + Thread.sleep(1000); + //This will interrupt thread. However, the thread will not die. It keeps on ticking and trying to + //run the audit. + assertTrue("AuditThread not still running after stopAuditThread invoked!?",integrityAudit.isThreadInitialized()); + + PolicyLogger.debug("testAuditInit: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestAuditInit: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * This method initializes and cleans the DB so that PDP-D will be able to + * store IntegrityAuditEntity in the DB. + */ + public static void initializeDb(){ + + PolicyLogger.debug("initializeDb: Entering"); + + Properties cleanProperties = new Properties(); + cleanProperties.put(DroolsPersistenceProperties.DB_DRIVER,"org.h2.Driver"); + cleanProperties.put(DroolsPersistenceProperties.DB_URL, "jdbc:h2:file:./sql/drools"); + cleanProperties.put(DroolsPersistenceProperties.DB_USER, "sa"); + cleanProperties.put(DroolsPersistenceProperties.DB_PWD, ""); + //EntityManagerFactory emf = Persistence.createEntityManagerFactory("schemaPU", cleanProperties); + EntityManagerFactory emf = Persistence.createEntityManagerFactory("junitDroolsPU", cleanProperties); + + EntityManager em = emf.createEntityManager(); + // Start a transaction + EntityTransaction et = em.getTransaction(); + + et.begin(); + + // Clean up the DB + em.createQuery("Delete from IntegrityAuditEntity").executeUpdate(); + + // commit transaction + et.commit(); + em.close(); + + PolicyLogger.debug("initializeDb: Exiting"); + } + + private class PolicyManagementRunner extends Thread { + + public void run() { + PolicyLogger.info("PolicyManagementRunner.run: Entering"); + String args[] = { "src/main/server/config" }; + try { + Main.main(args); + } catch (Exception e) { + PolicyLogger + .info("PolicyManagementRunner.run: Exception thrown from Main.main(), message=" + + e.getMessage()); + } + PolicyLogger.info("PolicyManagementRunner.run: Exiting"); + } + + public void stopRunner() { + PolicyEngine.manager.shutdown(); + } + + } + +} diff --git a/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/ResiliencyTestCases.java b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/ResiliencyTestCases.java new file mode 100644 index 00000000..f58d304e --- /dev/null +++ b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/ResiliencyTestCases.java @@ -0,0 +1,1267 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.controller.test; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Date; +import java.util.Properties; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityTransaction; +import javax.persistence.Persistence; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import org.openecomp.policy.common.logging.eelf.PolicyLogger; +import org.openecomp.policy.common.im.AdministrativeStateException; +import org.openecomp.policy.common.im.IntegrityMonitor; +import org.openecomp.policy.common.im.StandbyStatusException; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.drools.core.DroolsPDPIntegrityMonitor; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.drools.core.PolicyContainer; +import org.openecomp.policy.drools.im.PMStandbyStateChangeNotifier; +import org.openecomp.policy.drools.persistence.DroolsPdp; +import org.openecomp.policy.drools.persistence.DroolsPdpEntity; +import org.openecomp.policy.drools.persistence.DroolsPdpImpl; +import org.openecomp.policy.drools.persistence.DroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.JpaDroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.DroolsPersistenceProperties; +import org.openecomp.policy.drools.persistence.XacmlPersistenceProperties; +import org.openecomp.policy.drools.system.Main; +import org.openecomp.policy.drools.system.PolicyEngine; + +import org.apache.commons.lang3.time.DateUtils; + +/* + * Cloned from StandbyStateManagement.java in support of US673632. + * See MultiSite_v1-10.ppt, slide 38 + */ +public class ResiliencyTestCases { + + /* + * Currently, the DroolsPdpsElectionHandler.DesignationWaiter is invoked every ten seconds, starting + * at ten seconds after the minute boundary (e.g. 13:05:10). So, an 80 second sleep should be + * sufficient to ensure that we wait for the DesignationWaiter to do its job, before + * checking the results. + */ + long sleepTime = 80000; + + /* + * DroolsPdpsElectionHandler runs every ten seconds, so a 15 second sleep should be + * plenty to ensure it has time to re-promote this PDP. + */ + long electionWaitSleepTime = 15000; + + /* + * Sleep 5 seconds after each test to allow interrupt (shutdown) recovery. + */ + long interruptRecoveryTime = 5000; + + /* + * See the IntegrityMonitor.getJmxUrl() method for the rationale behind this jmx related processing. + */ + @BeforeClass + public static void setUpClass() throws Exception { + + String userDir = System.getProperty("user.dir"); + PolicyLogger.debug("setUpClass: userDir=" + userDir); + System.setProperty("com.sun.management.jmxremote.port", "9980"); + System.setProperty("com.sun.management.jmxremote.authenticate","false"); + + // Make sure path to config directory is set correctly in PolicyContainer.main + // Also make sure we ignore HTTP server failures resulting from port conflicts. + PolicyContainer.isUnitTesting = true; + + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + + } + + public void cleanDroolsDB() throws Exception{ + PolicyLogger.debug("\n\ncleanDroolsDB: Entering\n\n"); + + PolicyLogger.debug("cleanDroolsDB: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + + PolicyLogger.debug("cleanDroolsDB: Creating emfDrools"); + EntityManagerFactory emf = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + PolicyLogger.debug("cleanDroolsDB: Cleaning up tables"); + + EntityManager em = emf.createEntityManager(); + EntityTransaction et = em.getTransaction(); + et.begin(); + + // Make sure the DB is clean + PolicyLogger.debug("cleanDroolsDB: clean DroolsPdpEntity"); + em.createQuery("DELETE FROM DroolsPdpEntity").executeUpdate(); + PolicyLogger.debug("cleanDroolsDB: clean DroolsSessionEntity"); + em.createQuery("DELETE FROM DroolsSessionEntity").executeUpdate(); + + em.flush(); + PolicyLogger.debug("cleanDroolsDB: after flush"); + + et.commit(); + + PolicyLogger.debug("\n\ncleanDroolsDB: Exiting\n\n"); + } + + public void cleanXacmlDB() throws Exception { + PolicyLogger.debug("\n\ncleanXacmlDB: Entering\n\n"); + + PolicyLogger.debug("cleanXacmlDB: Reading IntegrityMonitorProperties"); + + PolicyLogger.debug("cleanXacmlDB: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + + PolicyLogger.debug("cleanXacmlDB: Creating emf"); + EntityManagerFactory emf = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + EntityManager em = emf.createEntityManager(); + EntityTransaction et = em.getTransaction(); + et.begin(); + + // Make sure the DB is clean + PolicyLogger.debug("cleanXacmlDB: clean StateManagementEntity"); + em.createQuery("DELETE FROM StateManagementEntity").executeUpdate(); + PolicyLogger.debug("cleanXacmlDB: clean ResourceRegistrationEntity"); + em.createQuery("DELETE FROM ResourceRegistrationEntity").executeUpdate(); + PolicyLogger.debug("cleanXacmlDB: clean ForwardProgressEntity"); + em.createQuery("DELETE FROM ForwardProgressEntity").executeUpdate(); + + em.flush(); + PolicyLogger.debug("cleandXacmlDB: after flush"); + + et.commit(); + + PolicyLogger.debug("\n\ncleanXacmlDB: Exiting\n\n"); + + } + + @Ignore + @Test + public void singleNodeTests() throws Exception{ + //snNewInstall(); + snNewInstallBadDepData(); + /*snRecoveryFromBadDepData(); + snLock(); + snLockRestart(); + snUnlock(); + snUnlockRestart();*/ + } + + @Ignore + @Test + public void twoNodeTests() throws Exception{ + tnNewInstall(); + tnLockActive(); + tnUnlockColdStandby(); + tnFailActive(); + tnRecoverFailed(); + } + + @Ignore + @Test + public void twoSitesTwoNodesPerSiteTests() throws Exception{ + tstnNewInstall(); + tstnLock1Site1(); + tstnLock2Site1(); + tstnFailActiveSite2(); + tstnRecoverFailedSite2(); + tstnUnlockSite1(); + tstnFailSite2(); + } + + + /* + * Single Node Tests + */ + public void snNewInstall() throws Exception{ + PolicyLogger.debug("\n\nsnNewInstall: Entry\n\n"); + cleanDroolsDB(); + cleanXacmlDB(); + + //******************************************* + + PolicyLogger.debug("snNewInstall: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("snNewInstall: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("snNewInstall: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("snNewInstall: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("snNewInstall: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("snNewInstall: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdp pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("snNewInstall: After insertion, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * When the Standby Status changes (from providingservice) to hotstandby + * or coldstandby,the Active/Standby selection algorithm must stand down + * if thePDP-D is currently the lead/active node and allow another PDP-D + * to take over. + * + * It must also call lock on all engines in the engine management. + * + */ + PolicyLogger.debug("snNewInstall: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + PolicyLogger.debug("snNewInstall: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("snNewInstall: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("snNewInstall: Promoting PDP=" + thisPdpId); + sm.promote(); + + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("snNewInstall: Before locking, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + PolicyLogger.debug("snNewInstall: Locking sm"); + sm.lock(); + + Thread.sleep(interruptRecoveryTime); + /* + * Verify that the PDP is no longer designated. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("snNewInstall: After lock sm.lock() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("snNewInstall: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\nsnNewInstall: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + //******************************************** + + PolicyLogger.debug("\n\nsnNewInstall: Exit\n\n"); + } + + public void snNewInstallBadDepData() throws Exception{ + PolicyLogger.debug("\n\nsnNewInstallBadDepData: Entry\n\n"); + cleanDroolsDB(); + cleanXacmlDB(); + + //******************************************* + + PolicyLogger.debug("snNewInstallBadDepData: Reading IntegrityMonitor_BadDependencyData.properties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor_BadDependencyData.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("snNewInstallBadDepData: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("snNewInstallBadDepData: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("snNewInstallBadDepData: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("snNewInstallBadDepData: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("snNewInstallBadDepData: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdp pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + //PolicyLogger.debug + System.out.println + ("\n\nsnNewInstallBadDepData: After insertion, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId + "\n\n********************"); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * When the Standby Status changes (from providingservice) to hotstandby + * or coldstandby,the Active/Standby selection algorithm must stand down + * if thePDP-D is currently the lead/active node and allow another PDP-D + * to take over. + */ + PolicyLogger.debug("snNewInstall: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + PolicyLogger.debug("snNewInstall: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("snNewInstall: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("snNewInstall: Promoting PDP=" + thisPdpId); + sm.promote(); + + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("snNewInstall: Before locking, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + /* + * Verify that the PDP is no longer designated. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("snNewInstall: After lock sm.lock() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("snNewInstall: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\nsnNewInstall: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + //******************************************** + + PolicyLogger.debug("\n\nsnNewInstallBadDepData: Exit\n\n"); + } + + public void snRecoveryFromBadDepData() throws Exception{ + + } + + public void snLock() throws Exception { + + } + + public void snLockRestart() throws Exception { + + } + + public void snUnlock() throws Exception { + + } + + public void snUnlockRestart() throws Exception { + + } + + /* + * Two Nodes tests + */ + public void tnNewInstall() throws Exception { + + } + + public void tnLockActive() throws Exception { + + } + + public void tnUnlockColdStandby() throws Exception { + + } + + public void tnFailActive() throws Exception { + + } + + public void tnRecoverFailed() throws Exception { + + } + + /* + * Two Sites, Two Nodes Each Site tests + */ + + public void tstnNewInstall() throws Exception { + + } + + public void tstnLock1Site1() throws Exception { + + } + + public void tstnLock2Site1() throws Exception { + + } + + public void tstnFailActiveSite2() throws Exception { + + } + + public void tstnRecoverFailedSite2() throws Exception { + + } + + public void tstnUnlockSite1() throws Exception { + + } + + public void tstnFailSite2() throws Exception { + + } + + + @Ignore + @Test + public void testColdStandby() throws Exception { + + PolicyLogger.debug("\n\ntestColdStandby: Entering\n\n"); + + PolicyLogger.debug("testColdStandby: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testColdStandby: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testColdStandby: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + PolicyLogger.debug("testColdStandby: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdp pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testColdStandby: After insertion, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * When the Standby Status changes (from providingservice) to hotstandby + * or coldstandby,the Active/Standby selection algorithm must stand down + * if thePDP-D is currently the lead/active node and allow another PDP-D + * to take over. + * + * It must also call lock on all engines in the engine management. + * + * Yes, this is kludgy, but we have a chicken and egg problem here: we + * need a StateManagement object to invoke the + * deleteAllStateManagementEntities method. + */ + PolicyLogger.debug("testColdStandby: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + PolicyLogger.debug("testColdStandby: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testColdStandby: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testColdStandby: Promoting PDP=" + thisPdpId); + sm.promote(); + + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testColdStandby: Before locking, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + PolicyLogger.debug("testColdStandby: Locking sm"); + sm.lock(); + + Thread.sleep(interruptRecoveryTime); + /* + * Verify that the PDP is no longer designated. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testColdStandby: After lock sm.lock() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testColdStandby: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestColdStandby: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * Tests hot standby when there is only one PDP. + */ + @Ignore + @Test + public void testHotStandby1() throws Exception { + + PolicyLogger.debug("\n\ntestHotStandby1: Entering\n\n"); + + PolicyLogger.debug("testHotStandby1: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testHotStandby1: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testHotStandby1: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.debug("testHotStandby1: Inserting PDP=" + thisPdpId + " as not designated"); + Date yesterday = DateUtils.addDays(new Date(), -1); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby1: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testHotStandby1: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testHotStandby1: Demoting PDP=" + thisPdpId); + // demoting should cause state to transit to hotstandby + sm.demote(); + + PolicyLogger.debug("testHotStandby1: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testHotStandby1: Sleeping " + + sleepTime + + "ms, to allow JpaDroolsPdpsConnector time to check droolspdpentity table"); + Thread.sleep(sleepTime); + + /* + * Verify that this formerly un-designated PDP in HOT_STANDBY is now designated and providing service. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby1: After sm.demote() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testHotStandby1: After demotion, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + assertTrue(standbyStatus != null && standbyStatus.equals(StateManagement.PROVIDING_SERVICE)); + + PolicyLogger.debug("testHotStandby1: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestHotStandby1: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * Tests hot standby when two PDPs are involved. + */ + @Ignore + @Test + public void testHotStandby2() throws Exception { + + PolicyLogger.debug("\n\ntestHotStandby2: Entering\n\n"); + + PolicyLogger.debug("testHotStandby2: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testHotStandby2: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby2: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby2: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testHotStandby2: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testHotStandby2: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert a PDP that's designated but not current. + */ + String activePdpId = "pdp2"; + PolicyLogger.debug("testHotStandby2: Inserting PDP=" + activePdpId + " as stale, designated PDP"); + Date yesterday = DateUtils.addDays(new Date(), -1); + DroolsPdp pdp = new DroolsPdpImpl(activePdpId, true, 4, yesterday); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(activePdpId); + PolicyLogger.debug("testHotStandby2: After insertion, PDP=" + activePdpId + ", which is not current, has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * Promote the designated PDP. + * + * We have a chicken and egg problem here: we need a StateManagement + * object to invoke the deleteAllStateManagementEntities method. + */ + PolicyLogger.debug("testHotStandy2: Promoting PDP=" + activePdpId); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, activePdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + /* + * Insert this PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.debug("testHotStandby2: Inserting PDP=" + thisPdpId + " as not designated"); + pdp = new DroolsPdpImpl(thisPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby2: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testHotStandby2: Demoting PDP=" + thisPdpId); + StateManagement sm2 = new StateManagement(emfXacml, thisPdpId); + sm2.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testHotStandby2: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testHotStandby2: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting/demoting"); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testHotStandby2: Runner started; promoting PDP=" + activePdpId); + sm.promote(); + String standbyStatus = sm.getStandbyStatus(activePdpId); + PolicyLogger.debug("testHotStandby2: After promoting, PDP=" + activePdpId + " has standbyStatus=" + + standbyStatus); + + // demoting PDP should ensure that state transits to hotstandby + PolicyLogger.debug("testHotStandby2: Runner started; demoting PDP=" + thisPdpId); + sm2.demote(); + standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testHotStandby2: After demoting, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + PolicyLogger.debug("testHotStandby2: Sleeping " + + sleepTime + + "ms, to allow JpaDroolsPdpsConnector time to check droolspdpentity table"); + Thread.sleep(sleepTime); + + /* + * Verify that this PDP, demoted to HOT_STANDBY, is now + * re-designated and providing service. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby2: After demoting PDP=" + activePdpId + + ", DESIGNATED=" + droolsPdpEntity.isDesignated() + + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + standbyStatus = sm2.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testHotStandby2: After demoting PDP=" + activePdpId + + ", PDP=" + thisPdpId + " has standbyStatus=" + standbyStatus); + assertTrue(standbyStatus != null + && standbyStatus.equals(StateManagement.PROVIDING_SERVICE)); + + PolicyLogger.debug("testHotStandby2: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestHotStandby2: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * 1) Inserts and designates this PDP, then verifies that startTransaction + * is successful. + * + * 2) Demotes PDP, and verifies that because there is only one PDP, it will + * be immediately re-promoted, thus allowing startTransaction to be + * successful. + * + * 3) Locks PDP and verifies that startTransaction results in + * AdministrativeStateException. + * + * 4) Unlocks PDP and verifies that startTransaction results in + * StandbyStatusException. + * + * 5) Promotes PDP and verifies that startTransaction is once again + * successful. + */ + @Ignore + @Test + public void testLocking1() throws Exception { + + PolicyLogger.debug("testLocking1: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testLocking1: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking1: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking1: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testLocking1: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testLocking1: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as designated. Initial standby state will be + * either null or cold standby. + */ + PolicyLogger.debug("testLocking1: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testLocking1: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + PolicyLogger.debug("testLocking1: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testLocking1: Running policy-management.Main class, designated=" + + conn.getPdp(thisPdpId).isDesignated()); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testLocking1: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testLocking1: Promoting PDP=" + thisPdpId); + sm.promote(); + + PolicyLogger.debug("testLocking1: Sleeping " + + sleepTime + + "ms, to allow time for policy-management.Main class to come up, designated=" + + conn.getPdp(thisPdpId).isDesignated()); + Thread.sleep(sleepTime); + + PolicyLogger.debug("testLocking1: Waking up and invoking startTransaction on active PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = (DroolsPDPIntegrityMonitor) IntegrityMonitor + .getInstance(); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // demoting should cause state to transit to hotstandby, followed by re-promotion, + // since there is only one PDP. + PolicyLogger.debug("testLocking1: demoting PDP=" + thisPdpId); + sm = droolsPdpIntegrityMonitor.getStateManager(); + sm.demote(); + + PolicyLogger.debug("testLocking1: sleeping" + electionWaitSleepTime + + " to allow election handler to re-promote PDP=" + thisPdpId); + Thread.sleep(electionWaitSleepTime); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on re-promoted PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // locking should cause state to transit to cold standby + PolicyLogger.debug("testLocking1: locking PDP=" + thisPdpId); + sm.lock(); + + // Just to avoid any race conditions, sleep a little after locking + PolicyLogger.debug("testLocking1: Sleeping a few millis after locking, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on locked PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + PolicyLogger.error("testLocking1: startTransaction unexpectedly successful"); + assertTrue(false); + } catch (AdministrativeStateException e) { + PolicyLogger.debug("testLocking1: As expected, caught AdministrativeStateException, message=" + e.getMessage()); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } finally { + droolsPdpIntegrityMonitor.endTransaction(); + } + + // unlocking should cause state to transit to hot standby + PolicyLogger.debug("testLocking1: unlocking PDP=" + thisPdpId); + sm.unlock(); + + // Just to avoid any race conditions, sleep a little after locking + PolicyLogger.debug("testLocking1: Sleeping a few millis after unlocking, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on unlocked PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + PolicyLogger.error("testLocking1: startTransaction unexpectedly successful"); + assertTrue(false); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.debug("testLocking1: As expected, caught StandbyStatusException, message=" + e.getMessage()); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } finally { + droolsPdpIntegrityMonitor.endTransaction(); + } + + // promoting should cause state to transit to providing service + PolicyLogger.debug("testLocking1: promoting PDP=" + thisPdpId); + sm.promote(); + + // Just to avoid any race conditions, sleep a little after promoting + PolicyLogger.debug("testLocking1: Sleeping a few millis after promoting, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on promoted PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + PolicyLogger.debug("testLocking1: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestLocking1: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * 1) Inserts and designates this PDP, then verifies that startTransaction + * is successful. + * + * 2) Inserts another PDP in hotstandby. + * + * 3) Demotes this PDP, and verifies 1) that other PDP is not promoted (because one + * PDP cannot promote another PDP) and 2) that this PDP is re-promoted. + */ + @Ignore + @Test + public void testLocking2() throws Exception { + + PolicyLogger.debug("\n\ntestLocking2: Entering\n\n"); + + PolicyLogger.debug("testLocking2: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testLocking2: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking2: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking2: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testLocking2: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testLocking2: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.debug("testLocking2: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, true, 3, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testLocking2: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + PolicyLogger.debug("testLocking2: Instantiating stateManagement object and promoting PDP=" + thisPdpId); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + /* + * Insert another PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + String standbyPdpId = "pdp2"; + PolicyLogger.debug("testLocking2: Inserting PDP=" + standbyPdpId + " as not designated"); + Date yesterday = DateUtils.addDays(new Date(), -1); + pdp = new DroolsPdpImpl(standbyPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + droolsPdpEntity = conn.getPdp(standbyPdpId); + PolicyLogger.debug("testLocking2: After insertion, PDP=" + standbyPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testLocking2: Demoting PDP=" + standbyPdpId); + StateManagement sm2 = new StateManagement(emfXacml, standbyPdpId); + sm2.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testLocking2: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testLocking2: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting/demoting"); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testLocking2: Promoting PDP=" + thisPdpId); + sm.promote(); + + // demoting PDP should ensure that state transits to hotstandby + PolicyLogger.debug("testLocking2: Demoting PDP=" + standbyPdpId); + sm2.demote(); + + PolicyLogger.debug("testLocking2: Sleeping " + + sleepTime + + "ms, to allow time for policy-management.Main class to come up"); + Thread.sleep(sleepTime); + + PolicyLogger.debug("testLocking2: Waking up and invoking startTransaction on active PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = (DroolsPDPIntegrityMonitor) IntegrityMonitor + .getInstance(); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking2: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking2: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // demoting should cause state to transit to hotstandby followed by re-promotion. + PolicyLogger.debug("testLocking2: demoting PDP=" + thisPdpId); + sm = droolsPdpIntegrityMonitor.getStateManager(); + sm.demote(); + + PolicyLogger.debug("testLocking2: sleeping" + electionWaitSleepTime + + " to allow election handler to re-promote PDP=" + thisPdpId); + Thread.sleep(electionWaitSleepTime); + + PolicyLogger.debug("testLocking2: Waking up and invoking startTransaction on re-promoted PDP=" + + thisPdpId + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking2: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking2: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + PolicyLogger.debug("testLocking2: Verifying designated status for PDP=" + + standbyPdpId); + boolean standbyPdpDesignated = conn.getPdp(standbyPdpId).isDesignated(); + assertTrue(standbyPdpDesignated == false); + + PolicyLogger.debug("testLocking2: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestLocking2: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + private class PolicyManagementRunner extends Thread { + + public void run() { + PolicyLogger.debug("PolicyManagementRunner.run: Entering"); + String args[] = { "src/main/server/config" }; + try { + Main.main(args); + } catch (Exception e) { + PolicyLogger + .debug("PolicyManagementRunner.run: Exception thrown from Main.main(), message=" + + e.getMessage()); + } + PolicyLogger.debug("PolicyManagementRunner.run: Exiting"); + } + + public void stopRunner() { + PolicyEngine.manager.shutdown(); + } + + } + +} diff --git a/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/StandbyStateManagementTest.java b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/StandbyStateManagementTest.java new file mode 100644 index 00000000..af649866 --- /dev/null +++ b/policy-persistence/src/test/java/org/openecomp/policy/drools/controller/test/StandbyStateManagementTest.java @@ -0,0 +1,887 @@ +/*- + * ============LICENSE_START======================================================= + * policy-persistence + * ================================================================================ + * Copyright (C) 2017 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.openecomp.policy.drools.controller.test; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileInputStream; +import java.util.Date; +import java.util.Properties; + +import javax.persistence.EntityManagerFactory; +import javax.persistence.Persistence; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +import org.openecomp.policy.common.logging.eelf.PolicyLogger; +import org.openecomp.policy.common.im.AdministrativeStateException; +import org.openecomp.policy.common.im.IntegrityMonitor; +import org.openecomp.policy.common.im.StandbyStatusException; +import org.openecomp.policy.common.im.StateManagement; +import org.openecomp.policy.drools.core.DroolsPDPIntegrityMonitor; +import org.openecomp.policy.drools.core.IntegrityMonitorProperties; +import org.openecomp.policy.drools.core.PolicyContainer; +import org.openecomp.policy.drools.im.PMStandbyStateChangeNotifier; +import org.openecomp.policy.drools.persistence.DroolsPdp; +import org.openecomp.policy.drools.persistence.DroolsPdpEntity; +import org.openecomp.policy.drools.persistence.DroolsPdpImpl; +import org.openecomp.policy.drools.persistence.DroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.JpaDroolsPdpsConnector; +import org.openecomp.policy.drools.persistence.DroolsPersistenceProperties; +import org.openecomp.policy.drools.persistence.XacmlPersistenceProperties; +import org.openecomp.policy.drools.system.Main; +import org.openecomp.policy.drools.system.PolicyEngine; + +import org.apache.commons.lang3.time.DateUtils; + +/* + * Cloned from StandbyStateManagement.java in support of US673632. + * See MultiSite_v1-10.ppt, slide 38 + */ +public class StandbyStateManagementTest { + + /* + * Currently, the DroolsPdpsElectionHandler.DesignationWaiter is invoked every ten seconds, starting + * at ten seconds after the minute boundary (e.g. 13:05:10). So, an 80 second sleep should be + * sufficient to ensure that we wait for the DesignationWaiter to do its job, before + * checking the results. + */ + long sleepTime = 80000; + + /* + * DroolsPdpsElectionHandler runs every ten seconds, so a 15 second sleep should be + * plenty to ensure it has time to re-promote this PDP. + */ + long electionWaitSleepTime = 15000; + + /* + * Sleep 5 seconds after each test to allow interrupt (shutdown) recovery. + */ + long interruptRecoveryTime = 5000; + + /* + * See the IntegrityMonitor.getJmxUrl() method for the rationale behind this jmx related processing. + */ + @BeforeClass + public static void setUpClass() throws Exception { + + String userDir = System.getProperty("user.dir"); + PolicyLogger.debug("setUpClass: userDir=" + userDir); + System.setProperty("com.sun.management.jmxremote.port", "9980"); + System.setProperty("com.sun.management.jmxremote.authenticate","false"); + + // Make sure path to config directory is set correctly in PolicyContainer.main + // Also make sure we ignore HTTP server failures resulting from port conflicts. + PolicyContainer.isUnitTesting = true; + + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + + } + + @Ignore + @Test + public void testColdStandby() throws Exception { + + PolicyLogger.debug("\n\ntestColdStandby: Entering\n\n"); + + PolicyLogger.debug("testColdStandby: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testColdStandby: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testColdStandby: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testColdStandby: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + PolicyLogger.debug("testColdStandby: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdp pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testColdStandby: After insertion, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * When the Standby Status changes (from providingservice) to hotstandby + * or coldstandby,the Active/Standby selection algorithm must stand down + * if thePDP-D is currently the lead/active node and allow another PDP-D + * to take over. + * + * It must also call lock on all engines in the engine management. + * + * Yes, this is kludgy, but we have a chicken and egg problem here: we + * need a StateManagement object to invoke the + * deleteAllStateManagementEntities method. + */ + PolicyLogger.debug("testColdStandby: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + PolicyLogger.debug("testColdStandby: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testColdStandby: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testColdStandby: Promoting PDP=" + thisPdpId); + sm.promote(); + + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testColdStandby: Before locking, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + PolicyLogger.debug("testColdStandby: Locking sm"); + sm.lock(); + + Thread.sleep(interruptRecoveryTime); + /* + * Verify that the PDP is no longer designated. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testColdStandby: After lock sm.lock() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testColdStandby: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestColdStandby: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * Tests hot standby when there is only one PDP. + */ + @Ignore + @Test + public void testHotStandby1() throws Exception { + + PolicyLogger.debug("\n\ntestHotStandby1: Entering\n\n"); + + PolicyLogger.debug("testHotStandby1: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testHotStandby1: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testHotStandby1: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testHotStandby1: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.debug("testHotStandby1: Inserting PDP=" + thisPdpId + " as not designated"); + Date yesterday = DateUtils.addDays(new Date(), -1); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby1: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testHotStandby1: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testHotStandby1: Demoting PDP=" + thisPdpId); + // demoting should cause state to transit to hotstandby + sm.demote(); + + PolicyLogger.debug("testHotStandby1: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testHotStandby1: Sleeping " + + sleepTime + + "ms, to allow JpaDroolsPdpsConnector time to check droolspdpentity table"); + Thread.sleep(sleepTime); + + /* + * Verify that this formerly un-designated PDP in HOT_STANDBY is now designated and providing service. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testHotStandby1: After sm.demote() invoked, DESIGNATED=" + + droolsPdpEntity.isDesignated() + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + String standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.debug("testHotStandby1: After demotion, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + assertTrue(standbyStatus != null && standbyStatus.equals(StateManagement.PROVIDING_SERVICE)); + + PolicyLogger.debug("testHotStandby1: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestHotStandby1: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * Tests hot standby when two PDPs are involved. + */ + @Ignore + @Test + public void testHotStandby2() throws Exception { + + PolicyLogger.info("\n\ntestHotStandby2: Entering\n\n"); + + PolicyLogger.info("testHotStandby2: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.info("testHotStandby2: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.info("testHotStandby2: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.info("testHotStandby2: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.info("testHotStandby2: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.info("testHotStandby2: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert a PDP that's designated but not current. + */ + String activePdpId = "pdp2"; + PolicyLogger.info("testHotStandby2: Inserting PDP=" + activePdpId + " as stale, designated PDP"); + Date yesterday = DateUtils.addDays(new Date(), -1); + DroolsPdp pdp = new DroolsPdpImpl(activePdpId, true, 4, yesterday); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(activePdpId); + PolicyLogger.info("testHotStandby2: After insertion, PDP=" + activePdpId + ", which is not current, has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + /* + * Promote the designated PDP. + * + * We have a chicken and egg problem here: we need a StateManagement + * object to invoke the deleteAllStateManagementEntities method. + */ + PolicyLogger.info("testHotStandy2: Promoting PDP=" + activePdpId); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, activePdpId);//pdp2 + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + // Artificially putting a PDP into service is really a two step process, 1) + // inserting it as designated and 2) promoting it so that its standbyStatus + // is providing service. + + /* + * Insert this PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.info("testHotStandby2: Inserting PDP=" + thisPdpId + " as not designated"); + pdp = new DroolsPdpImpl(thisPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.info("testHotStandby2: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.info("testHotStandby2: Demoting PDP=" + thisPdpId);//pdp1 + StateManagement sm2 = new StateManagement(emfXacml, thisPdpId); + sm2.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.info("testHotStandby2: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); //pdp1 + policyManagementRunner.start(); + + PolicyLogger.info("testHotStandby2: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting/demoting"); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.info("testHotStandby2: Runner started; promoting PDP=" + activePdpId);//pdpd2xs + //at this point, the newly created pdp will have set the state to disabled/failed/cold standby + //because it is stale. So, it cannot be promoted. We need to call sm.enableNotFailed() so we + //can promote it and demote the other pdp - else the other pdp will just spring back to providingservice + sm.enableNotFailed();//pdp1 + sm.promote(); + String standbyStatus = sm.getStandbyStatus(activePdpId); + PolicyLogger.info("testHotStandby2: After promoting, PDP=" + activePdpId + " has standbyStatus=" + + standbyStatus); + + // demoting PDP should ensure that state transits to hotstandby + PolicyLogger.info("testHotStandby2: Runner started; demoting PDP=" + thisPdpId); + sm2.demote();//pdp1 + standbyStatus = sm.getStandbyStatus(thisPdpId); + PolicyLogger.info("testHotStandby2: After demoting, PDP=" + thisPdpId + " has standbyStatus=" + + standbyStatus); + + PolicyLogger.info("testHotStandby2: Sleeping " + + sleepTime + + "ms, to allow JpaDroolsPdpsConnector time to check droolspdpentity table"); + Thread.sleep(sleepTime); + + /* + * Verify that this PDP, demoted to HOT_STANDBY, is now + * re-designated and providing service. + */ + droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.info("testHotStandby2: After demoting PDP=" + activePdpId + + ", DESIGNATED=" + droolsPdpEntity.isDesignated() + + " for PDP=" + thisPdpId); + assertTrue(droolsPdpEntity.isDesignated() == true); + standbyStatus = sm2.getStandbyStatus(thisPdpId); + PolicyLogger.info("testHotStandby2: After demoting PDP=" + activePdpId + + ", PDP=" + thisPdpId + " has standbyStatus=" + standbyStatus); + assertTrue(standbyStatus != null + && standbyStatus.equals(StateManagement.PROVIDING_SERVICE)); + + PolicyLogger.info("testHotStandby2: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.info("\n\ntestHotStandby2: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * 1) Inserts and designates this PDP, then verifies that startTransaction + * is successful. + * + * 2) Demotes PDP, and verifies that because there is only one PDP, it will + * be immediately re-promoted, thus allowing startTransaction to be + * successful. + * + * 3) Locks PDP and verifies that startTransaction results in + * AdministrativeStateException. + * + * 4) Unlocks PDP and verifies that startTransaction results in + * StandbyStatusException. + * + * 5) Promotes PDP and verifies that startTransaction is once again + * successful. + */ + @Ignore + @Test + public void testLocking1() throws Exception { + + PolicyLogger.debug("testLocking1: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testLocking1: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking1: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking1: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testLocking1: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testLocking1: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as designated. Initial standby state will be + * either null or cold standby. + */ + PolicyLogger.debug("testLocking1: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, true, 4, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testLocking1: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + PolicyLogger.debug("testLocking1: Instantiating stateManagement object"); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testLocking1: Running policy-management.Main class, designated=" + + conn.getPdp(thisPdpId).isDesignated()); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testLocking1: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting PDP=" + + thisPdpId); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testLocking1: Promoting PDP=" + thisPdpId); + sm.promote(); + + PolicyLogger.debug("testLocking1: Sleeping " + + sleepTime + + "ms, to allow time for policy-management.Main class to come up, designated=" + + conn.getPdp(thisPdpId).isDesignated()); + Thread.sleep(sleepTime); + + PolicyLogger.debug("testLocking1: Waking up and invoking startTransaction on active PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = (DroolsPDPIntegrityMonitor) IntegrityMonitor + .getInstance(); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // demoting should cause state to transit to hotstandby, followed by re-promotion, + // since there is only one PDP. + PolicyLogger.debug("testLocking1: demoting PDP=" + thisPdpId); + sm = droolsPdpIntegrityMonitor.getStateManager(); + sm.demote(); + + PolicyLogger.debug("testLocking1: sleeping" + electionWaitSleepTime + + " to allow election handler to re-promote PDP=" + thisPdpId); + Thread.sleep(electionWaitSleepTime); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on re-promoted PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // locking should cause state to transit to cold standby + PolicyLogger.debug("testLocking1: locking PDP=" + thisPdpId); + sm.lock(); + + // Just to avoid any race conditions, sleep a little after locking + PolicyLogger.debug("testLocking1: Sleeping a few millis after locking, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on locked PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + PolicyLogger.error("testLocking1: startTransaction unexpectedly successful"); + assertTrue(false); + } catch (AdministrativeStateException e) { + PolicyLogger.debug("testLocking1: As expected, caught AdministrativeStateException, message=" + e.getMessage()); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } finally { + droolsPdpIntegrityMonitor.endTransaction(); + } + + // unlocking should cause state to transit to hot standby + PolicyLogger.debug("testLocking1: unlocking PDP=" + thisPdpId); + sm.unlock(); + + // Just to avoid any race conditions, sleep a little after locking + PolicyLogger.debug("testLocking1: Sleeping a few millis after unlocking, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on unlocked PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + PolicyLogger.error("testLocking1: startTransaction unexpectedly successful"); + assertTrue(false); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.debug("testLocking1: As expected, caught StandbyStatusException, message=" + e.getMessage()); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } finally { + droolsPdpIntegrityMonitor.endTransaction(); + } + + // promoting should cause state to transit to providing service + PolicyLogger.debug("testLocking1: promoting PDP=" + thisPdpId); + sm.promote(); + + // Just to avoid any race conditions, sleep a little after promoting + PolicyLogger.debug("testLocking1: Sleeping a few millis after promoting, to avoid race condition"); + Thread.sleep(100); + + PolicyLogger.debug("testLocking1: Invoking startTransaction on promoted PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking1: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking1: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking1: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + PolicyLogger.debug("testLocking1: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestLocking1: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + /* + * 1) Inserts and designates this PDP, then verifies that startTransaction + * is successful. + * + * 2) Inserts another PDP in hotstandby. + * + * 3) Demotes this PDP, and verifies 1) that other PDP is not promoted (because one + * PDP cannot promote another PDP) and 2) that this PDP is re-promoted. + */ + @Ignore + @Test + public void testLocking2() throws Exception { + + PolicyLogger.debug("\n\ntestLocking2: Entering\n\n"); + + PolicyLogger.debug("testLocking2: Reading IntegrityMonitorProperties"); + Properties integrityMonitorProperties = new Properties(); + integrityMonitorProperties.load(new FileInputStream(new File( + "src/test/server/config/IntegrityMonitor.properties"))); + IntegrityMonitorProperties.initProperties(integrityMonitorProperties); + String thisPdpId = IntegrityMonitorProperties + .getProperty(IntegrityMonitorProperties.PDP_INSTANCE_ID); + + PolicyLogger.debug("testLocking2: Reading xacmlPersistenceProperties"); + Properties xacmlPersistenceProperties = new Properties(); + xacmlPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/xacmlPersistence.properties"))); + XacmlPersistenceProperties.initProperties(xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking2: Creating emfXacml"); + EntityManagerFactory emfXacml = Persistence.createEntityManagerFactory( + "junitXacmlPU", xacmlPersistenceProperties); + + PolicyLogger.debug("testLocking2: Reading droolsPersistenceProperties"); + Properties droolsPersistenceProperties = new Properties(); + droolsPersistenceProperties.load(new FileInputStream(new File( + "src/test/server/config/droolsPersistence.properties"))); + DroolsPersistenceProperties.initProperties(droolsPersistenceProperties); + + PolicyLogger.debug("testLocking2: Creating emfDrools"); + EntityManagerFactory emfDrools = Persistence.createEntityManagerFactory( + "junitDroolsPU", droolsPersistenceProperties); + + DroolsPdpsConnector conn = new JpaDroolsPdpsConnector(emfDrools); + + PolicyLogger.debug("testLocking2: Cleaning up tables"); + conn.deleteAllSessions(); + conn.deleteAllPdps(); + + /* + * Insert this PDP as designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + PolicyLogger.debug("testLocking2: Inserting PDP=" + thisPdpId + " as designated"); + DroolsPdpImpl pdp = new DroolsPdpImpl(thisPdpId, true, 3, new Date()); + conn.insertPdp(pdp); + DroolsPdpEntity droolsPdpEntity = conn.getPdp(thisPdpId); + PolicyLogger.debug("testLocking2: After insertion, PDP=" + thisPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == true); + + PolicyLogger.debug("testLocking2: Instantiating stateManagement object and promoting PDP=" + thisPdpId); + StateManagement sm = new StateManagement(emfXacml, "dummy"); + sm.deleteAllStateManagementEntities(); + sm = new StateManagement(emfXacml, thisPdpId); + PMStandbyStateChangeNotifier pmStandbyStateChangeNotifier = new PMStandbyStateChangeNotifier(); + sm.addObserver(pmStandbyStateChangeNotifier); + + /* + * Insert another PDP as not designated. Initial standby state will be + * either null or cold standby. Demoting should transit state to + * hot standby. + */ + String standbyPdpId = "pdp2"; + PolicyLogger.debug("testLocking2: Inserting PDP=" + standbyPdpId + " as not designated"); + Date yesterday = DateUtils.addDays(new Date(), -1); + pdp = new DroolsPdpImpl(standbyPdpId, false, 4, yesterday); + conn.insertPdp(pdp); + droolsPdpEntity = conn.getPdp(standbyPdpId); + PolicyLogger.debug("testLocking2: After insertion, PDP=" + standbyPdpId + " has DESIGNATED=" + + droolsPdpEntity.isDesignated()); + assertTrue(droolsPdpEntity.isDesignated() == false); + + PolicyLogger.debug("testLocking2: Demoting PDP=" + standbyPdpId); + StateManagement sm2 = new StateManagement(emfXacml, standbyPdpId); + sm2.addObserver(pmStandbyStateChangeNotifier); + + PolicyLogger.debug("testLocking2: Running policy-management.Main class"); + PolicyManagementRunner policyManagementRunner = new PolicyManagementRunner(); + policyManagementRunner.start(); + + PolicyLogger.debug("testLocking2: Runner started; Sleeping " + + interruptRecoveryTime + "ms before promoting/demoting"); + Thread.sleep(interruptRecoveryTime); + + PolicyLogger.debug("testLocking2: Promoting PDP=" + thisPdpId); + sm.promote(); + + // demoting PDP should ensure that state transits to hotstandby + PolicyLogger.debug("testLocking2: Demoting PDP=" + standbyPdpId); + sm2.demote(); + + PolicyLogger.debug("testLocking2: Sleeping " + + sleepTime + + "ms, to allow time for policy-management.Main class to come up"); + Thread.sleep(sleepTime); + + PolicyLogger.debug("testLocking2: Waking up and invoking startTransaction on active PDP=" + + thisPdpId + + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + DroolsPDPIntegrityMonitor droolsPdpIntegrityMonitor = (DroolsPDPIntegrityMonitor) IntegrityMonitor + .getInstance(); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking2: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking2: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + // demoting should cause state to transit to hotstandby followed by re-promotion. + PolicyLogger.debug("testLocking2: demoting PDP=" + thisPdpId); + sm = droolsPdpIntegrityMonitor.getStateManager(); + sm.demote(); + + PolicyLogger.debug("testLocking2: sleeping" + electionWaitSleepTime + + " to allow election handler to re-promote PDP=" + thisPdpId); + Thread.sleep(electionWaitSleepTime); + + PolicyLogger.debug("testLocking2: Waking up and invoking startTransaction on re-promoted PDP=" + + thisPdpId + ", designated=" + + conn.getPdp(thisPdpId).isDesignated()); + try { + droolsPdpIntegrityMonitor.startTransaction(); + droolsPdpIntegrityMonitor.endTransaction(); + PolicyLogger.debug("testLocking2: As expected, transaction successful"); + } catch (AdministrativeStateException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught AdministrativeStateException, message=" + e.getMessage()); + assertTrue(false); + } catch (StandbyStatusException e) { + PolicyLogger.error("testLocking2: Unexpectedly caught StandbyStatusException, message=" + e.getMessage()); + assertTrue(false); + } catch (Exception e) { + PolicyLogger.error("testLocking2: Unexpectedly caught Exception, message=" + e.getMessage()); + assertTrue(false); + } + + PolicyLogger.debug("testLocking2: Verifying designated status for PDP=" + + standbyPdpId); + boolean standbyPdpDesignated = conn.getPdp(standbyPdpId).isDesignated(); + assertTrue(standbyPdpDesignated == false); + + PolicyLogger.debug("testLocking2: Stopping policyManagementRunner"); + policyManagementRunner.stopRunner(); + + PolicyLogger.debug("\n\ntestLocking2: Exiting\n\n"); + Thread.sleep(interruptRecoveryTime); + + } + + private class PolicyManagementRunner extends Thread { + + public void run() { + PolicyLogger.info("PolicyManagementRunner.run: Entering"); + String args[] = { "src/main/server/config" }; + try { + Main.main(args); + } catch (Exception e) { + PolicyLogger + .info("PolicyManagementRunner.run: Exception thrown from Main.main(), message=" + + e.getMessage()); + } + PolicyLogger.info("PolicyManagementRunner.run: Exiting"); + } + + public void stopRunner() { + PolicyEngine.manager.shutdown(); + } + + } + +} diff --git a/policy-persistence/src/test/resources/IntegrityMonitor.properties b/policy-persistence/src/test/resources/IntegrityMonitor.properties new file mode 100644 index 00000000..0ab36286 --- /dev/null +++ b/policy-persistence/src/test/resources/IntegrityMonitor.properties @@ -0,0 +1,67 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +#hostPort = ${{host_port}} +hostPort = 0.0.0.0:9981 + +# The following were added as part of US673632 +# +# Forward Progress Monitor update interval seconds +fp_monitor_interval = 30 +# Failed counter threshold before failover +failed_counter_threshold = 3 +# Interval between test transactions when no traffic seconds +test_trans_interval = 10 +# Interval between writes of the FPC to the DB seconds +write_fpc_interval = 5 +# Name of the site in which this node is hosted +site_name = pdp_1 +# Node type +# Note: Make sure you don't leave any trailing spaces, or you'll get an 'invalid node type' error! +node_type = pdp_drools +# Dependency groups are groups of resources upon which a node operational state is dependent upon. +# Each group is a comma-separated list of resource names and groups are separated by a semicolon. For example: +#dependency_groups=site_1.astra_1,site_1.astra_2;site_1.brms_1,site_1.brms_2;site_1.logparser_1;site_1.pypdp_1 +#dependency_groups=${{dependency_groups}} +dependency_groups="" +# When set to true, dependent health checks are performed by using JMX to invoke test() on the dependent. +# The default false is to use state checks for health. +#test_via_jmx=${{test_via_jmx}} +# This is the max number of seconds beyond which a non incrementing FPC is considered a failure +#max_fpc_update_interval=${{max_fpc_update_interval}} + +# Needed by DroolsPdpsElectionHandler +pdp.checkInterval=1500 +pdp.updateInterval=1000 +#pdp.timeout=3000 +# Need long timeout, because testTransaction is only run every 10 seconds. +pdp.timeout=15000 +#how long do we wait for the pdp table to populate on initial startup +pdp.initialWait=20000 + +# Known as the PDPID in the droolpdpentity table. +resource.name=pdp1 +#resource.name=${{resource_name}} + + + + + + diff --git a/policy-persistence/src/test/resources/META-INF/persistence.xml b/policy-persistence/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000..51ec1613 --- /dev/null +++ b/policy-persistence/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ============LICENSE_START======================================================= + policy-persistence + ================================================================================ + Copyright (C) 2017 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========================================================= + --> + +<persistence version="2.1" + xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"> + + <persistence-unit name="junitDroolsPU" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + <class>org.openecomp.policy.drools.persistence.DroolsPdpEntity</class> + <class>org.openecomp.policy.drools.persistence.DroolsSessionEntity</class> + <class>org.openecomp.policy.drools.persistence.LastSiteEntity</class> + <class>org.drools.persistence.info.SessionInfo</class> + <class>org.drools.persistence.info.WorkItemInfo</class> + <class>org.openecomp.policy.common.ia.jpa.IntegrityAuditEntity</class> + <properties> + <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> + <property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/> + <property name="javax.persistence.schema-generation.scripts.create-target" value="./sql/generatedCreateDrools.ddl"/> + <property name="javax.persistence.schema-generation.scripts.drop-target" value="./sql/generatedDropDrools.ddl"/> + </properties> + </persistence-unit> + + <persistence-unit name="junitXacmlPU" transaction-type="RESOURCE_LOCAL"> + <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> + <class>org.openecomp.policy.common.im.jpa.StateManagementEntity</class> + <class>org.openecomp.policy.common.im.jpa.ForwardProgressEntity</class> + <class>org.openecomp.policy.common.im.jpa.ResourceRegistrationEntity</class> + <class>org.openecomp.policy.common.ia.jpa.IntegrityAuditEntity</class> + <properties> + <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> + <property name="javax.persistence.schema-generation.scripts.action" value="drop-and-create"/> + <property name="javax.persistence.schema-generation.scripts.create-target" value="./sql/generatedCreateXacml.ddl"/> + <property name="javax.persistence.schema-generation.scripts.drop-target" value="./sql/generatedDropXacml.ddl"/> + </properties> + </persistence-unit> + +</persistence> diff --git a/policy-persistence/src/test/resources/droolsPersistence.properties b/policy-persistence/src/test/resources/droolsPersistence.properties new file mode 100644 index 00000000..544e1c23 --- /dev/null +++ b/policy-persistence/src/test/resources/droolsPersistence.properties @@ -0,0 +1,51 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +javax.persistence.jdbc.driver = org.h2.Driver +javax.persistence.jdbc.url = jdbc:h2:file:./sql/drools +javax.persistence.jdbc.user = sa +javax.persistence.jdbc.password = + +#javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver +#javax.persistence.jdbc.url=jdbc:mariadb://localhost:3306/drools +#javax.persistence.jdbc.user=root +#javax.persistence.jdbc.password=policy + +#javax.persistence.jdbc.driver = ${{JDBC_DRIVER}} +#javax.persistence.jdbc.url = ${{JDBC_DROOLS_URL}} +#javax.persistence.jdbc.user = ${{JDBC_USER}} +#javax.persistence.jdbc.password = ${{JDBC_PASSWORD}} + +# Needed? +#javax.persistence.jdbc.driver = org.h2.Driver +#javax.persistence.jdbc.url = jdbc:h2:file:./sql/ncomp +#javax.persistence.jdbc.user = sa +#javax.persistence.jdbc.password = +#persistenceDisabled=false +#javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver +#javax.persistence.jdbc.url=jdbc:mariadb://192.168.56.30:3306/drools +#javax.persistence.jdbc.user=patb +#javax.persistence.jdbc.password=policy + +hibernate.dataSource=org.mariadb.jdbc.MySQLDataSource + +# For testing purposes, it may be convenient to disable persistence +persistenceDisabled=false + diff --git a/policy-persistence/src/test/resources/log4j.properties b/policy-persistence/src/test/resources/log4j.properties new file mode 100644 index 00000000..746d59a0 --- /dev/null +++ b/policy-persistence/src/test/resources/log4j.properties @@ -0,0 +1,31 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +log4j.rootLogger=DEBUG, out +log4j.logger.com.att=DEBUG +log4j.logger.org.openecomp.policy.drools.system=DEBUG +log4j.logger.org.openecomp.policy.drools.im=DEBUG +log4j.logger.org.openecomp.policy.common.im=DEBUG +log4j.logger.org.openecomp.policy.drools.event.comm=DEBUG + +# CONSOLE appender not used by default +log4j.appender.out=org.apache.log4j.ConsoleAppender +log4j.appender.out.layout=org.apache.log4j.PatternLayout +log4j.appender.out.layout.ConversionPattern=%d %-5p %-30.30c{1} %4L - %m%n diff --git a/policy-persistence/src/test/resources/logback.xml b/policy-persistence/src/test/resources/logback.xml new file mode 100644 index 00000000..9fd83e8d --- /dev/null +++ b/policy-persistence/src/test/resources/logback.xml @@ -0,0 +1,209 @@ +<!-- + ============LICENSE_START======================================================= + policy-persistence + ================================================================================ + Copyright (C) 2017 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========================================================= + --> + +<!-- Controls the output of logs for JUnit tests --> + +<configuration scan="true" scanPeriod="3 seconds" debug="true"> + <!--<jmxConfigurator /> --> + <!-- directory path for all other type logs --> + <property name="logDir" value="testingLogs" /> + + <!-- directory path for debugging type logs --> + <property name="debugDir" value="testingLogs" /> + + <!-- specify the component name + <ECOMP-component-name>::= "MSO" | "DCAE" | "ASDC " | "AAI" |"Policy" | "SDNC" | "AC" --> + <property name="componentName" value="drools-pdp"></property> + <property name="subComponentName" value="policy-management"></property> + + <!-- log file names --> + <property name="errorLogName" value="error" /> + <property name="metricsLogName" value="metrics" /> + <property name="auditLogName" value="audit" /> + <property name="debugLogName" value="debug" /> + + <property name="defaultPattern" value="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}|%X{requestId}|%X{serviceInstanceId}|%t|%X{serverName}|%X{serviceName}|%X{instanceUuid}|%p|%X{severity}|%X{serverIpAddress}|%X{server}|%X{clientIpAddress}|%c||%msg%n" /> + <!-- <property name="defaultPattern" value="%d{"yyyy-MM-dd'T'HH:mm:ss.SSSXXX", UTC}|%X{RequestId}|%X{ServiceInstanceId}|%thread||%X{ServiceName}|%X{InstanceUUID}|%.-5level|%X{AlertSeverity}|%X{ServerIPAddress}|%X{ServerFQDN}|%X{RemoteHost}||%X{Timer}|%msg%n" /> --> + <property name="logDirectory" value="${logDir}/${componentName}/${subComponentName}" /> + <property name="debugLogDirectory" value="${debugDir}/${componentName}/${subComponentName}" /> + <!-- + <property name="logDirectory" value="${logDir}/${componentName}/${subComponentName}" /> + <property name="debugLogDirectory" value="${debugDir}/${componentName}/${subComponentName}" /> + --> + <!-- example from old log4j.properties: ${catalina.base}/logs/pdp-rest.log --> + + <!-- Example evaluator filter applied against console appender --> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <!-- ============================================================================ --> + <!-- EELF Appenders --> + <!-- ============================================================================ --> + + <!-- The EELFAppender is used to record events to the general application + log --> + + + + + <!-- EELF Audit Appender. This appender is used to record audit engine + related logging events. The audit logger and appender are specializations + of the EELF application root logger and appender. This can be used to segregate + Policy engine events from other components, or it can be eliminated to record + these events as part of the application root log. --> + + <appender name="EELFAudit" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${auditLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${auditLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + <appender name="asyncEELFAudit" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFAudit" /> + </appender> + +<appender name="EELFMetrics" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${metricsLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${metricsLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <!-- <pattern>"%d{HH:mm:ss.SSS} [%thread] %-5level %logger{1024} - + %msg%n"</pattern> --> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + + <appender name="asyncEELFMetrics" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFMetrics"/> + </appender> + + <appender name="EELFError" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${logDirectory}/${errorLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${logDirectory}/${errorLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <level>ERROR</level> + </filter> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFError" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFError"/> + </appender> + + <appender name="EELFDebug" + class="ch.qos.logback.core.rolling.RollingFileAppender"> + <file>${debugLogDirectory}/${debugLogName}.log</file> + <rollingPolicy + class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> + <fileNamePattern>${debugLogDirectory}/${debugLogName}.%i.log.zip + </fileNamePattern> + <minIndex>1</minIndex> + <maxIndex>9</maxIndex> + </rollingPolicy> + <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> + <!-- <level>INFO</level> --> + <level>DEBUG</level> + </filter> + <triggeringPolicy + class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> + <maxFileSize>5MB</maxFileSize> + </triggeringPolicy> + <encoder> + <pattern>${defaultPattern}</pattern> + </encoder> + </appender> + + <appender name="asyncEELFDebug" class="ch.qos.logback.classic.AsyncAppender"> + <queueSize>256</queueSize> + <appender-ref ref="EELFDebug" /> + <includeCallerData>true</includeCallerData> + </appender> + + + <!-- ============================================================================ --> + <!-- EELF loggers --> + <!-- ============================================================================ --> + + <logger name="com.att.eelf.audit" level="info" additivity="false"> + <appender-ref ref="asyncEELFAudit" /> + </logger> + + <logger name="com.att.eelf.metrics" level="info" additivity="false"> + <appender-ref ref="asyncEELFMetrics" /> + </logger> + + <logger name="com.att.eelf.error" level="error" additivity="false"> + <appender-ref ref="asyncEELFError" /> + </logger> + + <!-- <logger name="com.att.eelf.debug" level="info" additivity="false"> --> + <logger name="com.att.eelf.debug" level="debug" additivity="false"> + <appender-ref ref="asyncEELFDebug" /> + </logger> + + <!-- <root level="INFO"> --> + <root level="DEBUG"> + <appender-ref ref="asyncEELFDebug" /> + <appender-ref ref="asyncEELFError" /> + </root> + +</configuration> diff --git a/policy-persistence/src/test/resources/xacmlPersistence.properties b/policy-persistence/src/test/resources/xacmlPersistence.properties new file mode 100644 index 00000000..284e87d7 --- /dev/null +++ b/policy-persistence/src/test/resources/xacmlPersistence.properties @@ -0,0 +1,43 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +javax.persistence.jdbc.driver = org.h2.Driver +javax.persistence.jdbc.url = jdbc:h2:file:./sql/xacml +javax.persistence.jdbc.user = sa +javax.persistence.jdbc.password = + +#javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver +#javax.persistence.jdbc.url=jdbc:mariadb://127.0.0.1:3306/xacml +#javax.persistence.jdbc.user=root +#javax.persistence.jdbc.password=policy + +#javax.persistence.jdbc.driver = ${{JDBC_DRIVER}} +#javax.persistence.jdbc.url = ${{JDBC_URL}} +#javax.persistence.jdbc.user = ${{JDBC_USER}} +#javax.persistence.jdbc.password = ${{JDBC_PASSWORD}} + +# Needed? +hibernate.dataSource=org.mariadb.jdbc.MySQLDataSource + +# For testing purposes, it may be convenient to disable persistence +persistenceDisabled=false + + + diff --git a/policy-persistence/src/test/server/config/IntegrityMonitor.properties b/policy-persistence/src/test/server/config/IntegrityMonitor.properties new file mode 100644 index 00000000..b16beda9 --- /dev/null +++ b/policy-persistence/src/test/server/config/IntegrityMonitor.properties @@ -0,0 +1,62 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +# port 9981 fails on Jenkins, so try another. +hostPort = 0.0.0.0:57692 + +# The following were added as part of US673632 +# +# Forward Progress Monitor update interval seconds +fp_monitor_interval = 30 +# Failed counter threshold before failover +failed_counter_threshold = 3 +# Interval between test transactions when no traffic seconds +test_trans_interval = 10 +# Interval between writes of the FPC to the DB seconds +write_fpc_interval = 5 +# Name of the site in which this node is hosted +site_name = pdp_1 +# Node type. Can take values of: pdp-xacml, pdp-drools, pap, pap-admin, logparser, brms-gateway, +# astra-gateway, elk-server and pypdpNode type +# Note: Make sure you don't leave any trailing spaces, or you'll get an 'invalid node type' error! +node_type = pdp_drools +# Dependency groups are groups of resources upon which a node operational state is dependent upon. +# Each group is a comma-separated list of resource names and groups are separated by a semicolon. For example: +#For JUnit testing this must be empty since none of the other components exist +#dependency_groups=site_1.astra_1,site_1.astra_2;site_1.brms_1,site_1.brms_2;site_1.logparser_1;site_1.pypdp_1 +dependency_groups= + +# Needed by DroolsPdpsElectionHandler +pdp.checkInterval=1500 +pdp.updateInterval=1000 +#pdp.timeout=3000 +# Need long timeout, because testTransaction is only run every 10 seconds. +pdp.timeout=15000 +#how long do we wait for the pdp table to populate on initial startup +pdp.initialWait=20000 + +# Known as the PDPID in the droolpdpentity table. +resource.name=pdp1 + +# The amount of this a resource (entity) should sleep between audit executions. +# If not specified, defaults to five seconds. +# -1 turns off audit +# zero forces audit to run continuously +integrity_audit_period_seconds=60 diff --git a/policy-persistence/src/test/server/config/droolsPersistence.properties b/policy-persistence/src/test/server/config/droolsPersistence.properties new file mode 100644 index 00000000..8cdaf6ab --- /dev/null +++ b/policy-persistence/src/test/server/config/droolsPersistence.properties @@ -0,0 +1,35 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +javax.persistence.jdbc.driver = org.h2.Driver +javax.persistence.jdbc.url = jdbc:h2:file:./sql/drools +javax.persistence.jdbc.user = sa +javax.persistence.jdbc.password = + +#javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver +#javax.persistence.jdbc.url=jdbc:mariadb://localhost:3306/drools +#javax.persistence.jdbc.user=root +#javax.persistence.jdbc.password=policy + +# Needed? +hibernate.dataSource=org.mariadb.jdbc.MySQLDataSource + +# For testing purposes, it may be convenient to disable persistence +persistenceDisabled=false diff --git a/policy-persistence/src/test/server/config/policyLogger.properties b/policy-persistence/src/test/server/config/policyLogger.properties new file mode 100644 index 00000000..6ee66fd6 --- /dev/null +++ b/policy-persistence/src/test/server/config/policyLogger.properties @@ -0,0 +1,44 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +################################### Set concurrentHashMap and timer info ####################### +#Timer initial delay and the delay between in milliseconds before task is to be execute. +timer.delay.time=1000 +#Timer scheduleAtFixedRate period - time in milliseconds between successive task executions. +check.interval= 30000 +#Longest time an event info can be stored in the concurrentHashMap for logging - in seconds. +event.expired.time=86400 +#Size of the concurrentHashMap which stores the event starting time, etc - when its size reaches this limit, the Timer gets executed +#to remove all expired records from this concurrentHashMap. +concurrentHashMap.limit=5000 +#Size of the concurrentHashMap - when its size drops to this point, stop the Timer +stop.check.point=2500 +################################### Set logging format ############################################# +# set EELF for EELF logging format, set LOG4J for using log4j, set SYSTEMOUT for using system.out.println +logger.type=EELF +#################################### Set level for EELF or SYSTEMOUT logging ################################## +# Set level for debug file. Set DEBUG to enable .info, .warn and .debug; set INFO for enable .info and .warn; set OFF to disable all +debugLogger.level=INFO +# Set level for metrics file. Set OFF to disable; set ON to enable +metricsLogger.level=ON +# Set level for error file. Set OFF to disable; set ON to enable +error.level=ON +# Set level for audit file. Set OFF to disable; set ON to enable +audit.level=ON diff --git a/policy-persistence/src/test/server/config/xacmlPersistence.properties b/policy-persistence/src/test/server/config/xacmlPersistence.properties new file mode 100644 index 00000000..149aa557 --- /dev/null +++ b/policy-persistence/src/test/server/config/xacmlPersistence.properties @@ -0,0 +1,38 @@ +### +# ============LICENSE_START======================================================= +# policy-persistence +# ================================================================================ +# Copyright (C) 2017 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========================================================= +### + +javax.persistence.jdbc.driver = org.h2.Driver +javax.persistence.jdbc.url = jdbc:h2:file:./sql/xacml +javax.persistence.jdbc.user = sa +javax.persistence.jdbc.password = + +#javax.persistence.jdbc.driver=org.mariadb.jdbc.Driver +#javax.persistence.jdbc.url=jdbc:mariadb://127.0.0.1:3306/xacml +#javax.persistence.jdbc.user=root +#javax.persistence.jdbc.password=policy + +# Needed? +hibernate.dataSource=org.mariadb.jdbc.MySQLDataSource + +# For testing purposes, it may be convenient to disable persistence +persistenceDisabled=false + + + |