From 52b8e4dc27e901595395b3aa5d99e5257bf1c8a3 Mon Sep 17 00:00:00 2001 From: SoMuchForSubtlety Date: Sat, 3 Sep 2022 18:43:25 +0200 Subject: [PATCH] Add basic rootless podman support The implementation is mostly borrowed from the rootless docker strategy. --- .../RootlessPodmanClientProviderStrategy.java | 95 +++++++++++++++++++ ....dockerclient.DockerClientProviderStrategy | 1 + .../DockerRegistryContainer.java | 2 +- 3 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java diff --git a/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java new file mode 100644 index 00000000000..1b11b12e6b9 --- /dev/null +++ b/core/src/main/java/org/testcontainers/dockerclient/RootlessPodmanClientProviderStrategy.java @@ -0,0 +1,95 @@ +package org.testcontainers.dockerclient; + +import com.sun.jna.Library; +import com.sun.jna.Native; +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.SystemUtils; +import org.jetbrains.annotations.Nullable; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Optional; + +/** + * + * @deprecated this class is used by the SPI and should not be used directly + */ +@Deprecated +@Slf4j +public final class RootlessPodmanClientProviderStrategy extends DockerClientProviderStrategy { + + public static final int PRIORITY = UnixSocketClientProviderStrategy.PRIORITY + 1; + + @Getter(lazy = true) + @Nullable + private final Path socketPath = resolveSocketPath(); + + private Path resolveSocketPath() { + return tryEnv() + .orElseGet(() -> { + Path implicitPath = Paths.get("/run/user/" + LibC.INSTANCE.getuid()); + return tryFolder(implicitPath).orElse(null); + }); + } + + private Optional tryEnv() { + String xdgRuntimeDir = System.getenv("XDG_RUNTIME_DIR"); + if (StringUtils.isBlank(xdgRuntimeDir)) { + log.debug("$XDG_RUNTIME_DIR is not set."); + return Optional.empty(); + } + Path path = Paths.get(xdgRuntimeDir); + if (!Files.exists(path)) { + log.debug("$XDG_RUNTIME_DIR is set to '{}' but the folder does not exist.", path); + return Optional.empty(); + } + Path podmanSocketPath = path.resolve("podman/podman.sock"); + if (!Files.exists(podmanSocketPath)) { + log.debug("$XDG_RUNTIME_DIR is set but '{}' does not exist.", podmanSocketPath); + return Optional.empty(); + } + return Optional.of(podmanSocketPath); + } + + private Optional tryFolder(Path path) { + if (!Files.exists(path)) { + log.debug("'{}' does not exist.", path); + return Optional.empty(); + } + Path podmanSocketPath = path.resolve("podman/podman.sock"); + if (!Files.exists(podmanSocketPath)) { + log.debug("'{}' does not exist.", podmanSocketPath); + return Optional.empty(); + } + return Optional.of(podmanSocketPath); + } + + @Override + public TransportConfig getTransportConfig() throws InvalidConfigurationException { + return TransportConfig.builder().dockerHost(URI.create("unix://" + getSocketPath().toString())).build(); + } + + @Override + protected boolean isApplicable() { + return SystemUtils.IS_OS_LINUX && getSocketPath() != null && Files.exists(getSocketPath()); + } + + @Override + public String getDescription() { + return "Rootless Podman accessed via Unix socket (" + getSocketPath() + ")"; + } + + @Override + protected int getPriority() { + return PRIORITY; + } + + private interface LibC extends Library { + LibC INSTANCE = Native.loadLibrary("c", LibC.class); + int getuid(); + } +} diff --git a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy index d9cbad0ebff..d55c89485be 100644 --- a/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy +++ b/core/src/main/resources/META-INF/services/org.testcontainers.dockerclient.DockerClientProviderStrategy @@ -3,3 +3,4 @@ org.testcontainers.dockerclient.UnixSocketClientProviderStrategy org.testcontainers.dockerclient.DockerMachineClientProviderStrategy org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy org.testcontainers.dockerclient.RootlessDockerClientProviderStrategy +org.testcontainers.dockerclient.RootlessPodmanClientProviderStrategy diff --git a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java index a907c674386..956bb9fff9e 100644 --- a/core/src/test/java/org/testcontainers/DockerRegistryContainer.java +++ b/core/src/test/java/org/testcontainers/DockerRegistryContainer.java @@ -100,7 +100,7 @@ public DockerImageName createImage(String originalImage, String tag) { .withTag(tag); // push the image to the registry - client.tagImageCmd(dummyImageId, imageName.asCanonicalNameString(), tag).exec(); + client.tagImageCmd(dummyImageId, imageName.getUnversionedPart(), tag).exec(); client .pushImageCmd(imageName.asCanonicalNameString())