From 169d4b617e205ce551dc28f1b00a5483fbeb286a Mon Sep 17 00:00:00 2001 From: Martin Furmanski Date: Thu, 29 Jun 2017 17:37:45 +0200 Subject: [PATCH] Support ipv6 in switch role uri creation --- .../kernel/ha/cluster/SwitchToMaster.java | 28 ++++++++--- .../kernel/ha/cluster/SwitchToSlave.java | 26 ++++++++-- .../kernel/ha/HaIPv6ConfigurationTest.java | 33 +++++++++---- .../kernel/ha/cluster/SwitchToMasterTest.java | 48 +++++++++++++++++++ 4 files changed, 115 insertions(+), 20 deletions(-) diff --git a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToMaster.java b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToMaster.java index f3eba09e8e581..b2febea9a7344 100644 --- a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToMaster.java +++ b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToMaster.java @@ -19,6 +19,8 @@ */ package org.neo4j.kernel.ha.cluster; +import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.URI; import java.util.function.BiFunction; import java.util.function.Supplier; @@ -123,17 +125,31 @@ public URI switchToMaster( LifeSupport haCommunicationLife, URI me ) static URI getMasterUri( URI me, MasterServer masterServer, Config config ) { - String hostname = config.get( HaSettings.ha_server ).getHost(); - if ( hostname == null || hostname.contains( "0.0.0.0" ) ) + InetSocketAddress masterSocketAddress = masterServer.getSocketAddress(); + + if ( hostname == null || isWildcard( hostname ) ) { - String masterAddress = ServerUtil.getHostString( masterServer.getSocketAddress() ); - hostname = masterAddress.contains( "0.0.0.0" ) ? me.getHost() : masterAddress; + InetAddress masterAddress = masterSocketAddress.getAddress(); + hostname = masterAddress.isAnyLocalAddress() ? me.getHost() : ServerUtil.getHostString( masterSocketAddress ); + hostname = ensureWrapForIPv6Uri( hostname ); } - int port = masterServer.getSocketAddress().getPort(); + return URI.create( "ha://" + hostname + ":" + masterSocketAddress.getPort() + "?serverId=" + myId( config ) ); + } - return URI.create( "ha://" + hostname + ":" + port + "?serverId=" + myId( config ) ); + private static String ensureWrapForIPv6Uri( String hostname ) + { + if ( hostname.contains( ":" ) && !hostname.contains( "[" ) ) + { + hostname = "[" + hostname + "]"; + } + return hostname; + } + + private static boolean isWildcard( String hostname ) + { + return hostname.contains( "0.0.0.0" ) || hostname.contains( "[::]" ) || hostname.contains( "[0:0:0:0:0:0:0:0]" ); } private static InstanceId myId( Config config ) diff --git a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToSlave.java b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToSlave.java index 25c3068750c82..684b0d4d51dfd 100644 --- a/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToSlave.java +++ b/enterprise/ha/src/main/java/org/neo4j/kernel/ha/cluster/SwitchToSlave.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; +import java.net.InetSocketAddress; import java.net.URI; import java.time.Clock; import java.util.function.Function; @@ -334,11 +335,28 @@ private boolean catchUpWithMaster( UpdatePuller updatePuller ) throws IllegalArg private URI createHaURI( URI me, Server server ) { - String hostString = ServerUtil.getHostString( server.getSocketAddress() ); - int port = server.getSocketAddress().getPort(); + InetSocketAddress serverSocketAddress = server.getSocketAddress(); + String hostString = ServerUtil.getHostString( serverSocketAddress ); + + String host = isWildcard( hostString ) ? me.getHost() : hostString; + host = ensureWrapForIpv6Uri( host ); + InstanceId serverId = config.get( ClusterSettings.server_id ); - String host = hostString.contains( HighAvailabilityModeSwitcher.INADDR_ANY ) ? me.getHost() : hostString; - return URI.create( "ha://" + host + ":" + port + "?serverId=" + serverId ); + return URI.create( "ha://" + host + ":" + serverSocketAddress.getPort() + "?serverId=" + serverId ); + } + + private String ensureWrapForIpv6Uri( String host ) + { + if ( host.contains( ":" ) && !host.contains( "[" ) ) + { + host = "[" + host + "]"; + } + return host; + } + + private static boolean isWildcard( String hostString ) + { + return hostString.contains( "0.0.0.0" ) || hostString.contains( "::" ) || hostString.contains( "0:0:0:0:0:0:0:0" ); } MasterClient newMasterClient( URI masterUri, URI me, StoreId storeId, LifeSupport life ) diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java index 34fe0b5e502a8..93b6bc51a90a9 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/HaIPv6ConfigurationTest.java @@ -29,11 +29,13 @@ import org.neo4j.cluster.ClusterSettings; import org.neo4j.graphdb.GraphDatabaseService; +import org.neo4j.graphdb.Transaction; import org.neo4j.graphdb.factory.HighlyAvailableGraphDatabaseFactory; import org.neo4j.test.rule.TestDirectory; -import static org.junit.Assume.assumeTrue; - +/** + * Test various IPv6 configuration options on a single HA instance. + */ public class HaIPv6ConfigurationTest { @Rule @@ -46,7 +48,7 @@ public void testClusterWithLocalhostAddresses() throws Throwable .newEmbeddedDatabaseBuilder( dir.makeGraphDbDir() ) .setConfig( ClusterSettings.cluster_server, ipv6HostPortSetting( "::1", 5000 ) ) .setConfig( ClusterSettings.initial_hosts, ipv6HostPortSetting( "::1", 5000 ) ) - .setConfig( HaSettings.ha_server, ipv6HostPortSetting( "::", 6000 ) ) + .setConfig( HaSettings.ha_server, ipv6HostPortSetting( "::1", 6000 ) ) .setConfig( ClusterSettings.server_id, "1" ) .newGraphDatabase(); @@ -62,8 +64,7 @@ public void testClusterWithLocalhostAddresses() throws Throwable @Test public void testClusterWithLinkLocalAddress() throws Throwable { - boolean foundAnIpv6LinkLocalAddress = false; - InetAddress inetAddress = null; + InetAddress inetAddress; Enumeration nics = NetworkInterface.getNetworkInterfaces(); while ( nics.hasMoreElements() ) @@ -73,16 +74,16 @@ public void testClusterWithLinkLocalAddress() throws Throwable while ( inetAddresses.hasMoreElements() ) { inetAddress = inetAddresses.nextElement(); - if ( inetAddress instanceof Inet6Address && inetAddress.isLinkLocalAddress() ) + if ( inetAddress instanceof Inet6Address && inetAddress.isLinkLocalAddress() && inetAddress.isReachable( 1000 ) ) { - foundAnIpv6LinkLocalAddress = true; - break; + testWithAddress( inetAddress ); } } } + } - assumeTrue( foundAnIpv6LinkLocalAddress ); - + private void testWithAddress( InetAddress inetAddress ) throws Exception + { GraphDatabaseService db = new HighlyAvailableGraphDatabaseFactory() .newEmbeddedDatabaseBuilder( dir.makeGraphDbDir() ) .setConfig( ClusterSettings.cluster_server, ipv6HostPortSetting( inetAddress.getHostAddress(), 5000 ) ) @@ -91,6 +92,12 @@ public void testClusterWithLinkLocalAddress() throws Throwable .setConfig( ClusterSettings.server_id, "1" ) .newGraphDatabase(); + try ( Transaction tx = db.beginTx() ) + { + db.createNode(); + tx.success(); + } + db.shutdown(); } @@ -105,6 +112,12 @@ public void testClusterWithWildcardAddresses() throws Throwable .setConfig( ClusterSettings.server_id, "1" ) .newGraphDatabase(); + try ( Transaction tx = db.beginTx() ) + { + db.createNode(); + tx.success(); + } + db.shutdown(); } diff --git a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/cluster/SwitchToMasterTest.java b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/cluster/SwitchToMasterTest.java index 98bca086c1382..3b2a6c259b652 100644 --- a/enterprise/ha/src/test/java/org/neo4j/kernel/ha/cluster/SwitchToMasterTest.java +++ b/enterprise/ha/src/test/java/org/neo4j/kernel/ha/cluster/SwitchToMasterTest.java @@ -55,6 +55,25 @@ public void switchToMasterShouldUseConfigSettingIfSuitable() throws Exception assertEquals( "Wrong address", "ha://192.168.1.99:6001?serverId=1", result.toString() ); } + @Test + public void switchToMasterShouldUseIPv6ConfigSettingIfSuitable() throws Exception + { + // given + Config config = new Config( + stringMap( ClusterSettings.server_id.name(), "1", HaSettings.ha_server.name(), "[fe80::1]:6001" ) ); + URI me = new URI( "ha://[::1]" ); + + MasterServer masterServer = mock( MasterServer.class ); + + // when + when( masterServer.getSocketAddress() ).thenReturn( new InetSocketAddress( "[fe80::1]", 6001 ) ); + + URI result = SwitchToMaster.getMasterUri( me, masterServer, config ); + + // then + assertEquals( "Wrong address", "ha://[fe80::1]:6001?serverId=1", result.toString() ); + } + @Test public void switchToMasterShouldIgnoreWildcardInConfig() throws Exception { @@ -84,6 +103,35 @@ public void switchToMasterShouldIgnoreWildcardInConfig() throws Exception assertEquals( "Wrong address", "ha://127.0.0.1:6001?serverId=1", result.toString() ); } + @Test + public void switchToMasterShouldIgnoreIPv6WildcardInConfig() throws Exception + { + // SwitchToMaster is used to advertise to the rest of the cluster and advertising 0.0.0.0 makes no sense + + // given + Config config = new Config( + stringMap( ClusterSettings.server_id.name(), "1", HaSettings.ha_server.name(), "[::]:6001" ) ); + URI me = new URI( "ha://[::1]" ); + + MasterServer masterServer = mock( MasterServer.class ); + + // when + when( masterServer.getSocketAddress() ).thenReturn( new InetSocketAddress( "[fe80::1]", 6001 ) ); + + URI result = SwitchToMaster.getMasterUri( me, masterServer, config ); + + // then + assertEquals( "Wrong address", "ha://[fe80:0:0:0:0:0:0:1]:6001?serverId=1", result.toString() ); + + // when masterServer is 0.0.0.0 + when( masterServer.getSocketAddress() ).thenReturn( new InetSocketAddress( 6001 ) ); + + result = SwitchToMaster.getMasterUri( me, masterServer, config ); + + // then + assertEquals( "Wrong address", "ha://[::1]:6001?serverId=1", result.toString() ); + } + @Test public void switchToMasterShouldHandleNoIpInConfig() throws Exception {