-
Notifications
You must be signed in to change notification settings - Fork 8
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for using env vars to override cassandra datastax driver configuration properties #389
Conversation
…configuration properties. fixes #240
Still needs new documentation, and I need to consider if there are corner cases to handle. |
…nfiguration for Datastax driver.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not 100% but I think we can change direction here...
Declaring properties in tests (with ApplicationContext.run) do not seem to be overridden by env variables.
I suspect this is why we need to pull the Environment into the session factory.
But this is not how applications are configured in the real world 🤔
If we create a file in test/resources/application-envprops.properties
containing:
configuration=props
micronaut.metrics.enabled=true
cassandra.default.basic.contact-points[0]=localhost:${cassandra.port}
cassandra.default.basic.session-name=defaultSession
cassandra.default.advanced.metrics.factory.class=MicrometerMetricsFactory
cassandra.default.advanced.metrics.session.enabled[0]=connected-nodes
cassandra.default.advanced.metrics.session.enabled[1]=cql-requests
cassandra.default.basic.load-balancing-policy.local-datacenter=datacenter1
and a file test/resources/application-envyaml.yaml
containing:
micronaut:
metrics:
enabled: true
configuration: yaml
cassandra:
default:
basic:
contact-points: ["localhost:${cassandra.port}"]
session-name: defaultSession
load-balancing-policy:
local-datacenter: datacenter1
advanced:
metrics:
factory:
class: MicrometerMetricsFactory
session:
enabled: [connected-nodes, cql-requests]
We can change the test to: (after adding testRuntimeOnly(mn.snakeyaml)
to the build)
@Issue("https://github.com/micronaut-projects/micronaut-cassandra/issues/240")
void "test metrics with overriding #configStyle with env vars"() {
given:
CassandraContainer cassandra = new CassandraContainer(DockerImageName.parse('cassandra:latest'))
cassandra.start()
// override: cassandra.default.basic.session-name=defaultSession
def env = new EnvironmentVariables(
"CASSANDRA_DEFAULT_BASIC_SESSION_NAME", "envSession",
"CASSANDRA_PORT", "${cassandra.firstMappedPort}"
)
env.setup()
ApplicationContext applicationContext = ApplicationContext.run("env$configStyle")
when:
CqlSession defaultCluster = applicationContext.getBean(CqlSession)
PropertyResolver resolver = applicationContext.getBean(PropertyResolver)
MeterRegistry meterRegistry = applicationContext.getBean(MeterRegistry)
then:
resolver.getRequiredProperty("configuration", String) == configStyle
defaultCluster
meterRegistry
and:
meterRegistry.meters.id.name.findAll { it.contains("envSession") } ==~ ['envSession.connected-nodes', 'envSession.cql-requests']
cleanup:
env.teardown()
cassandra.stop()
applicationContext.close()
where:
configStyle << ['props', 'yaml']
}
I think we are a lot closer to testing how the application is run in the wild...
Doing it this way, we can change the session method to something like:
/**
* Creates the {@link CqlSessionBuilder} bean for the given configuration.
*
* @param configuration The cassandra configuration bean
* @return A {@link CqlSession} bean
*/
@EachBean(CassandraConfiguration.class)
public CqlSessionBuilder session(CassandraConfiguration configuration) {
try {
return CqlSession.builder().withConfigLoader(new DefaultDriverConfigLoader(() -> {
ConfigFactory.invalidateCaches();
String prefix = configuration.getName();
Map<String, Object> properties = this.resolver.getProperties(CassandraConfiguration.PREFIX + "." + prefix);
// translate indexed properties for list values from Micronaut array index notation (i.e. foo[0]=bar)
// to Datastax driver decimal notation (i.e. foo.0=bar)
properties = properties.entrySet().stream()
.filter(e -> !(e.getValue() instanceof Collection<?>))
.collect((Collectors.toMap(e -> e.getKey().replaceAll("\\[(\\d+)]", ".$1"), Map.Entry::getValue)));
return ConfigFactory.parseMap(properties).withFallback(ConfigFactory.load().getConfig(DefaultDriverConfigLoader.DEFAULT_ROOT_PATH));
}));
} catch (Exception e) {
LOG.error(String.format("Failed to instantiate CQL session: %s", e.getMessage()), e);
throw e;
}
}
This uses the evaluated properties instead of the RAW ones, and filters out any which have been converted into a collection by the micronaut properties consolodation
I think this works...
Let me know what you think?
cassandra/src/main/java/io/micronaut/cassandra/CassandraSessionFactory.java
Outdated
Show resolved
Hide resolved
cassandra/src/test/groovy/io/micronaut/cassandra/metrics/CassandraMetricsSpec.groovy
Outdated
Show resolved
Hide resolved
cassandra/src/test/groovy/io/micronaut/cassandra/metrics/CassandraMetricsSpec.groovy
Outdated
Show resolved
Hide resolved
Thanks @timyates great suggestions, and I think everything is resolved. |
Kudos, SonarCloud Quality Gate passed! |
fixes #240