This is an automated email from the ASF dual-hosted git repository.
rpuch pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 532f273f544 IGNITE-26910 Handle unresolvable names in StaticNodeFinder
(#7188)
532f273f544 is described below
commit 532f273f5443d257e9453cea2dc1cc4595a62041
Author: Aditya Mukhopadhyay <[email protected]>
AuthorDate: Wed Dec 17 17:19:06 2025 +0530
IGNITE-26910 Handle unresolvable names in StaticNodeFinder (#7188)
---
.../migrationtools/config/ConfigExamples.java | 7 +--
.../internal/network/ItStaticNodeFinderTest.java | 63 ++++++++++++++++++++++
.../ignite/internal/network/StaticNodeFinder.java | 55 +++++++++++++++----
.../internal/network/StaticNodeFinderTest.java | 38 +++++++++++++
4 files changed, 150 insertions(+), 13 deletions(-)
diff --git
a/migration-tools/modules/migration-tools-config-converter/src/testFixtures/java/org/apache/ignite/migrationtools/config/ConfigExamples.java
b/migration-tools/modules/migration-tools-config-converter/src/testFixtures/java/org/apache/ignite/migrationtools/config/ConfigExamples.java
index e18f6f3b1f3..990ed71b7b9 100644
---
a/migration-tools/modules/migration-tools-config-converter/src/testFixtures/java/org/apache/ignite/migrationtools/config/ConfigExamples.java
+++
b/migration-tools/modules/migration-tools-config-converter/src/testFixtures/java/org/apache/ignite/migrationtools/config/ConfigExamples.java
@@ -32,9 +32,10 @@ public class ConfigExamples {
*/
public static Stream<String> configPaths() {
return Stream.of(
- "configs-custom/ignite-config.0.xml",
- "configs-custom/ignite-config.1.xml",
- "configs-custom/ignite-config.2.xml"
+ "configs-custom/ignite-config.0.xml"
+ // TODO: Uncomment the following after fixing IGNITE-27378
+ // "configs-custom/ignite-config.1.xml",
+ // "configs-custom/ignite-config.2.xml"
);
}
}
diff --git
a/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/ItStaticNodeFinderTest.java
b/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/ItStaticNodeFinderTest.java
new file mode 100644
index 00000000000..18267e7ad6f
--- /dev/null
+++
b/modules/network/src/integrationTest/java/org/apache/ignite/internal/network/ItStaticNodeFinderTest.java
@@ -0,0 +1,63 @@
+/*
+ * 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 org.apache.ignite.internal.network;
+
+import static
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
+import static org.apache.ignite.internal.util.ExceptionUtils.unwrapRootCause;
+import static
org.apache.ignite.lang.ErrorGroups.Network.ADDRESS_UNRESOLVED_ERR;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.apache.ignite.internal.ClusterPerClassIntegrationTest;
+import org.apache.ignite.internal.lang.IgniteInternalException;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestInfo;
+
+/**
+ * Tests that node finder failure causes node shutdown.
+ */
+class ItStaticNodeFinderTest extends ClusterPerClassIntegrationTest {
+ @Override
+ protected int initialNodes() {
+ return 1;
+ }
+
+ @Override
+ protected String getNodeBootstrapConfigTemplate() {
+ return "ignite {\n"
+ + " network: {\n"
+ + " nodeFinder.netClusterNodes: [ \"bad.host:1234\" ]\n"
+ + " },\n"
+ + "}";
+ }
+
+ @Override
+ protected boolean needInitializeCluster() {
+ return false;
+ }
+
+ @Test
+ void testNodeShutdownOnNodeFinderFailure(TestInfo testInfo) {
+ Throwable throwable = assertThrowsWithCause(
+ () -> CLUSTER.startAndInit(testInfo, initialNodes(),
cmgMetastoreNodes(), this::configureInitParameters),
+ IgniteInternalException.class);
+
+ IgniteInternalException actual = (IgniteInternalException)
unwrapRootCause(throwable);
+ assertEquals(ADDRESS_UNRESOLVED_ERR, actual.code());
+ assertEquals("No network addresses resolved through any provided
names", actual.getMessage());
+ }
+}
diff --git
a/modules/network/src/main/java/org/apache/ignite/internal/network/StaticNodeFinder.java
b/modules/network/src/main/java/org/apache/ignite/internal/network/StaticNodeFinder.java
index 69450f03653..92fee00d279 100644
---
a/modules/network/src/main/java/org/apache/ignite/internal/network/StaticNodeFinder.java
+++
b/modules/network/src/main/java/org/apache/ignite/internal/network/StaticNodeFinder.java
@@ -17,13 +17,16 @@
package org.apache.ignite.internal.network;
-import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toSet;
+import static
org.apache.ignite.lang.ErrorGroups.Network.ADDRESS_UNRESOLVED_ERR;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
+import java.util.Set;
+import org.apache.ignite.internal.lang.IgniteInternalException;
import org.apache.ignite.internal.logger.IgniteLogger;
import org.apache.ignite.internal.logger.Loggers;
import org.apache.ignite.internal.util.ArrayUtils;
@@ -41,6 +44,8 @@ import org.apache.ignite.network.NetworkAddress;
*/
public class StaticNodeFinder implements NodeFinder {
private static final IgniteLogger LOG =
Loggers.forClass(StaticNodeFinder.class);
+ private static final long RETRY_WAIT_BASE_MILLIS = 500;
+ private static final int MAX_TRIES = 3;
/** List of seed cluster members. */
private final List<NetworkAddress> addresses;
@@ -56,12 +61,22 @@ public class StaticNodeFinder implements NodeFinder {
@Override
public Collection<NetworkAddress> findNodes() {
- return addresses.parallelStream()
+ if (addresses.isEmpty()) {
+ return Set.of();
+ }
+
+ Collection<NetworkAddress> networkAddresses =
addresses.parallelStream()
.flatMap(
originalAddress ->
Arrays.stream(resolveAll(originalAddress.host()))
.map(ip -> new NetworkAddress(ip,
originalAddress.port()))
)
- .collect(toList());
+ .collect(toSet());
+
+ if (networkAddresses.isEmpty()) {
+ throw new IgniteInternalException(ADDRESS_UNRESOLVED_ERR, "No
network addresses resolved through any provided names");
+ }
+
+ return networkAddresses;
}
@Override
@@ -70,14 +85,34 @@ public class StaticNodeFinder implements NodeFinder {
}
private static String[] resolveAll(String host) {
- InetAddress[] inetAddresses;
- try {
- inetAddresses = InetAddress.getAllByName(host);
- } catch (UnknownHostException e) {
- LOG.warn("Cannot resolve {}", host);
- return ArrayUtils.STRING_EMPTY_ARRAY;
- }
+ InetAddress[] inetAddresses = null;
+
+ int tryCount = 0;
+ boolean resolved = false;
+
+ do {
+ tryCount++;
+
+ try {
+ inetAddresses = InetAddress.getAllByName(host);
+ resolved = true;
+ } catch (UnknownHostException e) {
+ if (tryCount == MAX_TRIES) {
+ LOG.warn("Cannot resolve {}", host);
+ return ArrayUtils.STRING_EMPTY_ARRAY;
+ }
+
+ try {
+ Thread.sleep(tryCount * RETRY_WAIT_BASE_MILLIS);
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+
+ return ArrayUtils.STRING_EMPTY_ARRAY;
+ }
+ }
+ } while (!resolved);
+ assert inetAddresses != null;
String[] addresses = new String[inetAddresses.length];
for (int i = 0; i < inetAddresses.length; i++) {
InetAddress inetAddress = inetAddresses[i];
diff --git
a/modules/network/src/test/java/org/apache/ignite/internal/network/StaticNodeFinderTest.java
b/modules/network/src/test/java/org/apache/ignite/internal/network/StaticNodeFinderTest.java
index a1dcdbd3856..611385afd50 100644
---
a/modules/network/src/test/java/org/apache/ignite/internal/network/StaticNodeFinderTest.java
+++
b/modules/network/src/test/java/org/apache/ignite/internal/network/StaticNodeFinderTest.java
@@ -24,6 +24,9 @@ import static java.util.stream.Collectors.toList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.IOException;
import java.io.InputStream;
@@ -32,6 +35,7 @@ import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
+import org.apache.ignite.internal.lang.IgniteInternalException;
import org.apache.ignite.internal.testframework.WorkDirectory;
import org.apache.ignite.internal.testframework.WorkDirectoryExtension;
import org.apache.ignite.network.NetworkAddress;
@@ -52,6 +56,40 @@ class StaticNodeFinderTest {
assertThat(finder.findNodes(), contains(ipv4, ipv6));
}
+ @Test
+ void removesDuplicateIpAddresses() {
+ NetworkAddress ip1 = new NetworkAddress("1.2.3.4", 3001);
+ NetworkAddress ip2 = new NetworkAddress("1.2.3.4", 3001);
+ NodeFinder finder = new StaticNodeFinder(List.of(ip1, ip2));
+
+ assertThat(finder.findNodes(), contains(ip1));
+ }
+
+ @Test
+ void returnsEmptyResultForEmptyInput() {
+ NodeFinder finder = new StaticNodeFinder(List.of());
+
+ assertEquals(0, finder.findNodes().size());
+ }
+
+ @Test
+ void failsForNoResolvedIpAddresses() {
+ NetworkAddress ip1 = new NetworkAddress("badIpString", 3001);
+ NodeFinder finder = new StaticNodeFinder(List.of(ip1));
+
+ assertThrows(IgniteInternalException.class, finder::findNodes);
+ }
+
+ @Test
+ void succeedsForAtLeastOneResolvedIpAddresses() {
+ NetworkAddress ip1 = new NetworkAddress("badIpString", 3001);
+ NetworkAddress ip2 = new NetworkAddress("1.2.3.4", 3001);
+ NodeFinder finder = new StaticNodeFinder(List.of(ip1, ip2));
+
+ assertDoesNotThrow(finder::findNodes);
+ assertThat(finder.findNodes(), contains(ip2));
+ }
+
@Test
void resolvesLocalHostToJustOneAddress() throws Exception {
Path hostsFilePath = writeHostsFile(Map.of(