diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java index 78590d330cbf2..199e45fb37793 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/encryption/GridEncryptionManager.java @@ -433,7 +433,7 @@ public void onLocalJoin() { /** {@inheritDoc} */ @Override public void collectJoiningNodeData(DiscoveryDataBag dataBag) { - if (dataBag.isJoiningNodeClient()) + if (ctx.clientNode()) return; HashMap knownEncKeys = knownEncryptionKeys(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java index 88a9fde320f28..96ca0072e3585 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java @@ -1864,9 +1864,10 @@ else if (joiningNodeData instanceof CacheJoinNodeDiscoveryData) /** * @param data Joining node data. + * @param joiningNodeClient Joining node is client flag. * @return Message with error or null if everything was OK. */ - public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData data) { + public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData data, boolean joiningNodeClient) { if (data.hasJoiningNodeData()) { Serializable joiningNodeData = data.joiningNodeData(); @@ -1874,6 +1875,7 @@ public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData CacheJoinNodeDiscoveryData joinData = (CacheJoinNodeDiscoveryData)joiningNodeData; Set problemCaches = null; + Set encClientCaches = null; for (CacheJoinNodeDiscoveryData.CacheInfo cacheInfo : joinData.caches().values()) { CacheConfiguration cfg = cacheInfo.cacheData().config(); @@ -1895,6 +1897,12 @@ public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData problemCaches.add(cfg.getName()); } + else if (joiningNodeClient && cfg.isEncryptionEnabled()) { + if (encClientCaches == null) + encClientCaches = new HashSet<>(); + + encClientCaches.add(cfg.getName()); + } } } @@ -1903,6 +1911,14 @@ public String validateJoiningNodeData(DiscoveryDataBag.JoiningNodeDiscoveryData "Joining node has caches with data which are not presented on cluster, " + "it could mean that they were already destroyed, to add the node to cluster - " + "remove directories with the caches[", "]")); + + if (!F.isEmpty(encClientCaches)) { + return encClientCaches.stream().collect(Collectors.joining(", ", + "Joining node has encrypted caches which are not presented on the cluster, " + + "encrypted caches configured on client node cannot be started when such node joins " + + "the cluster, these caches can be started manually (dynamically) after node joined" + + "[caches=", "]")); + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index d3beafcc91e36..465473aaba93b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -3106,7 +3106,7 @@ private GridCacheSharedContext createSharedContext( if (!cachesInfo.isMergeConfigSupports(node)) return null; - String validationRes = cachesInfo.validateJoiningNodeData(discoData); + String validationRes = cachesInfo.validateJoiningNodeData(discoData, node.isClient()); if (validationRes != null) return new IgniteNodeValidationResult(node.id(), validationRes, validationRes); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java index cdf802bf17f99..2391bdb0643be 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/encryption/EncryptedCacheNodeJoinTest.java @@ -17,12 +17,16 @@ package org.apache.ignite.internal.encryption; +import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.cluster.ClusterState; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.util.IgniteUtils; +import org.apache.ignite.spi.IgniteSpiException; import org.apache.ignite.spi.encryption.keystore.KeystoreEncryptionSpi; +import org.apache.ignite.testframework.GridTestUtils; import org.junit.Test; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; @@ -42,6 +46,12 @@ public class EncryptedCacheNodeJoinTest extends AbstractEncryptionTest { /** */ private static final String GRID_5 = "grid-5"; + /** */ + private static final String GRID_6 = "grid-6"; + + /** */ + private static final String GRID_7 = "grid-7"; + /** */ public static final String CLIENT = "client"; @@ -76,7 +86,9 @@ public class EncryptedCacheNodeJoinTest extends AbstractEncryptionTest { grid.equals(GRID_2) || grid.equals(GRID_3) || grid.equals(GRID_4) || - grid.equals(GRID_5)) { + grid.equals(GRID_5) || + grid.equals(GRID_6) || + grid.equals(GRID_7)) { KeystoreEncryptionSpi encSpi = new KeystoreEncryptionSpi(); encSpi.setKeyStorePath(grid.equals(GRID_2) ? KEYSTORE_PATH_2 : KEYSTORE_PATH); @@ -98,7 +110,12 @@ protected CacheConfiguration cacheConfiguration(String gridName) { CacheConfiguration ccfg = defaultCacheConfiguration(); ccfg.setName(cacheName()); - ccfg.setEncryptionEnabled(gridName.equals(GRID_0)); + + if (gridName.startsWith(CLIENT) || + gridName.equals(GRID_0) || + gridName.equals(GRID_6) || + gridName.equals(GRID_7)) + ccfg.setEncryptionEnabled(true); return ccfg; } @@ -204,6 +221,103 @@ public void testClientNodeJoin() throws Exception { createEncryptedCache(client, grid0, cacheName(), null); } + /** */ + @Test + public void testClientNodeJoinActiveClusterWithNewStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(true, true, true); + } + + /** */ + @Test + public void testClientNodeJoinActiveClusterWithExistingStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(true, true, false); + } + + /** */ + @Test + public void testClientNodeJoinInactiveClusterWithNewStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(true, false, true); + } + + /** */ + @Test + public void testClientNodeJoinInactiveClusterWithExistingStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(true, false, false); + } + + /** */ + @Test + public void testServerNodeJoinActiveClusterWithNewStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(false, true, true); + } + + /** */ + @Test + public void testServerNodeJoinInactiveClusterWithNewStaticCacheConfig() throws Exception { + checkNodeJoinWithStaticCacheConfig(false, false, true); + } + + /** + * @param client {@code True} to test client node join, {@code False} to test server node join. + * @param activateBeforeJoin {@code True} to activate the server before joining the client node. + * @param newCfg {@code True} to configure cache on the last joined node. {@code False} to configure on all nodes. + */ + private void checkNodeJoinWithStaticCacheConfig( + boolean client, + boolean activateBeforeJoin, + boolean newCfg + ) throws Exception { + if (!newCfg) + configureCache = true; + + startGrid(GRID_0); + startGrid(GRID_6); + + IgniteEx client1 = startClientGrid("client1"); + + if (newCfg) + configureCache = true; + + if (activateBeforeJoin) + grid(GRID_0).cluster().state(ClusterState.ACTIVE); + + if (client && newCfg) { + String expErrMsg = "Joining node has encrypted caches which are not presented on the cluster, " + + "encrypted caches configured on client node cannot be started when such node joins " + + "the cluster, these caches can be started manually (dynamically) after node is joined " + + "[caches=" + cacheName() + ']'; + + GridTestUtils.assertThrowsAnyCause(log, () -> startClientGrid(CLIENT), IgniteSpiException.class, expErrMsg); + + return; + } + + IgniteEx node = client ? startClientGrid(CLIENT) : startGrid(GRID_7); + + if (!activateBeforeJoin) + grid(GRID_0).cluster().state(ClusterState.ACTIVE); + + awaitPartitionMapExchange(); + + IgniteCache cache = node.cache(cacheName()); + + assertNotNull(cache); + + for (long i = 0; i < 100; i++) + cache.put(i, String.valueOf(i)); + + checkEncryptedCaches(grid(GRID_0), grid(GRID_6)); + checkEncryptedCaches(grid(GRID_0), client1); + checkData(client1); + + if (client) { + checkEncryptedCaches(grid(GRID_0), grid(CLIENT)); + checkData(grid(CLIENT)); + } + else + checkEncryptedCaches(grid(GRID_7), grid(GRID_0)); + } + /** */ @Test public void testNodeCantJoinWithSameNameButNotEncCache() throws Exception { diff --git a/modules/spring/src/test/config/enc/enc-cache-client.xml b/modules/spring/src/test/config/enc/enc-cache-client.xml index ba4068a4606a7..6ebef07a3a84d 100644 --- a/modules/spring/src/test/config/enc/enc-cache-client.xml +++ b/modules/spring/src/test/config/enc/enc-cache-client.xml @@ -23,7 +23,7 @@ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> - +