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 scylladb module #8002

Merged
merged 17 commits into from
Jan 31, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ body:
- QuestDB
- RabbitMQ
- Redpanda
- ScyllaDB
- Selenium
- Solace
- Solr
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/enhancement.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ body:
- QuestDB
- RabbitMQ
- Redpanda
- ScyllaDB
- Selenium
- Solace
- Solr
Expand Down
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/feature.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ body:
- Pulsar
- RabbitMQ
- Redpanda
- ScyllaDB
- Selenium
- Solace
- Solr
Expand Down
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,11 @@ updates:
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/scylladb"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
- package-ecosystem: "gradle"
directory: "/modules/selenium"
schedule:
Expand Down
4 changes: 4 additions & 0 deletions .github/labeler.yml
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@
- changed-files:
- any-glob-to-any-file:
- modules/redpanda/**/*
"modules/scylladb":
- changed-files:
- any-glob-to-any-file:
- modules/scylladb/**/*
"modules/selenium":
- changed-files:
- any-glob-to-any-file:
Expand Down
58 changes: 58 additions & 0 deletions docs/modules/databases/scylladb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# ScyllaDB

Testcontainers module for [ScyllaDB](https://hub.docker.com/r/scylladb/scylla)

## ScyllaDB's usage examples

You can start a ScyllaDB container instance from any Java application by using:

<!--codeinclude-->
[Create container](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:container
<!--/codeinclude-->

<!--codeinclude-->
[Custom config file](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:customConfiguration
<!--/codeinclude-->

### Building CqlSession

<!--codeinclude-->
[Using CQL port](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:session
<!--/codeinclude-->

<!--codeinclude-->
[Using SSL](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:sslContext
<!--/codeinclude-->

<!--codeinclude-->
[Using Shard Awareness port](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:shardAwarenessSession
<!--/codeinclude-->

### Alternator

<!--codeinclude-->
[Enabling Alternator](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:alternator
<!--/codeinclude-->

<!--codeinclude-->
[DynamoDbClient with Alternator](../../../modules/scylladb/src/test/java/org/testcontainers/scylladb/ScyllaDBContainerTest.java) inside_block:dynamodDbClient
<!--/codeinclude-->

## Adding this module to your project dependencies

Add the following dependency to your `pom.xml`/`build.gradle` file:

=== "Gradle"
```groovy
testImplementation "org.testcontainers:scylladb:{{latest_version}}"
```

=== "Maven"
```xml
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>scylladb</artifactId>
<version>{{latest_version}}</version>
<scope>test</scope>
</dependency>
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ nav:
- modules/databases/postgres.md
- modules/databases/presto.md
- modules/databases/questdb.md
- modules/databases/scylladb.md
- modules/databases/tidb.md
- modules/databases/timeplus.md
- modules/databases/trino.md
Expand Down
9 changes: 9 additions & 0 deletions modules/scylladb/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
description = "Testcontainers :: ScyllaDB"

dependencies {
api project(":testcontainers")

testImplementation 'com.scylladb:java-driver-core:4.15.0.0'
testImplementation 'org.assertj:assertj-core:3.24.2'
testImplementation 'software.amazon.awssdk:dynamodb:2.28.6'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.testcontainers.scylladb;

import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.utility.DockerImageName;
import org.testcontainers.utility.MountableFile;

import java.net.InetSocketAddress;
import java.util.Optional;

/**
* Testcontainers implementation for ScyllaDB.
* <p>
* Supported image: {@code scylladb/scylla}
* <p>
* Exposed ports:
* <ul>
* <li>CQL Port: 9042</li>
* <li>Shard Aware Port: 19042</li>
* <li>Alternator Port: 8000</li>
* </ul>
*/
public class ScyllaDBContainer extends GenericContainer<ScyllaDBContainer> {

private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("scylladb/scylla");

private static final Integer CQL_PORT = 9042;

private static final Integer SHARD_AWARE_PORT = 19042;

private static final Integer ALTERNATOR_PORT = 8000;

private static final String COMMAND = "--developer-mode=1 --overprovisioned=1";

private static final String CONTAINER_CONFIG_LOCATION = "/etc/scylla";

private boolean alternatorEnabled = false;

private String configLocation;

public ScyllaDBContainer(String dockerImageName) {
this(DockerImageName.parse(dockerImageName));
}

public ScyllaDBContainer(DockerImageName dockerImageName) {
super(dockerImageName);
dockerImageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);

withExposedPorts(CQL_PORT, SHARD_AWARE_PORT);

withCommand(COMMAND);
waitingFor(Wait.forLogMessage(".*initialization completed..*", 1));
}

@Override
protected void configure() {
if (this.alternatorEnabled) {
addExposedPort(8000);
String newCommand =
COMMAND + " --alternator-port=" + ALTERNATOR_PORT + " --alternator-write-isolation=always";
withCommand(newCommand);
}

// Map (effectively replace) directory in Docker with the content of resourceLocation if resource location is
// not null.
Optional
.ofNullable(configLocation)
.map(MountableFile::forClasspathResource)
.ifPresent(mountableFile -> withCopyFileToContainer(mountableFile, CONTAINER_CONFIG_LOCATION));
}

public ScyllaDBContainer withConfigurationOverride(String configLocation) {
this.configLocation = configLocation;
return this;
}

public ScyllaDBContainer withSsl(MountableFile certificate, MountableFile keyfile, MountableFile truststore) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

truststore is optional. See https://opensource.docs.scylladb.com/stable/operating-scylla/security/client-node-encryption.html#validate-the-clients. So, we should provide another method
withSsl(MountableFile certificate, MountableFile keyfile)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch! thanks, fixed this one

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have reverted this because truststore must be at the system truststore and in order to do that we need to copy the file too. Sorry about that.

withCopyFileToContainer(certificate, "/etc/scylla/scylla.cer.pem");
withCopyFileToContainer(keyfile, "/etc/scylla/scylla.key.pem");
withCopyFileToContainer(truststore, "/etc/scylla/scylla.truststore");
withEnv("SSL_CERTFILE", "/etc/scylla/scylla.cer.pem");
return this;
}

public ScyllaDBContainer withAlternator() {
this.alternatorEnabled = true;
return this;
}

/**
* Retrieve an {@link InetSocketAddress} for connecting to the ScyllaDB container via the driver.
*
* @return A InetSocketAddress representation of this ScyllaDB container's host and port.
*/
public InetSocketAddress getContactPoint() {
return new InetSocketAddress(getHost(), getMappedPort(CQL_PORT));
}

public InetSocketAddress getShardAwareContactPoint() {
return new InetSocketAddress(getHost(), getMappedPort(SHARD_AWARE_PORT));
}

public String getAlternatorEndpoint() {
if (!this.alternatorEnabled) {
throw new IllegalStateException("Alternator is not enabled");
}
return "http://" + getHost() + ":" + getMappedPort(ALTERNATOR_PORT);
}
}
Loading
Loading