Restore Cassandra port option
This commit restores the port option that was removed in an earlier milestone. Contact points that do not define a port already are automatically transformed to include the one configured, with a default matching Cassandra's default port. This makes upgrades easier in the case a cluster uses consistent ports everywhere. Closes gh-19672
This commit is contained in:
@@ -21,6 +21,8 @@ import java.time.Duration;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
@@ -114,7 +116,7 @@ public class CassandraAutoConfiguration {
|
||||
mapQueryOptions(properties, options);
|
||||
mapSocketOptions(properties, options);
|
||||
mapPoolingOptions(properties, options);
|
||||
map.from(properties::getContactPoints)
|
||||
map.from(mapContactPoints(properties))
|
||||
.to((contactPoints) -> options.add(DefaultDriverOption.CONTACT_POINTS, contactPoints));
|
||||
map.from(properties.getLocalDatacenter()).to(
|
||||
(localDatacenter) -> options.add(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER, localDatacenter));
|
||||
@@ -152,6 +154,29 @@ public class CassandraAutoConfiguration {
|
||||
.to((maxQueueSize) -> options.add(DefaultDriverOption.REQUEST_THROTTLER_MAX_QUEUE_SIZE, maxQueueSize));
|
||||
}
|
||||
|
||||
private List<String> mapContactPoints(CassandraProperties properties) {
|
||||
return properties.getContactPoints().stream()
|
||||
.map((candidate) -> formatContactPoint(candidate, properties.getPort())).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private String formatContactPoint(String candidate, int port) {
|
||||
int i = candidate.lastIndexOf(':');
|
||||
if (i == -1 || !isPort(() -> candidate.substring(i + 1))) {
|
||||
return String.format("%s:%s", candidate, port);
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
|
||||
private boolean isPort(Supplier<String> value) {
|
||||
try {
|
||||
int i = Integer.parseInt(value.get());
|
||||
return i > 0 && i < 65535;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CassandraDriverOptions {
|
||||
|
||||
private final Map<String, String> options = new LinkedHashMap<>();
|
||||
|
||||
@@ -51,10 +51,16 @@ public class CassandraProperties {
|
||||
private String sessionName;
|
||||
|
||||
/**
|
||||
* Cluster node addresses in the form 'host:port'.
|
||||
* Cluster node addresses in the form 'host:port', or a simple 'host' to use the
|
||||
* configured port.
|
||||
*/
|
||||
private final List<String> contactPoints = new ArrayList<>(Collections.singleton("127.0.0.1:9042"));
|
||||
|
||||
/**
|
||||
* Port to use if a contact point does not specify one.
|
||||
*/
|
||||
private int port = 9042;
|
||||
|
||||
/**
|
||||
* Datacenter that is considered "local". Contact points should be from this
|
||||
* datacenter.
|
||||
@@ -147,6 +153,14 @@ public class CassandraProperties {
|
||||
return this.contactPoints;
|
||||
}
|
||||
|
||||
public int getPort() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public void setPort(int port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getLocalDatacenter() {
|
||||
return this.localDatacenter;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,6 @@ import com.datastax.oss.driver.api.core.CqlSessionBuilder;
|
||||
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
|
||||
import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
|
||||
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
|
||||
import com.typesafe.config.Config;
|
||||
import com.typesafe.config.ConfigParseOptions;
|
||||
import com.typesafe.config.impl.Parseable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
@@ -78,6 +75,38 @@ class CassandraAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigLoaderWithContactPointAndNoPort() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.cassandra.contact-points=cluster.example.com,another.example.com:9041",
|
||||
"spring.data.cassandra.local-datacenter=cassandra-eu1")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(DriverConfigLoader.class);
|
||||
DriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class).getInitialConfig()
|
||||
.getDefaultProfile();
|
||||
assertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))
|
||||
.containsOnly("cluster.example.com:9042", "another.example.com:9041");
|
||||
assertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))
|
||||
.isEqualTo("cassandra-eu1");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigLoaderWithContactPointAndNoPortAndCustomPort() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.data.cassandra.contact-points=cluster.example.com:9041,another.example.com",
|
||||
"spring.data.cassandra.port=9043", "spring.data.cassandra.local-datacenter=cassandra-eu1")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(DriverConfigLoader.class);
|
||||
DriverExecutionProfile configuration = context.getBean(DriverConfigLoader.class).getInitialConfig()
|
||||
.getDefaultProfile();
|
||||
assertThat(configuration.getStringList(DefaultDriverOption.CONTACT_POINTS))
|
||||
.containsOnly("cluster.example.com:9041", "another.example.com:9043");
|
||||
assertThat(configuration.getString(DefaultDriverOption.LOAD_BALANCING_LOCAL_DATACENTER))
|
||||
.isEqualTo("cassandra-eu1");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigLoaderWithCustomSessionName() {
|
||||
this.contextRunner.withPropertyValues("spring.data.cassandra.session-name=testcluster").run((context) -> {
|
||||
@@ -97,16 +126,6 @@ class CassandraAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigLoaderApplyConsistentDefaults() {
|
||||
this.contextRunner.run((context) -> {
|
||||
Config defaultConfig = defaultConfig();
|
||||
DriverExecutionProfile config = context.getBean(DriverConfigLoader.class).getInitialConfig()
|
||||
.getDefaultProfile();
|
||||
// TODO
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void driverConfigLoaderCustomizePoolOptions() {
|
||||
this.contextRunner.withPropertyValues("spring.data.cassandra.pool.idle-timeout=42",
|
||||
@@ -120,10 +139,6 @@ class CassandraAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
private static Config defaultConfig() {
|
||||
return Parseable.newResources("reference.conf", ConfigParseOptions.defaults()).parse().toConfig();
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class SimpleDriverConfigLoaderBuilderCustomizerConfig {
|
||||
|
||||
|
||||
@@ -4518,6 +4518,18 @@ Generally, you provide `keyspace-name` and `contact-points` as well the local da
|
||||
spring.data.cassandra.local-datacenter=datacenter1
|
||||
----
|
||||
|
||||
If the port is the same for all your contact points you can use a shortcut and only specify the host names, as shown in the following example:
|
||||
|
||||
[source,properties,indent=0,configprops]
|
||||
----
|
||||
spring.data.cassandra.keyspace-name=mykeyspace
|
||||
spring.data.cassandra.contact-points=cassandrahost1,cassandrahost2
|
||||
spring.data.cassandra.local-datacenter=datacenter1
|
||||
----
|
||||
|
||||
TIP: Those two examples are identical as the port default to `9042`.
|
||||
If you need to configure the port, use `spring.data.cassandra.port`.
|
||||
|
||||
You can also register an arbitrary number of beans that implement `DriverConfigLoaderBuilderCustomizer` for more advanced driver customizations.
|
||||
The `CqlSession` can be customized with a bean of type `CqlSessionBuilderCustomizer`.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user