Skip to content

Commit e152425

Browse files
Add basic rootless podman support
The implementation is mostly borrowed from the rootless docker strategy.
1 parent 76d767e commit e152425

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package org.testcontainers.dockerclient;
2+
3+
import com.sun.jna.Library;
4+
import com.sun.jna.Native;
5+
import lombok.Getter;
6+
import lombok.extern.slf4j.Slf4j;
7+
import org.apache.commons.lang3.StringUtils;
8+
import org.apache.commons.lang3.SystemUtils;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
import java.net.URI;
12+
import java.nio.file.Files;
13+
import java.nio.file.Path;
14+
import java.nio.file.Paths;
15+
import java.util.Optional;
16+
17+
/**
18+
*
19+
* @deprecated this class is used by the SPI and should not be used directly
20+
*/
21+
@Deprecated
22+
@Slf4j
23+
public final class RootlessPodmanClientProviderStrategy extends DockerClientProviderStrategy {
24+
25+
public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1;
26+
27+
@Getter(lazy = true)
28+
@Nullable
29+
private final Path socketPath = resolveSocketPath();
30+
31+
private Path resolveSocketPath() {
32+
return tryEnv()
33+
.orElseGet(() -> {
34+
Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid());
35+
return tryFolder(implicitPath).orElse(null);
36+
});
37+
}
38+
39+
private Optional<Path> tryEnv() {
40+
String xdgRuntimeDir = System.getenv("XDG_RUNTIME_DIR");
41+
if (StringUtils.isBlank(xdgRuntimeDir)) {
42+
log.debug("$XDG_RUNTIME_DIR is not set.");
43+
return Optional.empty();
44+
}
45+
Path path = Paths.get(xdgRuntimeDir);
46+
if (!Files.exists(path)) {
47+
log.debug("$XDG_RUNTIME_DIR is set to '{}' but the folder does not exist.", path);
48+
return Optional.empty();
49+
}
50+
Path podmanSocketPath = path.resolve("podman/podman.sock");
51+
if (!Files.exists(podmanSocketPath)) {
52+
log.debug("$XDG_RUNTIME_DIR is set but '{}' does not exist.", podmanSocketPath);
53+
return Optional.empty();
54+
}
55+
return Optional.of(podmanSocketPath);
56+
}
57+
58+
private Optional<Path> tryFolder(Path path) {
59+
if (!Files.exists(path)) {
60+
log.debug("'{}' does not exist.", path);
61+
return Optional.empty();
62+
}
63+
Path podmanSocketPath = path.resolve("podman/podman.sock");
64+
if (!Files.exists(podmanSocketPath)) {
65+
log.debug("'{}' does not exist.", podmanSocketPath);
66+
return Optional.empty();
67+
}
68+
return Optional.of(podmanSocketPath);
69+
}
70+
71+
@Override
72+
public TransportConfig getTransportConfig() throws InvalidConfigurationException {
73+
return TransportConfig.builder().dockerHost(URI.create("unix://" + getSocketPath().toString())).build();
74+
}
75+
76+
@Override
77+
protected boolean isApplicable() {
78+
return SystemUtils.IS_OS_LINUX && getSocketPath() != null && Files.exists(getSocketPath());
79+
}
80+
81+
@Override
82+
public String getDescription() {
83+
return "Rootless Podman accessed via Unix socket (" + getSocketPath() + ")";
84+
}
85+
86+
@Override
87+
protected int getPriority() {
88+
return PRIORITY;
89+
}
90+
91+
private interface LibC extends Library {
92+
LibC INSTANCE = Native.loadLibrary("c", LibC.class);
93+
int getuid();
94+
}
95+
}

core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ org.testcontainers.dockerclient.UnixSocketClientProviderStrategy
33
org.testcontainers.dockerclient.DockerMachineClientProviderStrategy
44
org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy
55
org.testcontainers.dockerclient.RootlessDockerClientProviderStrategy
6+
org.testcontainers.dockerclient.RootlessPodmanClientProviderStrategy

core/src/test/java/org/testcontainers/DockerRegistryContainer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public DockerImageName createImage(String originalImage, String tag) {
100100
.withTag(tag);
101101

102102
// push the image to the registry
103-
client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec();
103+
client.tagImageCmd(dummyImageId, imageName.getUnversionedPart(), tag).exec();
104104

105105
client
106106
.pushImageCmd(imageName.asCanonicalNameString())

0 commit comments

Comments
 (0)