-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
PortForwardingContainer.java
94 lines (74 loc) · 2.76 KB
/
PortForwardingContainer.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package org.testcontainers.containers;
import com.github.dockerjava.api.model.ContainerNetwork;
import com.trilead.ssh2.Connection;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.SneakyThrows;
import org.testcontainers.utility.DockerImageName;
import java.time.Duration;
import java.util.AbstractMap;
import java.util.Collections;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
public enum PortForwardingContainer {
INSTANCE;
private static String PASSWORD = UUID.randomUUID().toString();
private static ContainerDef DEFINITION = new ContainerDef() {
{
setImage(DockerImageName.parse("testcontainers/sshd:1.2.0"));
addExposedTcpPort(22);
addEnvVar("PASSWORD", PASSWORD);
}
};
private GenericContainer<?> container;
private final Set<Entry<Integer, Integer>> exposedPorts = Collections.newSetFromMap(new ConcurrentHashMap<>());
@Getter(value = AccessLevel.PRIVATE, lazy = true)
private final Connection sshConnection = createSSHSession();
@SneakyThrows
private Connection createSSHSession() {
container = new GenericContainer<>(DEFINITION);
container.start();
Connection connection = new Connection(container.getHost(), container.getMappedPort(22));
connection.setTCPNoDelay(true);
connection.connect(
(hostname, port, serverHostKeyAlgorithm, serverHostKey) -> true,
(int) Duration.ofSeconds(30).toMillis(),
(int) Duration.ofSeconds(30).toMillis()
);
if (!connection.authenticateWithPassword("root", PASSWORD)) {
throw new IllegalStateException("Authentication failed.");
}
return connection;
}
@SneakyThrows
public void exposeHostPort(int port) {
exposeHostPort(port, port);
}
@SneakyThrows
public void exposeHostPort(int hostPort, int containerPort) {
if (exposedPorts.add(new AbstractMap.SimpleEntry<>(hostPort, containerPort))) {
getSshConnection().requestRemotePortForwarding("", containerPort, "localhost", hostPort);
}
}
void start() {
getSshConnection();
}
Optional<ContainerNetwork> getNetwork() {
return Optional
.ofNullable(container)
.map(GenericContainer::getContainerInfo)
.flatMap(it -> it.getNetworkSettings().getNetworks().values().stream().findFirst());
}
void reset() {
if (container != null) {
container.stop();
}
container = null;
((AtomicReference<?>) (Object) sshConnection).set(null);
exposedPorts.clear();
}
}