diff --git a/modules/auto-activation-ext/README.txt b/modules/auto-activation-ext/README.txt new file mode 100644 index 00000000..819a808d --- /dev/null +++ b/modules/auto-activation-ext/README.txt @@ -0,0 +1,85 @@ +Apache Ignite Auto Activation Plugin +------------------------------------ + +Apache Ignite Auto Activation plugin enables cluster activation at startup, subject to configured conditions. + +Plugin skip cluster activation in any of next cases: + +- Cluster state is ACTIVE +- Cluster baseline is not empty + +Depending on how you use Ignite, you can an extension using one of the following methods: + +- If you use the binary distribution, move the libs/{module-dir} to the 'libs' directory of the Ignite distribution before starting the node. +- Add libraries from libs/{module-dir} to the classpath of your application. +- Add a module as a Maven dependency to your project. + + +Building Module And Running Tests +--------------------------------- + +To build and run Auto Activation extension use the command below: + +mvn clean package -pl modules/auto-activation-ext + + +Importing Auto Activation Plugin In Maven Project +------------------------------------------------- + +If you are using Maven to manage dependencies of your project, you can add Auto Activation Plugin module +dependency like this (replace '${ignite.version}' with actual Ignite version you are +interested in): + + + ... + + ... + + org.apache.ignite + ignite-auto-activation-ext + ${ignite-auto-activation-ext.version} + + ... + + ... + + + +Usage +----------------------------------- + +To enable cluster auto activation add next properties to your ignite-server.xml configurations + + + + + + + + + +where "condition" can be one of the following beans: + + + + + server-0 + server-1 + + + + +or + + + + + + server-0 + server-1 + + + \ No newline at end of file diff --git a/modules/auto-activation-ext/pom.xml b/modules/auto-activation-ext/pom.xml new file mode 100644 index 00000000..0084b947 --- /dev/null +++ b/modules/auto-activation-ext/pom.xml @@ -0,0 +1,86 @@ + + + + + + + 4.0.0 + + + org.apache.ignite + ignite-parent-ext-internal + 1 + ../../parent-internal/pom.xml + + + ignite-auto-activation-ext + 1.0-SNAPSHOT + https://ignite.apache.org + + + + ${project.groupId} + ignite-core + provided + + + + ${project.groupId} + ignite-core + test-jar + test + + + + ${project.groupId} + ignite-log4j2 + test + + + + org.springframework + spring-beans + ${spring.version} + test + + + + org.springframework + spring-context + ${spring.version} + test + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 11 + 11 + + + + + + diff --git a/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByConsistentID.java b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByConsistentID.java new file mode 100644 index 00000000..ec184a9f --- /dev/null +++ b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByConsistentID.java @@ -0,0 +1,40 @@ +package opt.apache.ignite.activation; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Set; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.lang.IgnitePredicate; + +/** + * Activate cluster when nodes with specified ConsistentID values join topology. + */ +public class ActivateByConsistentID implements IgnitePredicate> { + /** Collection of required nodes ConsistentIDs. */ + private final Set requiredNodes; + + /** + * @param requiredNodes List of ConsistentIDs. + */ + public ActivateByConsistentID(Set requiredNodes) { + if (requiredNodes == null || requiredNodes.isEmpty()) + throw new IllegalArgumentException("requiredNodes must be set"); + + this.requiredNodes = requiredNodes; + } + + /** {@inheritDoc} */ + @Override public boolean apply(Collection nodes) { + Set missingNodes = new LinkedHashSet<>(requiredNodes); + + for (ClusterNode node : nodes) { + String nodeConsistentId = node.consistentId().toString(); + + missingNodes.remove(nodeConsistentId); + + if (missingNodes.isEmpty()) break; + } + + return missingNodes.isEmpty(); + } +} diff --git a/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByNodeAttribute.java b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByNodeAttribute.java new file mode 100644 index 00000000..645209dd --- /dev/null +++ b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByNodeAttribute.java @@ -0,0 +1,48 @@ +package opt.apache.ignite.activation; + +import java.util.Collection; +import java.util.LinkedHashSet; +import java.util.Set; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.lang.IgnitePredicate; + +/** + * Activate cluster when nodes with all specified attributes values join topology. + */ +public class ActivateByNodeAttribute implements IgnitePredicate> { + /** Node's attribute name. */ + private final String attrName; + + /** Collection of values for node's attribute. */ + private final Set requiredValues; + + /** + * @param attributeName Node's attribute name. + * @param requiredValues List of values for node's attribute. + */ + public ActivateByNodeAttribute(String attributeName, Set requiredValues) { + if (attributeName == null || attributeName.isBlank()) + throw new IllegalArgumentException("attributeName must be set"); + + if (requiredValues == null || requiredValues.isEmpty()) + throw new IllegalArgumentException("requiredValues must be set"); + + this.attrName = attributeName; + this.requiredValues = requiredValues; + } + + /** */ + @Override public boolean apply(Collection nodes) { + Set missingNodes = new LinkedHashSet(requiredValues); + + for (ClusterNode node : nodes) { + String attrVal = node.attribute(attrName); + + missingNodes.remove(attrVal); + + if (missingNodes.isEmpty()) break; + } + + return missingNodes.isEmpty(); + } +} diff --git a/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/AutoActivationPluginProvider.java b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/AutoActivationPluginProvider.java new file mode 100644 index 00000000..90ead41b --- /dev/null +++ b/modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/AutoActivationPluginProvider.java @@ -0,0 +1,135 @@ +package opt.apache.ignite.activation; + +import java.io.Serializable; +import java.util.Collection; +import java.util.UUID; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteCluster; +import org.apache.ignite.IgniteLogger; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.cluster.ClusterState; +import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.plugin.CachePluginContext; +import org.apache.ignite.plugin.CachePluginProvider; +import org.apache.ignite.plugin.ExtensionRegistry; +import org.apache.ignite.plugin.IgnitePlugin; +import org.apache.ignite.plugin.PluginConfiguration; +import org.apache.ignite.plugin.PluginContext; +import org.apache.ignite.plugin.PluginProvider; +import org.apache.ignite.plugin.PluginValidationException; + +/** + * Activate cluster when specified condition meet + */ +public class AutoActivationPluginProvider implements PluginProvider { + /** */ + private final IgnitePredicate> condition; + + /** */ + private IgniteLogger logger; + + /** */ + private Ignite grid; + + /** + * @param condition Auto activation condition. + */ + public AutoActivationPluginProvider(IgnitePredicate> condition) { + if (condition == null) + throw new IllegalArgumentException("Auto activation condition must be set"); + + this.condition = condition; + } + + /** {@inheritDoc} */ + @Override public String name() { + return "Auto Activation Plugin"; + } + + /** {@inheritDoc} */ + @Override public T plugin() { + return (T)new IgnitePlugin() { + // No-op. + }; + } + + /** {@inheritDoc} */ + @Override public String version() { + return "1.0"; + } + + /** {@inheritDoc} */ + @Override public String copyright() { + return ""; + } + + /** {@inheritDoc} */ + @Override public void initExtensions(PluginContext pc, ExtensionRegistry er) { + logger = pc.log(this.getClass()); + grid = pc.grid(); + } + + /** {@inheritDoc} */ + @Override public T createComponent(PluginContext pc, Class type) { + return null; + } + + /** {@inheritDoc} */ + @Override public CachePluginProvider createCacheProvider(CachePluginContext cpc) { + return null; + } + + /** {@inheritDoc} */ + @Override public void start(PluginContext pc) { + // do nothing + } + + /** {@inheritDoc} */ + @Override public void stop(boolean bln) { + // do nothing + } + + /** {@inheritDoc} */ + @Override public void onIgniteStart() { + + IgniteCluster cluster = grid.cluster(); + + if (cluster.state() == ClusterState.ACTIVE) { + if (logger.isInfoEnabled()) logger.info("Auto activation skipped - cluster already activated"); + return; + } + + if (cluster.currentBaselineTopology() != null) { + if (logger.isInfoEnabled()) logger.info("Auto activation skipped - baseline is not empty"); + return; + } + + if (condition.apply(cluster.nodes())) { + if (logger.isInfoEnabled()) logger.info("Auto activation plugin set cluster state ACTIVE - activation condition meet"); + cluster.state(ClusterState.ACTIVE); + } + else { + if (logger.isInfoEnabled()) logger.info("Auto activation skipped - activation condition not meet"); + } + } + + /** {@inheritDoc} */ + @Override public void onIgniteStop(boolean bln) { + // do nothing + } + + /** {@inheritDoc} */ + @Override public Serializable provideDiscoveryData(UUID uuid) { + return null; + } + + /** {@inheritDoc} */ + @Override public void receiveDiscoveryData(UUID uuid, Serializable srlzbl) { + // do nothing + } + + /** {@inheritDoc} */ + @Override public void validateNewNode(ClusterNode cn) throws PluginValidationException { + // do nothing + } +} diff --git a/modules/auto-activation-ext/src/test/java/opt/apache/ignite/activation/AutoActivationTest.java b/modules/auto-activation-ext/src/test/java/opt/apache/ignite/activation/AutoActivationTest.java new file mode 100644 index 00000000..306b1712 --- /dev/null +++ b/modules/auto-activation-ext/src/test/java/opt/apache/ignite/activation/AutoActivationTest.java @@ -0,0 +1,681 @@ +package opt.apache.ignite.activation; + +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import java.util.Collections; +import java.util.Map; +import java.util.Set; + +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.cache.CacheMode; +import org.apache.ignite.cluster.ClusterState; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.DataRegionConfiguration; +import org.apache.ignite.configuration.DataStorageConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.configuration.WALMode; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.plugin.PluginProvider; +import org.apache.ignite.testframework.ListeningTestLogger; +import org.apache.ignite.testframework.LogListener; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +import static org.apache.ignite.cluster.ClusterState.ACTIVE; +import static org.apache.ignite.cluster.ClusterState.INACTIVE; +import static org.apache.ignite.testframework.GridTestUtils.assertThrows; + +/** + * {@link AutoActivationPluginProvider} test + */ +public class AutoActivationTest extends GridCommonAbstractTest { + /** Listening test logger. */ + private final ListeningTestLogger listeningLog = new ListeningTestLogger(log); + + /** */ + private final LogListener lsnrAlreadyAct = LogListener + .matches("Auto activation skipped - cluster already activated").build(); + + /** */ + private final LogListener lsnrBaseline = LogListener + .matches("Auto activation skipped - baseline is not empty").build(); + + /** */ + private final LogListener lsnrActMeet = LogListener + .matches("Auto activation plugin set cluster state ACTIVE - activation condition meet").build(); + + /** */ + private final LogListener lsnrActNotMeet = LogListener + .matches("Auto activation skipped - activation condition not meet").build(); + + /** */ + private final String NODE_0 = "node_0"; + + /** */ + private final String NODE_1 = "node_1"; + + /** */ + private final String NODE_2 = "node_2"; + + /** */ + private final String NODE_3 = "node_3"; + + /** */ + private final String ATTR = "CELL"; + + /** */ + private final String ATTR_VAL1 = "CELL_01"; + + /** */ + private final String ATTR_VAL2 = "CELL_02"; + + /** */ + private final Set nodesConsistentIds = Set.of(NODE_0, NODE_1, NODE_2); + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + super.beforeTest(); + + stopAllGrids(); + + cleanPersistenceDir(); + + listeningLog.registerAllListeners(lsnrAlreadyAct, lsnrBaseline, lsnrActMeet, lsnrActNotMeet); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(true); + + cleanPersistenceDir(); + + listeningLog.clearListeners(); + + super.afterTest(); + } + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + final IgniteConfiguration igniteConfiguration = super.getConfiguration(igniteInstanceName); + + switch (igniteInstanceName) { + case NODE_0: + igniteConfiguration.setConsistentId(NODE_0); + break; + + case NODE_1: + igniteConfiguration.setConsistentId(NODE_1); + break; + + case NODE_2: + igniteConfiguration.setConsistentId(NODE_2); + break; + + default: throw new IllegalArgumentException("Unknown node: " + igniteInstanceName); + } + + igniteConfiguration.setClusterStateOnStart(ClusterState.INACTIVE); + igniteConfiguration.setGridLogger(listeningLog); + + return igniteConfiguration; + } + + /** @return DataStorageConfiguration. */ + private DataStorageConfiguration getDataStorageConfiguration() { + return new DataStorageConfiguration() + .setWalSegmentSize(4 * 1024 * 1024) + .setWalMode(WALMode.LOG_ONLY) + .setCheckpointFrequency(1000) + .setWalCompactionEnabled(true) + .setDefaultDataRegionConfiguration(getDataRegionConfiguration()); + } + + /** @return DataRegionConfiguration. */ + private DataRegionConfiguration getDataRegionConfiguration() { + return new DataRegionConfiguration() + .setPersistenceEnabled(true) + .setMaxSize(100L * 1024 * 1024); + } + + /** @return CacheConfiguration. */ + private CacheConfiguration getCacheConfiguration() { + return new CacheConfiguration<>() + .setName(DEFAULT_CACHE_NAME) + .setCacheMode(CacheMode.PARTITIONED) + .setBackups(0) + .setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL) + .setIndexedTypes(String.class, Integer.class); + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByConsistentIdAllNodes() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(nodesConsistentIds) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0).setPluginProviders(autoActivationProvider))) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByConsistentIdFirstTwoNodes() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_0, NODE_1)) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0).setPluginProviders(autoActivationProvider))) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertFalse(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + + startGrid(getConfiguration(NODE_2).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByConsistentIdOnlyLastNode() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_2)) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0).setPluginProviders(autoActivationProvider))) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByConsistentIdAllNodesPlusCacheConfig() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_2)) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration()))) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration())); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration())); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testActivationNotMetInMemoryClusterActivationByConsistentId() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_3)) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0).setPluginProviders(autoActivationProvider))) { + startGrid(getConfiguration(NODE_1).setPluginProviders(autoActivationProvider)); + startGrid(getConfiguration(NODE_2).setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + } + } + + /** */ + @Test + public void testAlreadyActivatedInMemoryClusterActivationByConsistentId() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_0)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setClusterStateOnStart(ACTIVE) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrAlreadyAct.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testBaselineNotEmptyPersistenceClusterActivationByConsistentId() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(nodesConsistentIds) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)) + ) { + startGrid(getConfiguration(NODE_1) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_2) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + + node0.cluster().state(INACTIVE); + + stopAllGrids(); + + IgniteEx restartedNode0 = startGrid(getConfiguration(NODE_0) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_1) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_2) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrBaseline.check()); + assertEquals(restartedNode0.cluster().state(), INACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByNodeAttributeAllAttrs() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByNodeAttributeFirstAttr() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrActMeet.check()); + assertFalse(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + + startGrid(getConfiguration(NODE_1) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + + startGrid(getConfiguration(NODE_2) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByNodeAttributeLastAttr() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL2)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testSuccessfulInMemoryClusterActivationByNodeAttributeAllAttrsPlusCacheConfig() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration())) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration())); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider) + .setCacheConfiguration(getCacheConfiguration())); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testActivationNotMetInMemoryClusterActivationByNodeAttribute() throws Exception { + String ATTR_VAL3 = "CELL_03"; + + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL3)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)) + ) { + startGrid(getConfiguration(NODE_1) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_2) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + } + } + + /** */ + @Test + public void testAlreadyActivatedInMemoryClusterActivationByNodeAttribute() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1)) + ); + + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setClusterStateOnStart(ACTIVE) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider))) { + assertTrue(lsnrAlreadyAct.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testBaselineNotEmptyPersistenceClusterActivationByNodeAttribute() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)) + ) { + startGrid(getConfiguration(NODE_1) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_2) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + + node0.cluster().state(INACTIVE); + + stopAllGrids(); + + IgniteEx restartedNode0 = startGrid(getConfiguration(NODE_0) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_1) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(autoActivationProvider)); + + startGrid(getConfiguration(NODE_2) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrBaseline.check()); + assertEquals(restartedNode0.cluster().state(), INACTIVE); + } + } + + /** */ + @Test + public void testAssertionActivationByConsistentId() throws Exception { + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(null)))), + IllegalArgumentException.class, + "requiredNodes must be set" + ); + + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(null, null)))), + IllegalArgumentException.class, + "attributeName must be set" + ); + + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute("", null)))), + IllegalArgumentException.class, + "attributeName must be set" + ); + + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(ATTR, null)))), + IllegalArgumentException.class, + "requiredValues must be set" + ); + + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(ATTR, Collections.emptySet())))), + IllegalArgumentException.class, + "requiredValues must be set" + ); + + assertThrows( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(null))), + IllegalArgumentException.class, + "Auto activation condition must be set" + ); + } + + /** */ + @Test + public void testXmlCfgPersistenceClusterActivationByConsistentId() throws Exception { + try ( + IgniteEx node0 = + startGrid(loadConfiguration("activate-by-consistent-ID/ignite-server-node1.xml") + .setGridLogger(listeningLog)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(loadConfiguration("activate-by-consistent-ID/ignite-server-node2.xml") + .setGridLogger(listeningLog)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(loadConfiguration("activate-by-consistent-ID/ignite-server-node3.xml") + .setGridLogger(listeningLog)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } + + /** */ + @Test + public void testXmlCfgPersistenceClusterActivationByNodeAttribute() throws Exception { + try ( + IgniteEx node0 = startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node1.xml") + .setGridLogger(listeningLog)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node2.xml").setGridLogger(listeningLog)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node3.xml").setGridLogger(listeningLog)); + + assertTrue(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE); + } + } +} diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node1.xml b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node1.xml new file mode 100644 index 00000000..dfb2b46c --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node1.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cell-1_node-1 + cell-1_node-2 + cell-2_node-1 + + + + + + + + + + + diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node2.xml b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node2.xml new file mode 100644 index 00000000..2c87e410 --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node2.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cell-1_node-1 + cell-1_node-2 + cell-2_node-1 + + + + + + + + + + + diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node3.xml b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node3.xml new file mode 100644 index 00000000..7a46935c --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node3.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + cell-1_node-1 + cell-1_node-2 + cell-2_node-1 + + + + + + + + + + + diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node1.xml b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node1.xml new file mode 100644 index 00000000..cffbff86 --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node1.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CELL_1 + CELL_2 + + + + + + + + + + + diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node2.xml b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node2.xml new file mode 100644 index 00000000..abeaae4b --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node2.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CELL_1 + CELL_2 + + + + + + + + + + + diff --git a/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node3.xml b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node3.xml new file mode 100644 index 00000000..e7dc4e2b --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node3.xml @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CELL_1 + CELL_2 + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 11fa26d8..4aec53b7 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,7 @@ modules/ssh-ext modules/ml-ext modules/gatling-ext + modules/auto-activation-ext