Skip to content

Commit f77e194

Browse files
committed
Initial commit, most of the code for JsmH2Container.groovy has full test coverage.
0 parents  commit f77e194

14 files changed

Lines changed: 702 additions & 0 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/target/
2+
/.idea/vcs.xml

.idea/.gitignore

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/compiler.xml

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/jarRepositories.xml

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pom.xml

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<modelVersion>4.0.0</modelVersion>
6+
7+
<groupId>com.eficode</groupId>
8+
<artifactId>devstack</artifactId>
9+
<version>1.0-SNAPSHOT</version>
10+
11+
<dependencies>
12+
<!-- https://mvnrepository.com/artifact/org.codehaus.groovy/groovy-all -->
13+
<dependency>
14+
<groupId>org.codehaus.groovy</groupId>
15+
<artifactId>groovy-all</artifactId>
16+
<version>3.0.11</version>
17+
<type>pom</type>
18+
</dependency>
19+
<dependency>
20+
<groupId>org.spockframework</groupId>
21+
<artifactId>spock-core</artifactId>
22+
<version>2.1-groovy-3.0</version>
23+
</dependency>
24+
<dependency>
25+
<groupId>de.gesellix</groupId>
26+
<artifactId>docker-client</artifactId>
27+
<version>2022-05-24T07-36-00</version>
28+
</dependency>
29+
<dependency>
30+
<groupId>org.slf4j</groupId>
31+
<artifactId>slf4j-simple</artifactId>
32+
<version>1.7.36</version>
33+
</dependency>
34+
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-compress -->
35+
<dependency>
36+
<groupId>org.apache.commons</groupId>
37+
<artifactId>commons-compress</artifactId>
38+
<version>1.21</version>
39+
</dependency>
40+
<!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
41+
<dependency>
42+
<groupId>commons-io</groupId>
43+
<artifactId>commons-io</artifactId>
44+
<version>2.11.0</version>
45+
</dependency>
46+
<dependency>
47+
<groupId>com.konghq</groupId>
48+
<artifactId>unirest-java</artifactId>
49+
<version>3.13.6</version>
50+
<classifier>standalone</classifier>
51+
</dependency>
52+
53+
54+
</dependencies>
55+
56+
<build>
57+
<plugins>
58+
<plugin>
59+
<groupId>org.codehaus.gmavenplus</groupId>
60+
<artifactId>gmavenplus-plugin</artifactId>
61+
<version>1.13.1</version>
62+
<executions>
63+
<execution>
64+
<goals>
65+
<goal>execute</goal>
66+
</goals>
67+
</execution>
68+
</executions>
69+
<dependencies>
70+
<dependency>
71+
<groupId>org.apache.groovy</groupId>
72+
<artifactId>groovy</artifactId>
73+
<version>4.0.2</version>
74+
<scope>runtime</scope>
75+
</dependency>
76+
</dependencies>
77+
<configuration>
78+
<scripts>
79+
<script>src/main/groovy/Main.groovy</script>
80+
</scripts>
81+
</configuration>
82+
</plugin>
83+
</plugins>
84+
</build>
85+
86+
<properties>
87+
<maven.compiler.source>11</maven.compiler.source>
88+
<maven.compiler.target>11</maven.compiler.target>
89+
</properties>
90+
91+
</project>
Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package com.eficode.devstack.container
2+
3+
import de.gesellix.docker.client.DockerClientImpl
4+
import de.gesellix.docker.engine.DockerClientConfig
5+
import de.gesellix.docker.engine.DockerEnv
6+
import de.gesellix.docker.engine.EngineResponse
7+
import de.gesellix.docker.remote.api.IdResponse
8+
import de.gesellix.docker.remote.api.core.ClientException
9+
import de.gesellix.docker.remote.api.core.Frame
10+
import de.gesellix.docker.remote.api.core.StreamCallback
11+
import org.apache.commons.compress.archivers.ArchiveEntry
12+
import org.apache.commons.compress.archivers.tar.TarArchiveEntry
13+
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream
14+
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream
15+
import org.apache.commons.compress.utils.IOUtils
16+
import org.apache.commons.io.FileUtils
17+
import org.slf4j.Logger
18+
import org.slf4j.LoggerFactory
19+
20+
import java.nio.file.Files
21+
import java.nio.file.Path
22+
import java.time.Duration
23+
24+
trait ContainerManager {
25+
26+
static Logger log = LoggerFactory.getLogger(ContainerManager.class)
27+
static DockerClientImpl dockerClient = new DockerClientImpl()
28+
abstract String containerName
29+
abstract String containerMainPort
30+
String containerId
31+
32+
33+
abstract String createContainer()
34+
35+
36+
37+
38+
39+
40+
/**
41+
* Replaced the default docker connection (local) with a remote, secure one
42+
* @param host ex: "https://docker.domain.se:2376"
43+
* @param certPath folder containing ca.pem, cert.pem, key.pem
44+
*/
45+
static DockerClientImpl setupSecureRemoteConnection(String host, String certPath) {
46+
47+
DockerClientConfig dockerConfig = new DockerClientConfig(host)
48+
DockerEnv dockerEnv = new DockerEnv(host)
49+
dockerEnv.setCertPath(certPath)
50+
dockerEnv.setTlsVerify("1")
51+
dockerConfig.apply(dockerEnv)
52+
53+
return new DockerClientImpl(dockerConfig)
54+
55+
}
56+
57+
58+
boolean ping() {
59+
return dockerClient.ping().content as String == "OK"
60+
}
61+
String getContainerId() {
62+
63+
if (containerId) {
64+
return containerId
65+
}
66+
log.info("\tResolving container ID for: $containerName")
67+
68+
ArrayList<Map> content = dockerClient.ps().content
69+
70+
Map container = content.find { it.Names.first() == "/" + containerName }
71+
this.containerId = container?.Id
72+
log.info("\tGot:" + this.containerId)
73+
74+
return containerId
75+
}
76+
77+
boolean startContainer() {
78+
79+
dockerClient.startContainer(containerId)
80+
81+
return dockerClient.inspectContainer(containerId).content.state.running
82+
}
83+
84+
boolean stopAndRemoveContainer() {
85+
86+
dockerClient.stop(containerId, 240000)
87+
dockerClient.wait(containerId)
88+
dockerClient.rm(containerId)
89+
90+
91+
try {
92+
dockerClient.inspectContainer(containerId)
93+
} catch (ClientException ex) {
94+
95+
if (ex.response.message == "Not Found") {
96+
return true
97+
}
98+
}
99+
return false
100+
101+
102+
}
103+
104+
105+
106+
107+
static File createTar(ArrayList<String> filePaths, String outputPath) {
108+
109+
110+
File outputFile = new File(outputPath)
111+
TarArchiveOutputStream out = new TarArchiveOutputStream(Files.newOutputStream(outputFile.toPath()))
112+
113+
filePaths.each { filePath ->
114+
File newEntryFile = new File(filePath)
115+
assert newEntryFile.isFile() && newEntryFile.canRead(), "Error creating TAR cant read file:" + filePath
116+
117+
118+
TarArchiveEntry entry = new TarArchiveEntry(newEntryFile, newEntryFile.name)
119+
entry.setSize(newEntryFile.size())
120+
out.putArchiveEntry(entry)
121+
out.write(newEntryFile.bytes)
122+
123+
out.closeArchiveEntry()
124+
}
125+
126+
out.finish()
127+
128+
return outputFile
129+
130+
131+
}
132+
133+
static ArrayList<File> extractTar(File tarFile, String outputPath) {
134+
135+
136+
137+
log.info("Extracting: " + tarFile.path + " (${tarFile.size()/1024}kB)")
138+
log.info("\tTo:" + outputPath)
139+
assert outputPath[-1] == "/", "outputPath must end with /"
140+
ArrayList<File>outFiles = []
141+
TarArchiveInputStream i = new TarArchiveInputStream(tarFile.newInputStream())
142+
143+
ArchiveEntry entry = null
144+
145+
while ((entry = i.getNextEntry()) != null) {
146+
String outName = outputPath + entry.name
147+
log.debug("\tExtracting compressed file:" + entry.name + ", to:" + outputPath)
148+
149+
File outFile = new File(outName)
150+
151+
if (entry.isDirectory()) {
152+
assert outFile.mkdirs(), "Error creating directory:" + outFile.path
153+
}else {
154+
outFile.parentFile.mkdirs()
155+
OutputStream o = Files.newOutputStream(outFile.toPath())
156+
long output = IOUtils.copy(i,o)
157+
log.trace("\t\tExtracted ${(output/1024).round(1)}kB")
158+
o.close()
159+
}
160+
outFiles.add(outFile)
161+
}
162+
163+
return outFiles
164+
}
165+
166+
167+
/**
168+
* Copy files from a container
169+
* @param containerPath can be a file or a path (ending in /)
170+
* @param destinationPath
171+
* @return
172+
*/
173+
ArrayList<File> copyFilesFromContainer(String containerPath, String destinationPath) {
174+
175+
//containerPath can be both a directory or a file
176+
EngineResponse<InputStream> response = dockerClient.getArchive(containerId, containerPath)
177+
178+
179+
Path tempFile = Files.createTempFile("docker_download", ".tar")
180+
FileUtils.copyInputStreamToFile(response.content, tempFile.toFile())
181+
182+
ArrayList<File> outFiles = extractTar(tempFile.toFile(), destinationPath)
183+
184+
Files.delete(tempFile)
185+
186+
return outFiles
187+
188+
}
189+
190+
boolean copyFileToContainer(String srcFilePath, String destinationDirectory) {
191+
192+
193+
File tarFile = createTar([srcFilePath], Files.createTempFile("docker_upload", ".tar").toString())
194+
dockerClient.putArchive(containerId, destinationDirectory, tarFile.newDataInputStream())
195+
196+
return tarFile.delete()
197+
}
198+
199+
200+
201+
202+
203+
static class ContainerCallback<T> implements StreamCallback<T> {
204+
205+
ArrayList<String> output = []
206+
207+
@Override
208+
void onNext(Object o) {
209+
if (o instanceof Frame) {
210+
output.add(o.payloadAsString)
211+
}else {
212+
output.add(o.toString())
213+
}
214+
215+
}
216+
}
217+
218+
219+
ArrayList<String> runBashCommandInContainer(String command, long timeoutS=10) {
220+
221+
222+
ContainerCallback callBack = new ContainerCallback()
223+
EngineResponse<IdResponse> response = dockerClient.exec(containerId, ["/bin/bash", "-c", command],callBack , Duration.ofSeconds(timeoutS))
224+
225+
226+
227+
return callBack.output
228+
}
229+
230+
231+
232+
}

0 commit comments

Comments
 (0)