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