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(

Reply via email to