Skip to content

Commit fdc41bd

Browse files
authored
Added support for creating tarantool container from sdk (#43)
* Added support for creating tarantool container from sdk * Added null safety and test for dockerfile * Fix tests * Added URI to github actions
1 parent 027ab2d commit fdc41bd

File tree

13 files changed

+286
-7
lines changed

13 files changed

+286
-7
lines changed

.github/workflows/ubuntu-master.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,5 @@ jobs:
3030
env:
3131
TARANTOOL_SERVER_USER: root
3232
TARANTOOL_SERVER_GROUP: root
33+
URI: ${{ secrets.URI }}
3334
run: mvn -B verify --file pom.xml

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@
7676
<dependency>
7777
<groupId>org.junit.jupiter</groupId>
7878
<artifactId>junit-jupiter</artifactId>
79-
<version>5.6.2</version>
79+
<version>5.7.0</version>
8080
<scope>test</scope>
8181
</dependency>
8282
<dependency>
@@ -91,6 +91,11 @@
9191
<version>1.2.3</version>
9292
<scope>test</scope>
9393
</dependency>
94+
<dependency>
95+
<groupId>com.github.docker-java</groupId>
96+
<artifactId>docker-java</artifactId>
97+
<version>3.2.13</version>
98+
</dependency>
9499
</dependencies>
95100

96101
<build>

src/main/java/org/testcontainers/containers/TarantoolContainer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ public TarantoolContainer(String dockerImageName) {
5656
clientHelper = new TarantoolContainerClientHelper(this);
5757
}
5858

59+
public TarantoolContainer(TarantoolImageParams tarantoolImageParams) {
60+
super(TarantoolContainerImageHelper.getImage(tarantoolImageParams));
61+
clientHelper = new TarantoolContainerClientHelper(this);
62+
}
63+
5964
public TarantoolContainer(Future<String> image) {
6065
super(image);
6166
clientHelper = new TarantoolContainerClientHelper(this);
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package org.testcontainers.containers;
2+
3+
import com.github.dockerjava.api.DockerClient;
4+
import com.github.dockerjava.api.command.BuildImageResultCallback;
5+
import com.github.dockerjava.api.model.Image;
6+
import com.github.dockerjava.core.DockerClientBuilder;
7+
import org.apache.commons.lang3.StringUtils;
8+
9+
import java.util.Arrays;
10+
import java.util.Collection;
11+
import java.util.Collections;
12+
import java.util.HashSet;
13+
import java.util.List;
14+
15+
/**
16+
* Class for working with docker directly
17+
*
18+
* @author Oleg Kuznetsov
19+
*/
20+
class TarantoolContainerImageHelper {
21+
22+
private static final DockerClient dockerClient = DockerClientBuilder.getInstance().build();
23+
24+
private TarantoolContainerImageHelper() {
25+
}
26+
27+
/**
28+
* Checks image for existing by name and build if it not exist
29+
*
30+
* @param imageParams parameters for building tarantool image
31+
* @return image name
32+
*/
33+
static String getImage(TarantoolImageParams imageParams) {
34+
final String sdkVersion = imageParams.getSdkVersion();
35+
36+
if (StringUtils.isEmpty(sdkVersion)) {
37+
throw new IllegalArgumentException("SDK version is null or empty!");
38+
}
39+
40+
if (!hasImage(sdkVersion)) {
41+
buildImage(imageParams);
42+
}
43+
44+
return sdkVersion;
45+
}
46+
47+
/**
48+
* Builds image from parameters
49+
*
50+
* @param imageParams parameters for building tarantool image
51+
*/
52+
private static void buildImage(TarantoolImageParams imageParams) {
53+
final String sdkVersion = imageParams.getSdkVersion();
54+
final String uri = System.getenv("URI");
55+
56+
if (StringUtils.isEmpty(uri)) {
57+
throw new IllegalStateException("URI environment variable must be specified!");
58+
}
59+
60+
dockerClient.buildImageCmd(imageParams.getDockerfile())
61+
.withTags(new HashSet<>(Collections.singletonList(sdkVersion)))
62+
.withBuildArg("SDK_VERSION", sdkVersion)
63+
.withBuildArg("URI", uri)
64+
.exec(new BuildImageResultCallback())
65+
.awaitImageId();
66+
}
67+
68+
/**
69+
* Checks image for existing by name
70+
*
71+
* @param imageName image name for searching
72+
* @return true if image exist and false if not
73+
*/
74+
private static boolean hasImage(String imageName) {
75+
final List<Image> images = dockerClient.listImagesCmd().exec();
76+
return images.stream()
77+
.map(Image::getRepoTags)
78+
.map(Arrays::asList)
79+
.flatMap(Collection::stream)
80+
.anyMatch(tag -> tag.equals(imageName + ":latest"));
81+
}
82+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package org.testcontainers.containers;
2+
3+
import java.io.File;
4+
import java.net.URISyntaxException;
5+
6+
/**
7+
* Tarantool image parameters holder
8+
*
9+
* @author Oleg Kuznetsov
10+
*/
11+
public class TarantoolImageParams {
12+
13+
private final String sdkVersion;
14+
private final File dockerfile;
15+
16+
/**
17+
* Basic constructor for tarantool image parameters
18+
*
19+
* @param sdkVersion version of tarantool sdk which will be downloaded from specified in env variables URI,
20+
* for example: tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470
21+
*/
22+
public TarantoolImageParams(String sdkVersion) {
23+
this.sdkVersion = sdkVersion;
24+
try {
25+
this.dockerfile = new File(TarantoolImageParams.class.getClassLoader()
26+
.getResource("sdk/Dockerfile").toURI());
27+
} catch (URISyntaxException e) {
28+
throw new IllegalStateException("Can't access to Dockerfile for testcontainers");
29+
}
30+
}
31+
32+
/**
33+
* Custom constructor for tarantool image parameters
34+
*
35+
* @param sdkVersion version of tarantool sdk which will be downloaded from specified in env variables URI,
36+
* for example: tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470
37+
* @param dockerfile dockerfile for building custom tarantool image
38+
*/
39+
public TarantoolImageParams(String sdkVersion, File dockerfile) {
40+
this.sdkVersion = sdkVersion;
41+
this.dockerfile = dockerfile;
42+
}
43+
44+
/**
45+
* Getter for sdk version
46+
*
47+
* @return sdk version
48+
*/
49+
public String getSdkVersion() {
50+
return sdkVersion;
51+
}
52+
53+
/**
54+
* Getter for dockerfile
55+
*
56+
* @return dockerfile
57+
*/
58+
public File getDockerfile() {
59+
return dockerfile;
60+
}
61+
}

src/main/resources/sdk/Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
FROM centos:7
2+
3+
ARG TARANTOOL_WORKDIR="/app"
4+
ARG TARANTOOL_RUNDIR="/tmp/run"
5+
ARG TARANTOOL_DATADIR="/tmp/data"
6+
ARG SDK_TGT_DIR="/sdk"
7+
ARG URI=""
8+
ARG SDK_VERSION=""
9+
ARG SDK_TGZ=$SDK_VERSION.tar.gz
10+
11+
ENV URI=$URI
12+
ENV SDK_VERSION=$SDK_VERSION
13+
ENV SDK_TGT_DIR=$SDK_TGT_DIR
14+
ENV TARANTOOL_WORKDIR=$TARANTOOL_WORKDIR
15+
ENV TARANTOOL_RUNDIR=$TARANTOOL_RUNDIR
16+
ENV TARANTOOL_DATADIR=$TARANTOOL_DATADIR
17+
18+
RUN curl https://curl.se/ca/cacert.pem -o /etc/pki/tls/certs/ca-bundle.crt && \
19+
yum -y install wget && \
20+
wget $URI/$SDK_TGZ && \
21+
mkdir ./tmp_sdk && tar -xf $SDK_TGZ -C ./tmp_sdk && \
22+
mv ./tmp_sdk/tarantool-enterprise $SDK_TGT_DIR && rm $SDK_TGZ && \
23+
cp $SDK_TGT_DIR/tarantool /usr/bin/tarantool
24+
25+
WORKDIR $TARANTOOL_WORKDIR

src/main/resources/server.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@ box.cfg {
55
log_level = 6,
66
}
77
-- API user will be able to login with this password
8-
box.schema.user.create('api_user', { password = 'secret' })
8+
box.schema.user.create('api_user', { password = 'secret', if_not_exists = true })
99
-- API user will be able to create spaces, add or remove data, execute functions
10-
box.schema.user.grant('api_user', 'read,write,execute', 'universe')
10+
box.schema.user.grant('api_user', 'read,write,execute', 'universe', nil, { if_not_exists = true })

src/test/java/org/testcontainers/containers/TarantoolCartridgeContainerReplicasetsTest.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import org.junit.jupiter.api.Test;
44
import org.slf4j.LoggerFactory;
55
import org.testcontainers.containers.output.Slf4jLogConsumer;
6-
import org.testcontainers.containers.wait.strategy.Wait;
76
import org.testcontainers.utility.MountableFile;
87

98
import java.time.Duration;
@@ -36,7 +35,7 @@ public void test_ClusterContainer_StartsSuccessfully_ifFilesAreCopiedUnderRoot()
3635

3736
container.start();
3837
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
39-
if(container.isRunning())
38+
if (container.isRunning())
4039
container.stop();
4140
}
4241
}

src/test/java/org/testcontainers/containers/TarantoolCartridgeStaticContainerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class TarantoolCartridgeStaticContainerTest {
2626
LoggerFactory.getLogger(TarantoolCartridgeStaticContainerTest.class)));
2727

