From 7c1bff5ab3b70c0722eb7d744f80941b603e0dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 24 Jun 2026 18:08:23 +1000 Subject: [PATCH 1/7] IGNITE-28731 Create cluster auto activation plugin --- modules/auto-activation-ext/README.txt | 85 +++ modules/auto-activation-ext/pom.xml | 86 +++ .../activation/ActivateByConsistentID.java | 40 + .../activation/ActivateByNodeAttribute.java | 48 ++ .../AutoActivationPluginProvider.java | 135 ++++ .../ignite/activation/AutoActivationTest.java | 681 ++++++++++++++++++ .../ignite-server-node1.xml | 114 +++ .../ignite-server-node2.xml | 114 +++ .../ignite-server-node3.xml | 114 +++ .../ignite-server-node1.xml | 114 +++ .../ignite-server-node2.xml | 114 +++ .../ignite-server-node3.xml | 114 +++ pom.xml | 1 + 13 files changed, 1760 insertions(+) create mode 100644 modules/auto-activation-ext/README.txt create mode 100644 modules/auto-activation-ext/pom.xml create mode 100644 modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByConsistentID.java create mode 100644 modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/ActivateByNodeAttribute.java create mode 100644 modules/auto-activation-ext/src/main/java/opt/apache/ignite/activation/AutoActivationPluginProvider.java create mode 100644 modules/auto-activation-ext/src/test/java/opt/apache/ignite/activation/AutoActivationTest.java create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node1.xml create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node2.xml create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-consistent-ID/ignite-server-node3.xml create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node1.xml create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node2.xml create mode 100644 modules/auto-activation-ext/src/test/resources/activate-by-node-attribute/ignite-server-node3.xml diff --git a/modules/auto-activation-ext/README.txt b/modules/auto-activation-ext/README.txt new file mode 100644 index 000000000..819a808df --- /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 000000000..0084b947d --- /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 000000000..ec184a9f9 --- /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 000000000..645209ddb --- /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 000000000..90ead41b9 --- /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 000000000..306b17123 --- /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 000000000..dfb2b46ce --- /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 000000000..2c87e410f --- /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 000000000..7a46935ca --- /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 000000000..cffbff862 --- /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 000000000..abeaae4b5 --- /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 000000000..e7dc4e2b6 --- /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 11fa26d80..4aec53b7e 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,7 @@ modules/ssh-ext modules/ml-ext modules/gatling-ext + modules/auto-activation-ext From 17fd2f217c1e0fa6218c97e4f43b2b4fb4457735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Sun, 5 Jul 2026 17:25:23 +1000 Subject: [PATCH 2/7] IGNITE-28731 Create cluster auto activation plugin - Fix issues --- .../{README.txt => README.md} | 26 +++++++----- .../activation/ActivateByConsistentID.java | 20 ++++++++- .../activation/ActivateByNodeAttribute.java | 22 +++++++++- .../AutoActivationPluginProvider.java | 42 +++++++++++++++---- .../ignite/activation/AutoActivationTest.java | 4 +- .../ignite-server-node1.xml | 13 +++--- .../ignite-server-node2.xml | 11 +++-- .../ignite-server-node3.xml | 11 +++-- .../ignite-server-node1.xml | 13 +++--- .../ignite-server-node2.xml | 11 +++-- .../ignite-server-node3.xml | 11 +++-- 11 files changed, 121 insertions(+), 63 deletions(-) rename modules/auto-activation-ext/{README.txt => README.md} (89%) diff --git a/modules/auto-activation-ext/README.txt b/modules/auto-activation-ext/README.md similarity index 89% rename from modules/auto-activation-ext/README.txt rename to modules/auto-activation-ext/README.md index 819a808df..c9bac3639 100644 --- a/modules/auto-activation-ext/README.txt +++ b/modules/auto-activation-ext/README.md @@ -1,6 +1,5 @@ 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: @@ -30,10 +29,14 @@ If you are using Maven to manage dependencies of your project, you can add Auto dependency like this (replace '${ignite.version}' with actual Ignite version you are interested in): +```xml + + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 +http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + your.project ... ... @@ -46,13 +49,13 @@ interested in): ... - +``` Usage ----------------------------------- To enable cluster auto activation add next properties to your ignite-server.xml configurations - +``` @@ -60,9 +63,9 @@ To enable cluster auto activation add next properties to your ignite-server.xml - +``` where "condition" can be one of the following beans: - +``` @@ -71,9 +74,9 @@ where "condition" can be one of the following beans: - +``` or - +``` @@ -82,4 +85,5 @@ or server-1 - \ No newline at end of file + +``` 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 index ec184a9f9..9d3e8ffee 100644 --- 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 @@ -1,3 +1,20 @@ +/* + * 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. + */ + package opt.apache.ignite.activation; import java.util.Collection; @@ -32,7 +49,8 @@ public ActivateByConsistentID(Set requiredNodes) { missingNodes.remove(nodeConsistentId); - if (missingNodes.isEmpty()) break; + 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 index 645209ddb..7763f4edc 100644 --- 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 @@ -1,3 +1,20 @@ +/* + * 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. + */ + package opt.apache.ignite.activation; import java.util.Collection; @@ -31,7 +48,7 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) this.requiredValues = requiredValues; } - /** */ + /** {@inheritDoc} */ @Override public boolean apply(Collection nodes) { Set missingNodes = new LinkedHashSet(requiredValues); @@ -40,7 +57,8 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) missingNodes.remove(attrVal); - if (missingNodes.isEmpty()) break; + 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 index 90ead41b9..7e0a02795 100644 --- 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 @@ -1,3 +1,20 @@ +/* + * 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. + */ + package opt.apache.ignite.activation; import java.io.Serializable; @@ -81,12 +98,12 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public void start(PluginContext pc) { - // do nothing + // No-op. } /** {@inheritDoc} */ @Override public void stop(boolean bln) { - // do nothing + // No-op. } /** {@inheritDoc} */ @@ -95,27 +112,34 @@ public AutoActivationPluginProvider(IgnitePredicate> con IgniteCluster cluster = grid.cluster(); if (cluster.state() == ClusterState.ACTIVE) { - if (logger.isInfoEnabled()) logger.info("Auto activation skipped - cluster already activated"); + 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"); + 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"); + 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"); + if (logger.isInfoEnabled()) + logger.info("Auto activation skipped - activation condition not meet"); } } /** {@inheritDoc} */ @Override public void onIgniteStop(boolean bln) { - // do nothing + // No-op. } /** {@inheritDoc} */ @@ -125,11 +149,11 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public void receiveDiscoveryData(UUID uuid, Serializable srlzbl) { - // do nothing + // No-op. } /** {@inheritDoc} */ @Override public void validateNewNode(ClusterNode cn) throws PluginValidationException { - // do nothing + // No-op. } } 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 index 306b17123..5be3b65b4 100644 --- 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 @@ -1,5 +1,3 @@ -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 @@ -17,6 +15,8 @@ * limitations under the License. */ +package opt.apache.ignite.activation; + import java.util.Collections; import java.util.Map; import java.util.Set; 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 index dfb2b46ce..4a74c2061 100644 --- 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 @@ -6,9 +6,9 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - + + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - 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 index 2c87e410f..272e1d5cd 100644 --- 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 @@ -8,7 +8,7 @@ http://www.springframework.org/schema/util/spring-util.xsd"> - + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - 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 index 7a46935ca..4c49feca5 100644 --- 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 @@ -8,7 +8,7 @@ http://www.springframework.org/schema/util/spring-util.xsd"> - + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - 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 index cffbff862..a04fb04a5 100644 --- 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 @@ -6,9 +6,9 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - + + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - 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 index abeaae4b5..bd7786def 100644 --- 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 @@ -8,7 +8,7 @@ http://www.springframework.org/schema/util/spring-util.xsd"> - + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - 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 index e7dc4e2b6..462c0b9af 100644 --- 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 @@ -8,7 +8,7 @@ http://www.springframework.org/schema/util/spring-util.xsd"> - + @@ -26,11 +26,11 @@ - + - + @@ -52,7 +52,7 @@ - + @@ -79,7 +79,7 @@ - + @@ -106,7 +106,6 @@ - From bfd632079902f3211269bf873deba4a66d6b960f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Sun, 12 Jul 2026 02:21:42 +1000 Subject: [PATCH 3/7] IGNITE-28731 Create cluster auto activation plugin - fix snapshot version --- modules/auto-activation-ext/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/auto-activation-ext/pom.xml b/modules/auto-activation-ext/pom.xml index 0084b947d..600856e9e 100644 --- a/modules/auto-activation-ext/pom.xml +++ b/modules/auto-activation-ext/pom.xml @@ -33,7 +33,7 @@ ignite-auto-activation-ext - 1.0-SNAPSHOT + 1.0.0-SNAPSHOT https://ignite.apache.org From 115b23db1e8f7cf3d3c9ed64b3d816152b42d9e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Tue, 11 Aug 2026 13:12:31 +1000 Subject: [PATCH 4/7] IGNITE-28731 Create cluster auto activation plugin - fix some more issues --- modules/auto-activation-ext/README.md | 17 +-- .../activation/ActivateByConsistentID.java | 6 + .../activation/ActivateByNodeAttribute.java | 8 +- .../AutoActivationPluginProvider.java | 4 +- .../ignite/activation/AutoActivationTest.java | 108 +++++++++++++----- .../ignite-server-node1.xml | 83 +------------- .../ignite-server-node2.xml | 83 +------------- .../ignite-server-node3.xml | 83 +------------- .../ignite-server-node1.xml | 83 +------------- .../ignite-server-node2.xml | 83 +------------- .../ignite-server-node3.xml | 83 +------------- .../resources/common-ignite-server-node.xml | 88 ++++++++++++++ 12 files changed, 200 insertions(+), 529 deletions(-) create mode 100644 modules/auto-activation-ext/src/test/resources/common-ignite-server-node.xml diff --git a/modules/auto-activation-ext/README.md b/modules/auto-activation-ext/README.md index c9bac3639..57bae4129 100644 --- a/modules/auto-activation-ext/README.md +++ b/modules/auto-activation-ext/README.md @@ -2,10 +2,11 @@ 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: +The plugin skips cluster activation in any of next cases: -- Cluster state is ACTIVE +- Cluster state is ACTIVE or ACTIVE_READ_ONLY - Cluster baseline is not empty +- `condition` contains any client node Depending on how you use Ignite, you can an extension using one of the following methods: @@ -26,8 +27,7 @@ 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): +dependency like this: ```xml @@ -43,7 +43,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> org.apache.ignite ignite-auto-activation-ext - ${ignite-auto-activation-ext.version} + 1.0.0-SNAPSHOT ... @@ -75,15 +75,18 @@ where "condition" can be one of the following beans: ``` +where `server-0` and `server-1` are consistent ID's of required server nodes in the activated cluster + or ``` - server-0 - server-1 + attribute-0 + attribute-1 ``` +where `attribute-0` and `attribute-1` are values of user-defined attribute `ATTR` that will be used to choose server nodes for cluster auto activation. \ No newline at end of file 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 index 9d3e8ffee..a04813a25 100644 --- 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 @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; +import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.lang.IgnitePredicate; @@ -47,6 +48,11 @@ public ActivateByConsistentID(Set requiredNodes) { for (ClusterNode node : nodes) { String nodeConsistentId = node.consistentId().toString(); + if (missingNodes.contains(nodeConsistentId) && node.isClient()) { + throw new IgniteException("Auto-activation-plugin supports only server nodes. This node is client: ID " + + node.consistentId() + ", IP " + node.addresses()); + } + missingNodes.remove(nodeConsistentId); if (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 index 7763f4edc..167187ecd 100644 --- 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 @@ -20,6 +20,7 @@ import java.util.Collection; import java.util.LinkedHashSet; import java.util.Set; +import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.lang.IgnitePredicate; @@ -50,11 +51,16 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) /** {@inheritDoc} */ @Override public boolean apply(Collection nodes) { - Set missingNodes = new LinkedHashSet(requiredValues); + Set missingNodes = new LinkedHashSet<>(requiredValues); for (ClusterNode node : nodes) { String attrVal = node.attribute(attrName); + if (missingNodes.contains(attrVal) && node.isClient()) { + throw new IgniteException("Auto-activation-plugin supports only server nodes. This node is client: ID " + + node.consistentId() + ", IP " + node.addresses()); + } + missingNodes.remove(attrVal); if (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 index 7e0a02795..486c077f4 100644 --- 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 @@ -72,7 +72,7 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public String version() { - return "1.0"; + return "1.0.0-SNAPSHOT"; } /** {@inheritDoc} */ @@ -111,7 +111,7 @@ public AutoActivationPluginProvider(IgnitePredicate> con IgniteCluster cluster = grid.cluster(); - if (cluster.state() == ClusterState.ACTIVE) { + if (cluster.state() == ClusterState.ACTIVE || cluster.state() == ClusterState.ACTIVE_READ_ONLY) { if (logger.isInfoEnabled()) logger.info("Auto activation skipped - cluster already activated"); 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 index 5be3b65b4..627afefe1 100644 --- 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 @@ -20,7 +20,7 @@ import java.util.Collections; import java.util.Map; import java.util.Set; - +import org.apache.ignite.IgniteException; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.cluster.ClusterState; @@ -35,8 +35,11 @@ import org.apache.ignite.testframework.LogListener; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; import static org.apache.ignite.cluster.ClusterState.ACTIVE; +import static org.apache.ignite.cluster.ClusterState.ACTIVE_READ_ONLY; import static org.apache.ignite.cluster.ClusterState.INACTIVE; import static org.apache.ignite.testframework.GridTestUtils.assertThrows; @@ -162,6 +165,13 @@ private CacheConfiguration getCacheConfiguration() { .setIndexedTypes(String.class, Integer.class); } + /** @return IgniteConfiguration from XML. */ + private IgniteConfiguration getConfigurationFromXml(String xmlPath) throws Exception { + ApplicationContext ctx = new ClassPathXmlApplicationContext("common-ignite-server-node.xml", xmlPath); + + return ctx.getBean(IgniteConfiguration.class).setGridLogger(listeningLog); + } + /** */ @Test public void testSuccessfulInMemoryClusterActivationByConsistentIdAllNodes() throws Exception { @@ -303,6 +313,24 @@ public void testAlreadyActivatedInMemoryClusterActivationByConsistentId() throws } } + /** */ + @Test + public void testAlreadyActivatedInMemoryClusterActivationByConsistentIdActiveReadOnly() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(Set.of(NODE_0)) + ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setClusterStateOnStart(ACTIVE_READ_ONLY) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrAlreadyAct.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE_READ_ONLY); + } + } + /** */ @Test public void testBaselineNotEmptyPersistenceClusterActivationByConsistentId() throws Exception { @@ -578,7 +606,7 @@ public void testBaselineNotEmptyPersistenceClusterActivationByNodeAttribute() th /** */ @Test - public void testAssertionActivationByConsistentId() throws Exception { + public void testAssertionActivation() throws Exception { assertThrows( listeningLog, () -> startGrid(getConfiguration(NODE_0) @@ -630,49 +658,75 @@ public void testAssertionActivationByConsistentId() throws Exception { /** */ @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); + public void testAssertionActivationByConsistentIdClientNode() throws Exception { + assertThrows( + listeningLog, + () -> { + startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(Set.of(NODE_0, NODE_1))))); + + startGrid(getConfiguration(NODE_1) + .setClientMode(true) + .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(Set.of(NODE_0, NODE_1))))); + }, + IgniteException.class, + "Auto-activation-plugin supports only server nodes. This node is client: ID " + ); + } - startGrid(loadConfiguration("activate-by-consistent-ID/ignite-server-node3.xml") - .setGridLogger(listeningLog)); + /** */ + @Test + public void testAssertionActivationByNodeAttributeClientNode() throws Exception { + assertThrows( + listeningLog, + () -> { + startGrid(getConfiguration(NODE_0) + .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) + .setPluginProviders(new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) + ))); + + startGrid(getConfiguration(NODE_1) + .setClientMode(true) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(new AutoActivationPluginProvider( + new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) + ))); + }, + IgniteException.class, + "Auto-activation-plugin supports only server nodes. This node is client: ID " + ); + } - assertTrue(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), ACTIVE); - } + /** */ + @Test + public void testXmlCfgPersistenceClusterActivationByConsistentId() throws Exception { + executeXmlTest("activate-by-consistent-ID"); } /** */ @Test public void testXmlCfgPersistenceClusterActivationByNodeAttribute() throws Exception { + executeXmlTest("activate-by-node-attribute"); + } + + /** */ + private void executeXmlTest(String conditionType) throws Exception { try ( - IgniteEx node0 = startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node1.xml") - .setGridLogger(listeningLog)) + IgniteEx node0 = + startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node1.xml")) ) { assertTrue(lsnrActNotMeet.check()); assertFalse(lsnrActMeet.check()); assertEquals(node0.cluster().state(), INACTIVE); - startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node2.xml").setGridLogger(listeningLog)); + startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node2.xml")); assertTrue(lsnrActNotMeet.check()); assertFalse(lsnrActMeet.check()); assertEquals(node0.cluster().state(), INACTIVE); - startGrid(loadConfiguration("activate-by-node-attribute/ignite-server-node3.xml").setGridLogger(listeningLog)); + startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node3.xml")); 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 index 4a74c2061..5dc5c96cf 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - 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 index 272e1d5cd..d5294b058 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - 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 index 4c49feca5..9e94e68a3 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - 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 index a04fb04a5..6d4caf9fe 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - 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 index bd7786def..03a24476b 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - 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 index 462c0b9af..2761b8f78 100644 --- 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 @@ -6,93 +6,18 @@ http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 127.0.0.1:47500..47600 - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -104,10 +29,4 @@ - - - - - - diff --git a/modules/auto-activation-ext/src/test/resources/common-ignite-server-node.xml b/modules/auto-activation-ext/src/test/resources/common-ignite-server-node.xml new file mode 100644 index 000000000..6b8a99061 --- /dev/null +++ b/modules/auto-activation-ext/src/test/resources/common-ignite-server-node.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 127.0.0.1:47500..47600 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From ff10fc2624f982d336874d94b58c3bd2dd176069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Sat, 15 Aug 2026 14:08:13 +1000 Subject: [PATCH 5/7] IGNITE-28731 Create cluster auto activation plugin - fix some more issues --- modules/auto-activation-ext/README.md | 10 +- modules/auto-activation-ext/pom.xml | 3 - .../activation/ActivateByConsistentID.java | 10 +- .../activation/ActivateByNodeAttribute.java | 10 +- .../AutoActivationPluginProvider.java | 15 +-- .../ignite/activation/AutoActivationTest.java | 116 +++++++++--------- 6 files changed, 76 insertions(+), 88 deletions(-) diff --git a/modules/auto-activation-ext/README.md b/modules/auto-activation-ext/README.md index 57bae4129..1bfa09314 100644 --- a/modules/auto-activation-ext/README.md +++ b/modules/auto-activation-ext/README.md @@ -2,13 +2,13 @@ Apache Ignite Auto Activation Plugin ------------------------------------ Apache Ignite Auto Activation plugin enables cluster activation at startup, subject to configured conditions. -The plugin skips cluster activation in any of next cases: +The plugin skips cluster activation in the following cases: -- Cluster state is ACTIVE or ACTIVE_READ_ONLY -- Cluster baseline is not empty -- `condition` contains any client node +- Cluster state is either ACTIVE or ACTIVE_READ_ONLY +- Cluster baseline topology is not empty +- The required nodes list for cluster activation contains any client node -Depending on how you use Ignite, you can an extension using one of the following methods: +Depending on how you use Ignite, you can implement 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. diff --git a/modules/auto-activation-ext/pom.xml b/modules/auto-activation-ext/pom.xml index 600856e9e..732400143 100644 --- a/modules/auto-activation-ext/pom.xml +++ b/modules/auto-activation-ext/pom.xml @@ -17,9 +17,6 @@ ~ limitations under the License. --> - 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 index a04813a25..145151fc7 100644 --- 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 @@ -18,9 +18,8 @@ package opt.apache.ignite.activation; import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Set; -import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.lang.IgnitePredicate; @@ -43,16 +42,11 @@ public ActivateByConsistentID(Set requiredNodes) { /** {@inheritDoc} */ @Override public boolean apply(Collection nodes) { - Set missingNodes = new LinkedHashSet<>(requiredNodes); + Set missingNodes = new HashSet<>(requiredNodes); for (ClusterNode node : nodes) { String nodeConsistentId = node.consistentId().toString(); - if (missingNodes.contains(nodeConsistentId) && node.isClient()) { - throw new IgniteException("Auto-activation-plugin supports only server nodes. This node is client: ID " - + node.consistentId() + ", IP " + node.addresses()); - } - missingNodes.remove(nodeConsistentId); if (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 index 167187ecd..a49604650 100644 --- 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 @@ -18,9 +18,8 @@ package opt.apache.ignite.activation; import java.util.Collection; -import java.util.LinkedHashSet; +import java.util.HashSet; import java.util.Set; -import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.lang.IgnitePredicate; @@ -51,16 +50,11 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) /** {@inheritDoc} */ @Override public boolean apply(Collection nodes) { - Set missingNodes = new LinkedHashSet<>(requiredValues); + Set missingNodes = new HashSet<>(requiredValues); for (ClusterNode node : nodes) { String attrVal = node.attribute(attrName); - if (missingNodes.contains(attrVal) && node.isClient()) { - throw new IgniteException("Auto-activation-plugin supports only server nodes. This node is client: ID " - + node.consistentId() + ", IP " + node.addresses()); - } - missingNodes.remove(attrVal); if (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 index 486c077f4..1a27a15ea 100644 --- 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 @@ -36,7 +36,7 @@ import org.apache.ignite.plugin.PluginValidationException; /** - * Activate cluster when specified condition meet + * Activate cluster when specified condition meet. */ public class AutoActivationPluginProvider implements PluginProvider { /** */ @@ -77,7 +77,7 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public String copyright() { - return ""; + return "Apache Software Foundation"; } /** {@inheritDoc} */ @@ -125,16 +125,17 @@ public AutoActivationPluginProvider(IgnitePredicate> con return; } - if (condition.apply(cluster.nodes())) { + if (condition.apply(cluster.forServers().nodes())) { if (logger.isInfoEnabled()) logger.info("Auto activation plugin set cluster state ACTIVE - activation condition meet"); cluster.state(ClusterState.ACTIVE); + + return; } - else { - if (logger.isInfoEnabled()) - logger.info("Auto activation skipped - activation condition not meet"); - } + + if (logger.isInfoEnabled()) + logger.info("Auto activation skipped - activation condition not meet"); } /** {@inheritDoc} */ 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 index 627afefe1..8a27f6d1f 100644 --- 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 @@ -20,10 +20,8 @@ import java.util.Collections; import java.util.Map; import java.util.Set; -import org.apache.ignite.IgniteException; 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; @@ -44,7 +42,7 @@ import static org.apache.ignite.testframework.GridTestUtils.assertThrows; /** - * {@link AutoActivationPluginProvider} test + * Tests {@link AutoActivationPluginProvider}. */ public class AutoActivationTest extends GridCommonAbstractTest { /** Listening test logger. */ @@ -114,28 +112,10 @@ public class AutoActivationTest extends GridCommonAbstractTest { /** {@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 super.getConfiguration(igniteInstanceName) + .setConsistentId(igniteInstanceName) + .setClusterStateOnStart(INACTIVE) + .setGridLogger(listeningLog); } /** @return DataStorageConfiguration. */ @@ -658,44 +638,66 @@ public void testAssertionActivation() throws Exception { /** */ @Test - public void testAssertionActivationByConsistentIdClientNode() throws Exception { - assertThrows( - listeningLog, - () -> { - startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(Set.of(NODE_0, NODE_1))))); - - startGrid(getConfiguration(NODE_1) - .setClientMode(true) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(Set.of(NODE_0, NODE_1))))); - }, - IgniteException.class, - "Auto-activation-plugin supports only server nodes. This node is client: ID " + public void testActivationConditionByConsistentIdNotMeetWithClientNode() throws Exception { + PluginProvider autoActivationProvider = new AutoActivationPluginProvider( + new ActivateByConsistentID(nodesConsistentIds) ); + + try ( + IgniteEx node0 = startGrid(getConfiguration(NODE_0) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setClientMode(true) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_2) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + } } /** */ @Test - public void testAssertionActivationByNodeAttributeClientNode() throws Exception { - assertThrows( - listeningLog, - () -> { - startGrid(getConfiguration(NODE_0) - .setUserAttributes(Map.of(ATTR, ATTR_VAL1)) - .setPluginProviders(new AutoActivationPluginProvider( - new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) - ))); - - startGrid(getConfiguration(NODE_1) - .setClientMode(true) - .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) - .setPluginProviders(new AutoActivationPluginProvider( - new ActivateByNodeAttribute(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)) - ))); - }, - IgniteException.class, - "Auto-activation-plugin supports only server nodes. This node is client: ID " + public void testActivationConditionByNodeAttributeNotMeetWithClientNode() 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)) + ) { + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + + startGrid(getConfiguration(NODE_1) + .setClientMode(true) + .setDataStorageConfiguration(getDataStorageConfiguration()) + .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) + .setPluginProviders(autoActivationProvider)); + + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + } } /** */ From 56834c45865b0c1cfba01734742f8ad9f21e91ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Wed, 26 Aug 2026 14:48:16 +1000 Subject: [PATCH 6/7] IGNITE-28731 Create cluster auto activation plugin - fix some more issues --- .../activation/ActivateByConsistentID.java | 4 +- .../activation/ActivateByNodeAttribute.java | 4 +- .../AutoActivationPluginProvider.java | 3 +- .../ignite/activation/AutoActivationTest.java | 630 +++++------------- 4 files changed, 162 insertions(+), 479 deletions(-) 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 index 145151fc7..7e8760bb1 100644 --- 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 @@ -50,9 +50,9 @@ public ActivateByConsistentID(Set requiredNodes) { missingNodes.remove(nodeConsistentId); if (missingNodes.isEmpty()) - break; + return true; } - return missingNodes.isEmpty(); + return false; } } 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 index a49604650..d7b8e4ea6 100644 --- 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 @@ -58,9 +58,9 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) missingNodes.remove(attrVal); if (missingNodes.isEmpty()) - break; + return true; } - return missingNodes.isEmpty(); + return false; } } 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 index 1a27a15ea..33074c801 100644 --- 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 @@ -92,7 +92,7 @@ public AutoActivationPluginProvider(IgnitePredicate> con } /** {@inheritDoc} */ - @Override public CachePluginProvider createCacheProvider(CachePluginContext cpc) { + @Override public CachePluginProvider createCacheProvider(CachePluginContext cpc) { return null; } @@ -108,7 +108,6 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public void onIgniteStart() { - IgniteCluster cluster = grid.cluster(); if (cluster.state() == ClusterState.ACTIVE || cluster.state() == ClusterState.ACTIVE_READ_ONLY) { 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 index 8a27f6d1f..18adf6985 100644 --- 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 @@ -18,6 +18,7 @@ package opt.apache.ignite.activation; import java.util.Collections; +import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ignite.cache.CacheAtomicityMode; @@ -32,14 +33,14 @@ import org.apache.ignite.testframework.ListeningTestLogger; import org.apache.ignite.testframework.LogListener; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.jetbrains.annotations.NotNull; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; - import static org.apache.ignite.cluster.ClusterState.ACTIVE; import static org.apache.ignite.cluster.ClusterState.ACTIVE_READ_ONLY; import static org.apache.ignite.cluster.ClusterState.INACTIVE; -import static org.apache.ignite.testframework.GridTestUtils.assertThrows; +import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; /** * Tests {@link AutoActivationPluginProvider}. @@ -73,9 +74,6 @@ public class AutoActivationTest extends GridCommonAbstractTest { /** */ private final String NODE_2 = "node_2"; - /** */ - private final String NODE_3 = "node_3"; - /** */ private final String ATTR = "CELL"; @@ -114,10 +112,38 @@ public class AutoActivationTest extends GridCommonAbstractTest { @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { return super.getConfiguration(igniteInstanceName) .setConsistentId(igniteInstanceName) + .setUserAttributes(igniteInstanceName.equals(NODE_2) ? Map.of(ATTR, ATTR_VAL2) : Map.of(ATTR, ATTR_VAL1)) .setClusterStateOnStart(INACTIVE) .setGridLogger(listeningLog); } + /** */ + private IgniteConfiguration getConfiguration(String igniteInstanceName, PluginProvider autoActivationProvider, + String extraCfg) throws Exception { + IgniteConfiguration cfg = getConfiguration(igniteInstanceName).setPluginProviders(autoActivationProvider); + + if (extraCfg != null) { + switch (extraCfg) { + case "cacheConf": + cfg.setCacheConfiguration(getCacheConfiguration()); + break; + case "clientMode": + cfg.setClientMode(igniteInstanceName.equals(NODE_2)); + case "dataStorageConf": + cfg.setDataStorageConfiguration(getDataStorageConfiguration()); + break; + case "active": + cfg.setClusterStateOnStart(ACTIVE); + break; + case "activeReadOnly": + cfg.setClusterStateOnStart(ACTIVE_READ_ONLY); + break; + } + } + + return cfg; + } + /** @return DataStorageConfiguration. */ private DataStorageConfiguration getDataStorageConfiguration() { return new DataStorageConfiguration() @@ -129,15 +155,15 @@ private DataStorageConfiguration getDataStorageConfiguration() { } /** @return DataRegionConfiguration. */ - private DataRegionConfiguration getDataRegionConfiguration() { + private @NotNull DataRegionConfiguration getDataRegionConfiguration() { return new DataRegionConfiguration() .setPersistenceEnabled(true) .setMaxSize(100L * 1024 * 1024); } /** @return CacheConfiguration. */ - private CacheConfiguration getCacheConfiguration() { - return new CacheConfiguration<>() + private CacheConfiguration getCacheConfiguration() { + return new CacheConfiguration() .setName(DEFAULT_CACHE_NAME) .setCacheMode(CacheMode.PARTITIONED) .setBackups(0) @@ -146,570 +172,202 @@ private CacheConfiguration getCacheConfiguration() { } /** @return IgniteConfiguration from XML. */ - private IgniteConfiguration getConfigurationFromXml(String xmlPath) throws Exception { + private IgniteConfiguration getConfigurationFromXml(String xmlPath) { ApplicationContext ctx = new ClassPathXmlApplicationContext("common-ignite-server-node.xml", xmlPath); return ctx.getBean(IgniteConfiguration.class).setGridLogger(listeningLog); } + /** @return PluginProvider ActivateByConsistentID. */ + private PluginProvider getPluginProvider(Set consistentIds) { + return new AutoActivationPluginProvider(new ActivateByConsistentID(consistentIds)); + } + + /** @return PluginProvider ActivateByNodeAttribute. */ + private PluginProvider getPluginProvider(String attrName, Set requiredValues) { + return new AutoActivationPluginProvider(new ActivateByNodeAttribute(attrName, requiredValues)); + } + /** */ @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); - } + executeTest(3, getPluginProvider(nodesConsistentIds), null, List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(Set.of(NODE_0, NODE_1)), null, List.of("actNotMeet", "actMeet", "alreadyAct")); } /** */ @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); - } + executeTest(3, getPluginProvider(Set.of(NODE_2)), null, List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(Set.of(NODE_2)), "cacheConf", List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(Set.of("node_3")), null, List.of("actNotMeet", "actNotMeet", "actNotMeet")); } /** */ @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); - } + executeTest(1, getPluginProvider(Set.of(NODE_0)), "active", List.of("alreadyAct")); } /** */ @Test public void testAlreadyActivatedInMemoryClusterActivationByConsistentIdActiveReadOnly() throws Exception { - PluginProvider autoActivationProvider = new AutoActivationPluginProvider( - new ActivateByConsistentID(Set.of(NODE_0)) - ); - - try ( - IgniteEx node0 = startGrid(getConfiguration(NODE_0) - .setClusterStateOnStart(ACTIVE_READ_ONLY) - .setPluginProviders(autoActivationProvider)) - ) { - assertTrue(lsnrAlreadyAct.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), ACTIVE_READ_ONLY); - } + executeTest(1, getPluginProvider(Set.of(NODE_0)), "activeReadOnly", List.of("alreadyActReadOnly")); } /** */ @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)); + executeTest(3, getPluginProvider(nodesConsistentIds), + "dataStorageConf", List.of("actNotMeet", "actNotMeet", "actMeet")); - 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)); + stopAllGrids(); - startGrid(getConfiguration(NODE_2) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setPluginProviders(autoActivationProvider)); + executeTest(3, getPluginProvider(nodesConsistentIds), + "dataStorageConf", List.of("baseline", "baseline", "baseline")); + } - assertTrue(lsnrBaseline.check()); - assertEquals(restartedNode0.cluster().state(), INACTIVE); - } + /** */ + @Test + public void testActivationConditionByConsistentIdNotMeetWithClientNode() throws Exception { + executeTest(3, getPluginProvider(nodesConsistentIds), "clientMode", + List.of("actNotMeet", "actNotMeet", "actNotMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)), null, + List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1)), null, + List.of("actMeet", "alreadyAct", "alreadyAct")); } /** */ @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); - } + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL2)), null, + List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)), "cacheConf", + List.of("actNotMeet", "actNotMeet", "actMeet")); } /** */ @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); - } + executeTest(3, getPluginProvider(ATTR, Set.of("CELL_03")), null, + List.of("actNotMeet", "actNotMeet", "actNotMeet")); } /** */ @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); - } + executeTest(1, getPluginProvider(ATTR, Set.of(ATTR_VAL1)), "active", List.of("alreadyAct")); } /** */ @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)); + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)), "dataStorageConf", + List.of("actNotMeet", "actNotMeet", "actMeet")); - 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)); + stopAllGrids(); - startGrid(getConfiguration(NODE_2) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) - .setPluginProviders(autoActivationProvider)); + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)), "dataStorageConf", + List.of("baseline", "baseline", "baseline")); + } - assertTrue(lsnrBaseline.check()); - assertEquals(restartedNode0.cluster().state(), INACTIVE); - } + /** */ + @Test + public void testActivationConditionByNodeAttributeNotMeetWithClientNode() throws Exception { + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL1, ATTR_VAL2)), "clientMode", + List.of("actNotMeet", "actNotMeet", "actNotMeet")); } /** */ @Test - public void testAssertionActivation() throws Exception { - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByConsistentID(null)))), - IllegalArgumentException.class, - "requiredNodes must be set" - ); + public void testExceptionActivation() { + executeExceptionTest(ActivateByConsistentID.class, null, null, "requiredNodes must be set"); - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(null, null)))), - IllegalArgumentException.class, - "attributeName must be set" - ); + executeExceptionTest(ActivateByConsistentID.class, null, Collections.emptySet(), "requiredNodes must be set"); - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute("", null)))), - IllegalArgumentException.class, - "attributeName must be set" - ); + executeExceptionTest(ActivateByNodeAttribute.class, null, null, "attributeName must be set"); - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(ATTR, null)))), - IllegalArgumentException.class, - "requiredValues must be set" - ); + executeExceptionTest(ActivateByNodeAttribute.class, "", null, "attributeName must be set"); - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(new ActivateByNodeAttribute(ATTR, Collections.emptySet())))), - IllegalArgumentException.class, - "requiredValues must be set" - ); + executeExceptionTest(ActivateByNodeAttribute.class, ATTR, null, "requiredValues must be set"); - assertThrows( - listeningLog, - () -> startGrid(getConfiguration(NODE_0) - .setPluginProviders(new AutoActivationPluginProvider(null))), - IllegalArgumentException.class, - "Auto activation condition must be set" - ); + executeExceptionTest(ActivateByNodeAttribute.class, ATTR, Collections.emptySet(), "requiredValues must be set"); + + executeExceptionTest(null, null, null, "Auto activation condition must be set"); } /** */ @Test - public void testActivationConditionByConsistentIdNotMeetWithClientNode() throws Exception { - PluginProvider autoActivationProvider = new AutoActivationPluginProvider( - new ActivateByConsistentID(nodesConsistentIds) - ); - - try ( - IgniteEx node0 = startGrid(getConfiguration(NODE_0) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setPluginProviders(autoActivationProvider)) - ) { - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); - - startGrid(getConfiguration(NODE_1) - .setClientMode(true) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setPluginProviders(autoActivationProvider)); - - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); - - startGrid(getConfiguration(NODE_2) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setPluginProviders(autoActivationProvider)); - - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); - } + public void testXmlCfgPersistenceClusterActivationByConsistentId() throws Exception { + executeXmlTest("activate-by-consistent-ID"); } /** */ @Test - public void testActivationConditionByNodeAttributeNotMeetWithClientNode() 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)) - ) { - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); - - startGrid(getConfiguration(NODE_1) - .setClientMode(true) - .setDataStorageConfiguration(getDataStorageConfiguration()) - .setUserAttributes(Map.of(ATTR, ATTR_VAL2)) - .setPluginProviders(autoActivationProvider)); - - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); - } + public void testXmlCfgPersistenceClusterActivationByNodeAttribute() throws Exception { + executeXmlTest("activate-by-node-attribute"); } /** */ - @Test - public void testXmlCfgPersistenceClusterActivationByConsistentId() throws Exception { - executeXmlTest("activate-by-consistent-ID"); + private void executeTest(int nodesCount, PluginProvider autoActivationProvider, + String extraCfg, List assertions) throws Exception { + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0, autoActivationProvider, extraCfg))) { + assertion(node0, assertions.get(0)); + + if (nodesCount > 1) { + for (int i = 1; i < nodesCount; i++) { + startGrid(getConfiguration("node_" + i, autoActivationProvider, extraCfg)); + + assertion(node0, assertions.get(i)); + } + } + } } /** */ - @Test - public void testXmlCfgPersistenceClusterActivationByNodeAttribute() throws Exception { - executeXmlTest("activate-by-node-attribute"); + private void executeExceptionTest(Class condition, String attributeName, + Set nodesOrAttrValues, String exceptionMessage) { + assertThrowsAnyCause( + listeningLog, + () -> startGrid(getConfiguration(NODE_0) + .setPluginProviders(new AutoActivationPluginProvider( + (condition == null) ? null : condition == ActivateByConsistentID.class + ? new ActivateByConsistentID(nodesOrAttrValues) + : new ActivateByNodeAttribute(attributeName, nodesOrAttrValues)))), + IllegalArgumentException.class, + exceptionMessage + ); } /** */ @@ -718,20 +376,46 @@ private void executeXmlTest(String conditionType) throws Exception { IgniteEx node0 = startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node1.xml")) ) { - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); + assertion(node0, "actNotMeet"); startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node2.xml")); - assertTrue(lsnrActNotMeet.check()); - assertFalse(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), INACTIVE); + assertion(node0, "actNotMeet"); startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node3.xml")); - assertTrue(lsnrActMeet.check()); - assertEquals(node0.cluster().state(), ACTIVE); + assertion(node0, "actMeet"); + } + } + + /** */ + private void assertion(IgniteEx node0, String assertion) { + switch (assertion) { + case "actNotMeet": + assertTrue(lsnrActNotMeet.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), INACTIVE); + break; + case "actMeet": + assertTrue(lsnrActMeet.check()); + assertFalse(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + break; + case "alreadyActFalseAndActMeet": + assertFalse(lsnrActMeet.check()); + case "alreadyAct": + assertTrue(lsnrAlreadyAct.check()); + assertEquals(node0.cluster().state(), ACTIVE); + break; + case "alreadyActReadOnly": + assertTrue(lsnrAlreadyAct.check()); + assertFalse(lsnrActMeet.check()); + assertEquals(node0.cluster().state(), ACTIVE_READ_ONLY); + break; + case "baseline": + assertTrue(lsnrBaseline.check()); + assertEquals(node0.cluster().state(), INACTIVE); + break; } } } From 4f59e82e3a3dc6e03f5cecc440cae5781fb87b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=BE=D0=BB=D0=BE=D0=B6=D0=B0=D0=B5=D0=B2=20=D0=94?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D1=81=20=D0=90=D0=BB=D0=B5=D0=BA=D1=81=D0=B0?= =?UTF-8?q?=D0=BD=D0=B4=D1=80=D0=BE=D0=B2=D0=B8=D1=87?= Date: Mon, 7 Sep 2026 12:07:59 +1000 Subject: [PATCH 7/7] IGNITE-28731 Create cluster auto activation plugin - log extension --- modules/auto-activation-ext/README.md | 20 ++++++++-- .../activation/ActivateByConsistentID.java | 25 +++++++++--- .../activation/ActivateByNodeAttribute.java | 30 ++++++++++---- .../AutoActivationPluginProvider.java | 32 ++++++++------- .../ignite/activation/AutoActivationTest.java | 40 ++++++++++++++++++- 5 files changed, 116 insertions(+), 31 deletions(-) diff --git a/modules/auto-activation-ext/README.md b/modules/auto-activation-ext/README.md index 1bfa09314..c3ff86ec9 100644 --- a/modules/auto-activation-ext/README.md +++ b/modules/auto-activation-ext/README.md @@ -4,9 +4,23 @@ Apache Ignite Auto Activation plugin enables cluster activation at startup, subj The plugin skips cluster activation in the following cases: -- Cluster state is either ACTIVE or ACTIVE_READ_ONLY -- Cluster baseline topology is not empty -- The required nodes list for cluster activation contains any client node +- Cluster state is either ACTIVE or ACTIVE_READ_ONLY, log message: +```text + [DateTime][INFO][main][AutoActivationPluginProvider] Auto activation skipped - cluster already activated +``` +- Cluster baseline topology is not empty, log message: +```text + [DateTime][INFO][main][AutoActivationPluginProvider] Auto activation skipped - baseline is not empty +``` +- The baseline topology does not include all nodes listed for activation. A message containing the consistentIds of the missing nodes will be written to ignite.log: +```text + [DateTime][INFO][main][AutoActivationPluginProvider] Auto activation skipped - activation condition not meet (by consistent ID). Missing nodes [, , ...] +``` +- The node attributes in the topology do not contain the full list of values specified in the cluster's auto-activation settings. The log message will indicate the attribute name and list the missing values as follows: +```text +[DateTime][INFO][main][AutoActivationPluginProvider] Auto activation skipped - activation condition not meet (by node attribute). Attribute: , Missing values [, , ...] +``` +- The required nodes list for cluster activation contains any client node. In this case, the node will simply not participate in cluster activation, and the log message will be identical to that of a missing node. Depending on how you use Ignite, you can implement an extension using one of the following methods: 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 index 7e8760bb1..2eb189b37 100644 --- 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 @@ -17,16 +17,18 @@ package opt.apache.ignite.activation; -import java.util.Collection; import java.util.HashSet; import java.util.Set; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteMessaging; +import org.apache.ignite.cluster.ClusterGroup; 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> { +public class ActivateByConsistentID implements IgnitePredicate { /** Collection of required nodes ConsistentIDs. */ private final Set requiredNodes; @@ -41,18 +43,31 @@ public ActivateByConsistentID(Set requiredNodes) { } /** {@inheritDoc} */ - @Override public boolean apply(Collection nodes) { + @Override public boolean apply(Ignite grid) { Set missingNodes = new HashSet<>(requiredNodes); + ClusterGroup servers = grid.cluster().forServers(); + IgniteMessaging messaging = grid.message(servers); - for (ClusterNode node : nodes) { + for (ClusterNode node : servers.nodes()) { String nodeConsistentId = node.consistentId().toString(); missingNodes.remove(nodeConsistentId); - if (missingNodes.isEmpty()) + if (missingNodes.isEmpty()) { + messaging.send( + "auto-activation-plugin-events", + "Auto activation plugin set cluster state ACTIVE - activation condition meet (by consistent ID)" + ); + return true; + } } + messaging.send( + "auto-activation-plugin-events", + "Auto activation skipped - activation condition not meet (by consistent ID). Missing nodes " + + "[" + String.join(", ", missingNodes) + "]"); + return false; } } 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 index d7b8e4ea6..913447caa 100644 --- 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 @@ -17,16 +17,18 @@ package opt.apache.ignite.activation; -import java.util.Collection; import java.util.HashSet; import java.util.Set; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteMessaging; +import org.apache.ignite.cluster.ClusterGroup; 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> { +public class ActivateByNodeAttribute implements IgnitePredicate { /** Node's attribute name. */ private final String attrName; @@ -49,18 +51,32 @@ public ActivateByNodeAttribute(String attributeName, Set requiredValues) } /** {@inheritDoc} */ - @Override public boolean apply(Collection nodes) { - Set missingNodes = new HashSet<>(requiredValues); + @Override public boolean apply(Ignite grid) { + Set missingValues = new HashSet<>(requiredValues); - for (ClusterNode node : nodes) { + ClusterGroup servers = grid.cluster().forServers(); + + IgniteMessaging messaging = grid.message(servers); + + for (ClusterNode node : servers.nodes()) { String attrVal = node.attribute(attrName); - missingNodes.remove(attrVal); + missingValues.remove(attrVal); + + if (missingValues.isEmpty()) { + messaging.send( + "auto-activation-plugin-events", + "Auto activation plugin set cluster state ACTIVE - activation condition meet (by node attribute)" + ); - if (missingNodes.isEmpty()) return true; + } } + messaging.send("auto-activation-plugin-events", + "Auto activation skipped - activation condition not meet (by node attribute). " + + "Attribute: " + attrName + ", Missing values [" + String.join(", ", missingValues) + "]"); + return false; } } 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 index 33074c801..4997ad365 100644 --- 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 @@ -18,7 +18,6 @@ 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; @@ -40,7 +39,7 @@ */ public class AutoActivationPluginProvider implements PluginProvider { /** */ - private final IgnitePredicate> condition; + private final IgnitePredicate condition; /** */ private IgniteLogger logger; @@ -51,7 +50,7 @@ public class AutoActivationPluginProvider implements PluginProvider> condition) { + public AutoActivationPluginProvider(IgnitePredicate condition) { if (condition == null) throw new IllegalArgumentException("Auto activation condition must be set"); @@ -82,7 +81,7 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public void initExtensions(PluginContext pc, ExtensionRegistry er) { - logger = pc.log(this.getClass()); + logger = pc.log(this.getClass()); grid = pc.grid(); } @@ -108,6 +107,15 @@ public AutoActivationPluginProvider(IgnitePredicate> con /** {@inheritDoc} */ @Override public void onIgniteStart() { + grid.message(grid.cluster().forServers()).localListen( + "auto-activation-plugin-events", + (nodeId, message) -> { + logger.info(String.valueOf(message)); + + return true; + } + ); + IgniteCluster cluster = grid.cluster(); if (cluster.state() == ClusterState.ACTIVE || cluster.state() == ClusterState.ACTIVE_READ_ONLY) { @@ -124,17 +132,8 @@ public AutoActivationPluginProvider(IgnitePredicate> con return; } - if (condition.apply(cluster.forServers().nodes())) { - if (logger.isInfoEnabled()) - logger.info("Auto activation plugin set cluster state ACTIVE - activation condition meet"); - + if (condition.apply(grid)) cluster.state(ClusterState.ACTIVE); - - return; - } - - if (logger.isInfoEnabled()) - logger.info("Auto activation skipped - activation condition not meet"); } /** {@inheritDoc} */ @@ -156,4 +155,9 @@ public AutoActivationPluginProvider(IgnitePredicate> con @Override public void validateNewNode(ClusterNode cn) throws PluginValidationException { // No-op. } + + /** @return Condition. */ + public IgnitePredicate getCondition() { + return condition; + } } 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 index 18adf6985..4b297fca7 100644 --- 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 @@ -21,6 +21,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.regex.Pattern; import org.apache.ignite.cache.CacheAtomicityMode; import org.apache.ignite.cache.CacheMode; import org.apache.ignite.configuration.CacheConfiguration; @@ -65,6 +66,9 @@ public class AutoActivationTest extends GridCommonAbstractTest { private final LogListener lsnrActNotMeet = LogListener .matches("Auto activation skipped - activation condition not meet").build(); + /** */ + private LogListener lsnrMissed; + /** */ private final String NODE_0 = "node_0"; @@ -74,6 +78,9 @@ public class AutoActivationTest extends GridCommonAbstractTest { /** */ private final String NODE_2 = "node_2"; + /** */ + private final String NODE_3 = "node_3"; + /** */ private final String ATTR = "CELL"; @@ -83,6 +90,9 @@ public class AutoActivationTest extends GridCommonAbstractTest { /** */ private final String ATTR_VAL2 = "CELL_02"; + /** */ + private final String ATTR_VAL3 = "CELL_03"; + /** */ private final Set nodesConsistentIds = Set.of(NODE_0, NODE_1, NODE_2); @@ -215,7 +225,7 @@ public void testSuccessfulInMemoryClusterActivationByConsistentIdAllNodesPlusCac /** */ @Test public void testActivationNotMetInMemoryClusterActivationByConsistentId() throws Exception { - executeTest(3, getPluginProvider(Set.of("node_3")), null, List.of("actNotMeet", "actNotMeet", "actNotMeet")); + executeTest(3, getPluginProvider(Set.of(NODE_3)), null, List.of("actNotMeet", "actNotMeet", "actNotMeet")); } /** */ @@ -280,7 +290,7 @@ public void testSuccessfulInMemoryClusterActivationByNodeAttributeAllAttrsPlusCa /** */ @Test public void testActivationNotMetInMemoryClusterActivationByNodeAttribute() throws Exception { - executeTest(3, getPluginProvider(ATTR, Set.of("CELL_03")), null, + executeTest(3, getPluginProvider(ATTR, Set.of(ATTR_VAL3)), null, List.of("actNotMeet", "actNotMeet", "actNotMeet")); } @@ -342,6 +352,23 @@ public void testXmlCfgPersistenceClusterActivationByNodeAttribute() throws Excep /** */ private void executeTest(int nodesCount, PluginProvider autoActivationProvider, String extraCfg, List assertions) throws Exception { + AutoActivationPluginProvider provider = (AutoActivationPluginProvider)autoActivationProvider; + + log.info("Classs. " + provider.getCondition()); + log.info("Classs. " + autoActivationProvider.copyright()); + log.info("Classs. " + autoActivationProvider.version()); + log.info("Classs. " + autoActivationProvider.toString()); + Pattern missed = Pattern + .compile(provider.getCondition().getClass().equals(ActivateByConsistentID.class) + ? "\\(by consistent ID\\)\\. " + + "Missing nodes \\[(?:(?=.*" + NODE_1 + ")|(?=.*" + NODE_2 + ")|(?=.*" + NODE_3 + ")).+]" + : "\\(by node attribute\\)\\. Attribute: " + ATTR + ", " + + "Missing values \\[(?:(?=.*" + ATTR_VAL2 + ")|(?=.*" + ATTR_VAL3 + ")).+]"); + + lsnrMissed = LogListener.matches(missed).build(); + + listeningLog.registerListener(lsnrMissed); + try (IgniteEx node0 = startGrid(getConfiguration(NODE_0, autoActivationProvider, extraCfg))) { assertion(node0, assertions.get(0)); @@ -372,6 +399,14 @@ private void executeExceptionTest(Class condition, String attributeName, /** */ private void executeXmlTest(String conditionType) throws Exception { + lsnrMissed = LogListener + .matches(Pattern.compile(conditionType.equals("activate-by-consistent-ID") + ? "\\(by consistent ID\\)\\. Missing nodes \\[(?:(?=.*cell-2_node-1)|(?=.*cell-1_node-2)).+]" + : "\\(by node attribute\\)\\. Attribute: " + ATTR + ", Missing values \\[(?=.*CELL_2).+]")) + .build(); + + listeningLog.registerListener(lsnrMissed); + try ( IgniteEx node0 = startGrid(getConfigurationFromXml(conditionType + "/ignite-server-node1.xml")) @@ -393,6 +428,7 @@ private void assertion(IgniteEx node0, String assertion) { switch (assertion) { case "actNotMeet": assertTrue(lsnrActNotMeet.check()); + assertTrue(lsnrMissed.check()); assertFalse(lsnrActMeet.check()); assertEquals(node0.cluster().state(), INACTIVE); break;