Skip to content
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

Merged
merged 10 commits into from
Nov 2, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cassandra/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,11 @@ dependencies {
testImplementation(libs.testcontainers.cassandra)
testImplementation(mn.micronaut.management)
testImplementation(mnMicrometer.micronaut.micrometer.core)
testImplementation(libs.system.stubs)
testRuntimeOnly(mn.snakeyaml)
}

tasks.withType(Test) {
// this is needed by libs.system.stubs
jvmArgs = ["--add-opens", "java.base/java.util=ALL-UNNAMED"]
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
import com.typesafe.config.ConfigFactory;
import io.micronaut.context.annotation.EachBean;
import io.micronaut.context.annotation.Factory;
import io.micronaut.core.naming.conventions.StringConvention;
import io.micronaut.core.value.PropertyResolver;
import jakarta.annotation.PreDestroy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
Expand All @@ -37,6 +37,7 @@
*
* @author Nirav Assar
* @author Michael Pollind
* @author Dean Wette
* @since 1.0
*/
@Factory
Expand Down Expand Up @@ -67,10 +68,11 @@ public CqlSessionBuilder session(CassandraConfiguration configuration) {
return CqlSession.builder().withConfigLoader(new DefaultDriverConfigLoader(() -> {
ConfigFactory.invalidateCaches();
String prefix = configuration.getName();
Map<String, Object> properties = this.resolver.getProperties(CassandraConfiguration.PREFIX + "." + prefix, StringConvention.RAW);
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));
}));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import com.datastax.oss.driver.api.core.CqlSession
import io.micrometer.core.instrument.Meter
import io.micrometer.core.instrument.MeterRegistry
import io.micronaut.context.ApplicationContext
import io.micronaut.context.DefaultApplicationContext
import io.micronaut.context.env.MapPropertySource
import io.micronaut.core.value.PropertyResolver
import io.micronaut.inject.qualifiers.Qualifiers
import org.testcontainers.containers.CassandraContainer
import org.testcontainers.utility.DockerImageName
import spock.lang.Issue
import spock.lang.Specification
import uk.org.webcompere.systemstubs.environment.EnvironmentVariables

class CassandraMetricsSpec extends Specification {

Expand Down Expand Up @@ -55,4 +56,41 @@ class CassandraMetricsSpec extends Specification {
cassandra.stop()
applicationContext.close()
}

@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']
}
}
8 changes: 8 additions & 0 deletions cassandra/src/test/resources/application-envprops.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
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
17 changes: 17 additions & 0 deletions cassandra/src/test/resources/application-envyaml.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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]
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ managed-datastax-cassandra-driver = "4.17.0"
groovy = "4.0.14"
spock = "2.3-groovy-4.0"
testcontainers = "1.19.1"
system-stubs = "1.2.0"

[libraries]
# Core
Expand All @@ -22,6 +23,7 @@ managed-datastax-cassandra-driver-core = { module = "com.datastax.oss:java-drive
managed-datastax-cassandra-driver-mapper-processor = { module = "com.datastax.oss:java-driver-mapper-processor", version.ref = "managed-datastax-cassandra-driver" }
managed-datastax-cassandra-driver-metrics-micrometer = { module = "com.datastax.oss:java-driver-metrics-micrometer", version.ref = "managed-datastax-cassandra-driver" }

system-stubs = { module = "uk.org.webcompere:system-stubs-core", version.ref = "system-stubs" }
testcontainers-cassandra = { module = "org.testcontainers:cassandra", version.ref = "testcontainers" }
testcontainers-spock = { module = "org.testcontainers:spock", version.ref = "testcontainers" }

Expand Down
9 changes: 7 additions & 2 deletions src/main/docs/guide/additional.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ datastax-java-driver {
}
}
----
.micronaut bean configuration - application.yml
[source,yaml]
.micronaut bean configuration - application configuration
[configuration]
----
cassandra:
default:
Expand All @@ -26,3 +26,8 @@ cassandra:
load-balancing-policy:
local-datacenter: datacenter1
----

Micronaut Framework is very flexible with how application configuration is specified. Configuration properties can be overridden with environment variables. However, the Cassandra Datastax driver is not tolerant and fails fast when it encounters what it considers malformed/illegal configuration properties. Micronaut Cassandra handles this automatically for most cases, but if you want to use environment variables to override Cassandra application configuration the following rules apply:

1. Must be uppercase camelcase, e.g. MY_UPPER_CAMEL_CASE_ENV
2. Where https://docs.datastax.com/en/developer/java-driver/latest/manual/core/configuration/reference/[DataStax driver configuration] specifies hyphenated configuration keys, the hyphens must be preserved, e.g. `cassandra.default.basic.session-name` is overridden with `CASSANDRA_DEFAULT_BASIC_SESSION-NAME`.
wetted marked this conversation as resolved.
Show resolved Hide resolved
Loading