2828
@Test
29-
public void test_StaticClusterContainer_StartsSuccessfully_ifDirectoryBinndingIsUsed() throws Exception {
29+
public void test_StaticClusterContainer_StartsSuccessfully_ifDirectoryBindingIsUsed() throws Exception {
3030
CartridgeContainerTestUtils.executeProfileReplaceSmokeTest(container);
3131
}
3232
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package org.testcontainers.containers;
2+
3+
4+
import io.tarantool.driver.TarantoolVersion;
5+
import io.tarantool.driver.api.TarantoolClient;
6+
import io.tarantool.driver.api.TarantoolClientFactory;
7+
import io.tarantool.driver.api.TarantoolResult;
8+
import io.tarantool.driver.api.tuple.TarantoolTuple;
9+
import org.junit.jupiter.api.Assertions;
10+
import org.junit.jupiter.api.Test;
11+
12+
import java.io.File;
13+
import java.net.URISyntaxException;
14+
import java.util.List;
15+
16+
/**
17+
* @author Oleg Kuznetsov
18+
*/
19+
public class TarantoolSdkContainerTest {
20+
21+
@Test
22+
void test_should_createTarantoolContainerFromSdk() {
23+
try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
24+
new TarantoolImageParams("tarantool-enterprise-bundle-2.8.3-21-g7d35cd2be-r470")
25+
)) {
26+
tarantoolContainer.start();
27+
28+
final TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client =
29+
TarantoolClientFactory.createClient()
30+
.withCredentials("api_user", "secret")
31+
.withAddress(tarantoolContainer.getHost(), tarantoolContainer.getMappedPort(3301))
32+
.build();
33+
34+
final List<?> result = client.eval("return 'test'").join();
35+
final TarantoolVersion version = client.getVersion();
36+
37+
Assertions.assertEquals("test", result.get(0));
38+
Assertions.assertTrue(version.toString().startsWith("Tarantool 2.8.3 (Binary)"));
39+
}
40+
}
41+
42+
@Test
43+
void test_should_createTarantoolContainerFromSdk_ifDockerfileSpecified() throws URISyntaxException {
44+
final File dockerfile = new File(
45+
TarantoolSdkContainerTest.class.getClassLoader().getResource("testsdk/Dockerfile").toURI()
46+
);
47+
48+
try (final TarantoolContainer tarantoolContainer = new TarantoolContainer(
49+
new TarantoolImageParams("testsdk", dockerfile))
50+
.withDirectoryBinding("testsdk")) {
51+
52+
tarantoolContainer.start();
53+
54+
final TarantoolClient<TarantoolTuple, TarantoolResult<TarantoolTuple>> client =
55+
TarantoolClientFactory.createClient()
56+
.withCredentials("api_user", "secret")
57+
.withAddress(tarantoolContainer.getHost(), tarantoolContainer.getMappedPort(3301))
58+
.build();
59+
60+
final List<?> result = client.eval("return 'test'").join();
61+
final TarantoolVersion version = client.getVersion();
62+
63+
Assertions.assertEquals("test", result.get(0));
64+
Assertions.assertTrue(version.toString().startsWith("Tarantool 2.7.3 (Binary)"));
65+
}
66+
}
67+
}

0 commit comments

Comments
 (0)