17
17
*/
18
18
package com .datastax .oss .driver .internal .core .addresstranslation ;
19
19
20
+ import static com .datastax .oss .driver .api .core .config .DefaultDriverOption .RESOLVE_CONTACT_POINTS ;
21
+
20
22
import com .datastax .oss .driver .api .core .addresstranslation .AddressTranslator ;
21
23
import com .datastax .oss .driver .api .core .config .DriverOption ;
22
24
import com .datastax .oss .driver .api .core .context .DriverContext ;
23
- import com .google . common . base . Splitter ;
25
+ import com .datastax . oss . driver . internal . core . util . AddressUtils ;
24
26
import edu .umd .cs .findbugs .annotations .NonNull ;
27
+ import edu .umd .cs .findbugs .annotations .Nullable ;
25
28
import inet .ipaddr .IPAddress ;
26
29
import inet .ipaddr .IPAddressString ;
27
30
import java .net .InetSocketAddress ;
28
31
import java .util .List ;
29
- import java .util .Objects ;
30
32
import java .util .Optional ;
31
33
import java .util .stream .Collectors ;
32
34
import org .slf4j .Logger ;
43
45
* different Cassandra datacenters deployed to different Kubernetes clusters.
44
46
*/
45
47
public class SubnetAddressTranslator implements AddressTranslator {
46
-
47
48
private static final Logger LOG = LoggerFactory .getLogger (SubnetAddressTranslator .class );
48
49
49
50
/**
@@ -53,23 +54,22 @@ public class SubnetAddressTranslator implements AddressTranslator {
53
54
* <pre>
54
55
* advanced.address-translator.subnet-addresses {
55
56
* "100.64.0.0/15" = "cassandra.datacenter1.com:9042"
56
- * "100.66.0.0/15" = "cassandra.datacenter2.com"
57
+ * "100.66.0.0/15" = "cassandra.datacenter2.com:9042 "
57
58
* # IPv6 example:
58
59
* # "::ffff:6440:0/111" = "cassandra.datacenter1.com:9042"
59
- * # "::ffff:6442:0/111" = "cassandra.datacenter2.com"
60
+ * # "::ffff:6442:0/111" = "cassandra.datacenter2.com:9042 "
60
61
* }
61
62
* </pre>
62
63
*
63
- * If configured without port, the default 9042 will be used. Also supports IPv6 subnets. Note:
64
- * subnets must be represented as prefix blocks, see {@link inet.ipaddr.Address#isPrefixBlock()}.
64
+ * Note: subnets must be represented as prefix blocks, see {@link
65
+ * inet.ipaddr.Address#isPrefixBlock()}.
65
66
*/
66
67
public static final String ADDRESS_TRANSLATOR_SUBNET_ADDRESSES =
67
68
"advanced.address-translator.subnet-addresses" ;
68
69
69
70
/**
70
71
* A default address to fallback to if Cassandra node IP isn't contained in any of the configured
71
- * subnets. If configured without port, the default 9042 will be used. Also supports IPv6
72
- * addresses.
72
+ * subnets.
73
73
*/
74
74
public static final String ADDRESS_TRANSLATOR_DEFAULT_ADDRESS =
75
75
"advanced.address-translator.default-address" ;
@@ -92,11 +92,9 @@ public String getPath() {
92
92
}
93
93
};
94
94
95
- private static final String DELIMITER = ":" ;
96
- private static final int DEFAULT_PORT = 9042 ;
97
-
98
95
private final List <SubnetAddress > subnetAddresses ;
99
- private final Optional <InetSocketAddress > defaultAddress ;
96
+ private final Optional <String > defaultAddress ;
97
+ private final boolean resolveAddresses ;
100
98
private final String logPrefix ;
101
99
102
100
public SubnetAddressTranslator (@ NonNull DriverContext context ) {
@@ -109,19 +107,22 @@ public SubnetAddressTranslator(@NonNull DriverContext context) {
109
107
// Quoted and/or containing forward slashes map keys in reference.conf are read to
110
108
// strings with additional quotes, eg. 100.64.0.0/15 -> '100.64.0."0/15"' or
111
109
// "100.64.0.0/15" -> '"100.64.0.0/15"'
112
- String subnet = e .getKey ().replaceAll ("\" " , "" );
110
+ String subnetCIDR = e .getKey ().replaceAll ("\" " , "" );
113
111
String address = e .getValue ();
114
- return new SubnetAddress (subnet , address );
112
+ return new SubnetAddress (subnetCIDR , address );
115
113
})
116
114
.collect (Collectors .toList ());
117
115
this .defaultAddress =
118
116
Optional .ofNullable (
119
- context
120
- .getConfig ()
121
- .getDefaultProfile ()
122
- .getString (ADDRESS_TRANSLATOR_DEFAULT_ADDRESS_OPTION , null ))
123
- .map (SubnetAddressTranslator ::parseAddress );
124
- SubnetAddressTranslator .validateSubnetsAreNotOverlapping (this .subnetAddresses );
117
+ context
118
+ .getConfig ()
119
+ .getDefaultProfile ()
120
+ .getString (ADDRESS_TRANSLATOR_DEFAULT_ADDRESS_OPTION , null ));
121
+ this .resolveAddresses =
122
+ context .getConfig ().getDefaultProfile ().getBoolean (RESOLVE_CONTACT_POINTS , true );
123
+
124
+ validateSubnetsAreNotOverlapping (this .subnetAddresses );
125
+ this .defaultAddress .ifPresent (SubnetAddressTranslator ::validateAddress );
125
126
}
126
127
127
128
@ NonNull
@@ -130,11 +131,11 @@ public InetSocketAddress translate(@NonNull InetSocketAddress address) {
130
131
InetSocketAddress translatedAddress = null ;
131
132
for (SubnetAddress subnetAddress : subnetAddresses ) {
132
133
if (subnetAddress .contains (address )) {
133
- translatedAddress = subnetAddress .address ;
134
+ translatedAddress = parseAddress ( subnetAddress .address , resolveAddresses ) ;
134
135
}
135
136
}
136
137
if (translatedAddress == null && defaultAddress .isPresent ()) {
137
- translatedAddress = defaultAddress .get ();
138
+ translatedAddress = parseAddress ( defaultAddress .get (), resolveAddresses );
138
139
}
139
140
if (translatedAddress == null ) {
140
141
translatedAddress = address ;
@@ -146,15 +147,17 @@ public InetSocketAddress translate(@NonNull InetSocketAddress address) {
146
147
@ Override
147
148
public void close () {}
148
149
149
- private static InetSocketAddress parseAddress (String address ) {
150
- List <String > addressTuple = Splitter .onPattern (DELIMITER ).splitToList (address );
151
- if (addressTuple .size () == 2 ) {
152
- return new InetSocketAddress (addressTuple .get (0 ), Integer .parseInt (addressTuple .get (1 )));
153
- }
154
- if (addressTuple .size () == 1 ) {
155
- return new InetSocketAddress (addressTuple .get (0 ), DEFAULT_PORT );
150
+ @ Nullable
151
+ private static InetSocketAddress parseAddress (String address , boolean resolve ) {
152
+ return AddressUtils .extract (address , resolve ).iterator ().next ();
153
+ }
154
+
155
+ private static void validateAddress (String address ) {
156
+ try {
157
+ parseAddress (address , false );
158
+ } catch (RuntimeException e ) {
159
+ throw new IllegalArgumentException ("Invalid address: " + address , e );
156
160
}
157
- throw new IllegalArgumentException ("Invalid default address: " + address );
158
161
}
159
162
160
163
private static void validateSubnetsAreNotOverlapping (List <SubnetAddress > subnetAddresses ) {
@@ -174,21 +177,28 @@ private static void validateSubnetsAreNotOverlapping(List<SubnetAddress> subnetA
174
177
175
178
private static class SubnetAddress {
176
179
private final IPAddress subnet ;
177
- private final InetSocketAddress address ;
180
+ private final String address ;
181
+
182
+ private SubnetAddress (String subnetCIDR , String address ) {
183
+ this .subnet = parseSubnet (subnetCIDR );
184
+ this .address = address ;
178
185
179
- private SubnetAddress (String subnet , String address ) {
180
- IPAddress subnetIpAddress = new IPAddressString (subnet ).getAddress ();
181
- if (subnetIpAddress == null ) {
182
- throw new IllegalArgumentException ("Invalid subnet: " + subnet );
186
+ validateAddress (this .address );
187
+ }
188
+
189
+ private static IPAddress parseSubnet (String subnetCIDR ) {
190
+ IPAddress subnet = new IPAddressString (subnetCIDR ).getAddress ();
191
+ if (subnet == null ) {
192
+ throw new IllegalArgumentException ("Invalid subnet: " + subnetCIDR );
183
193
}
184
- if (!subnetIpAddress .isPrefixBlock ()) {
194
+ if (!subnet .isPrefixBlock ()) {
195
+
185
196
throw new IllegalArgumentException (
186
197
String .format (
187
198
"Subnet %s must be represented as a network prefix block %s" ,
188
- subnetIpAddress , subnetIpAddress .toPrefixBlock ()));
199
+ subnet , subnet .toPrefixBlock ()));
189
200
}
190
- this .subnet = subnetIpAddress ;
191
- this .address = parseAddress (address );
201
+ return subnet ;
192
202
}
193
203
194
204
private boolean isOverlapping (SubnetAddress other ) {
@@ -209,18 +219,5 @@ private boolean contains(InetSocketAddress address) {
209
219
}
210
220
return subnet .contains (ipAddress );
211
221
}
212
-
213
- @ Override
214
- public boolean equals (Object other ) {
215
- if (this == other ) return true ;
216
- if (!(other instanceof SubnetAddress )) return false ;
217
- SubnetAddress that = (SubnetAddress ) other ;
218
- return Objects .equals (subnet , that .subnet ) && Objects .equals (address , that .address );
219
- }
220
-
221
- @ Override
222
- public int hashCode () {
223
- return Objects .hash (subnet , address );
224
- }
225
222
}
226
223
}
0 commit comments