Skip to content

Commit

Permalink
refactor: extracts Kubernetes related classes
Browse files Browse the repository at this point in the history
  • Loading branch information
m4gshm committed Apr 17, 2024
1 parent 8398b21 commit a7d00bf
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 177 deletions.
106 changes: 17 additions & 89 deletions src/main/java/io/github/m4gshm/testcontainers/AbstractPod.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.github.m4gshm.testcontainers;

import com.fasterxml.jackson.databind.json.JsonMapper;
import com.github.dockerjava.api.command.InspectContainerResponse;
import io.fabric8.kubernetes.api.model.ContainerPort;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.ListOptionsBuilder;
Expand All @@ -15,19 +14,13 @@
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.images.builder.Transferable;
import org.testcontainers.shaded.com.google.common.hash.Hashing;
import org.testcontainers.utility.ThrowingFunction;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.time.Duration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
Expand All @@ -39,24 +32,18 @@
import static io.github.m4gshm.testcontainers.KubernetesUtils.RUNNING;
import static io.github.m4gshm.testcontainers.KubernetesUtils.UNKNOWN;
import static io.github.m4gshm.testcontainers.KubernetesUtils.createPod;
import static io.github.m4gshm.testcontainers.KubernetesUtils.escapeQuotes;
import static io.github.m4gshm.testcontainers.KubernetesUtils.getFirstNotReadyContainer;
import static io.github.m4gshm.testcontainers.KubernetesUtils.resource;
import static io.github.m4gshm.testcontainers.KubernetesUtils.shellQuote;
import static io.github.m4gshm.testcontainers.KubernetesUtils.uploadStdIn;
import static io.github.m4gshm.testcontainers.KubernetesUtils.waitEmptyQueue;
import static io.github.m4gshm.testcontainers.PodContainerUtils.config;
import static java.lang.Boolean.getBoolean;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.time.Duration.ofSeconds;
import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static lombok.AccessLevel.PROTECTED;
import static org.apache.commons.compress.archivers.tar.TarArchiveOutputStream.BIGNUMBER_POSIX;
import static org.apache.commons.compress.archivers.tar.TarArchiveOutputStream.LONGFILE_POSIX;

/**
* The base pod start/stop api implementation.
*/
@Slf4j
public abstract class AbstractPod {
public static final String ORG_TESTCONTAINERS_TYPE = "org.testcontainers.type";
Expand All @@ -65,7 +52,6 @@ public abstract class AbstractPod {
private static final String ORG_TESTCONTAINERS_HASH = "org.testcontainers.hash";
private static final String ORG_TESTCONTAINERS_DELETE_ON_STOP = "org.testcontainers.deleteOnStop";
private static final String ORG_TESTCONTAINERS_SESSION_LIMITED = "org.testcontainers.sessionLimited";
protected final Map<Transferable, String> copyToTransferableContainerPathMap = new HashMap<>();
protected final PodBuilderFactory podBuilderFactory = new PodBuilderFactory();
@Getter
@Setter
Expand Down Expand Up @@ -94,6 +80,14 @@ public AbstractPod(@NonNull PodNameGenerator podNameGenerator) {
this.podNameGenerator = podNameGenerator;
}

protected abstract void configure();

protected abstract List<EnvVar> getEnvVars();

protected abstract String[] getCommandParts();

protected abstract void waitUntilContainerStarted();

public void start() {
configure();

Expand Down Expand Up @@ -173,10 +167,7 @@ public void start() {
}
this.pod = podResource;

var containerInfo = new InspectContainerResponse();

//todo fill containerInfo
containerIsStarting(containerInfo, false);
doBeforeStart();

waitUntilPodStarted();
if (localPortForwardEnabled) {
Expand All @@ -185,10 +176,7 @@ public void start() {
waitUntilContainerStarted();
this.started = true;

copyToTransferableContainerPathMap.forEach(this::copyFileToContainer);

//todo fill containerInfo
containerIsStarted(containerInfo, false);
doAfterStart();
}

public void stop() {
Expand All @@ -215,17 +203,11 @@ public String getDockerImageName() {
return podBuilderFactory.getDockerImageName();
}

protected abstract void containerIsStarted(InspectContainerResponse containerInfo, boolean reused);

protected abstract List<EnvVar> getEnvVars();

protected abstract String[] getCommandParts();

protected abstract void waitUntilContainerStarted();

protected abstract void configure();
protected void doBeforeStart() {
}

protected abstract void containerIsStarting(InspectContainerResponse containerInfo, boolean reused);
protected void doAfterStart() {
}

protected KubernetesClient kubernetesClient() {
var kubernetesClient = this.kubernetesClient;
Expand All @@ -244,60 +226,6 @@ protected String hash(Pod pod) {
return Hashing.sha1().hashBytes(jsonMapper.writeValueAsBytes(pod)).toString();
}

@SneakyThrows
public void copyFileToContainer(Transferable transferable, String containerPath) {
assertPodRunning("copyFileToContainer");
var payload = new ByteArrayOutputStream();
try (var tar = new TarArchiveOutputStream(payload)) {
tar.setLongFileMode(LONGFILE_POSIX);
tar.setBigNumberMode(BIGNUMBER_POSIX);
transferable.transferTo(tar, containerPath);
}

uploadTmpTar(payload.toByteArray());
log.info("file {} copied to pod {}", containerPath, pod.get().getMetadata().getName());
}

@SneakyThrows
public void uploadTmpTar(byte[] payload) {
var podName = this.podName;
var podResource = pod;

var tmpDir = "/tmp";
var tarName = tmpDir + "/" + podName + ".tar";
log.debug("tar uploading {}", tarName);

var escapedTarPath = escapeQuotes(tarName);
try (var exec = podResource.terminateOnError().exec("touch", escapedTarPath)) {
waitEmptyQueue(exec);
}

uploadStdIn(pod, getRequestTimeout(), escapedTarPath, payload);
// uploadBase64(payload, escapedTarPath);

var unpackDir = "/";
var extractTarCmd = format("mkdir -p %1$s; tar -C %1$s -xmf %2$s; e=$?; rm %2$s; exit $e",
shellQuote(unpackDir), tarName);

var out = new ByteArrayOutputStream();
var err = new ByteArrayOutputStream();
try (var exec = podResource.redirectingInput().writingOutput(out).writingError(err).exec("sh", "-c", extractTarCmd)) {
waitEmptyQueue(exec);
var exitedCode = exec.exitCode();
var exitCode = exitedCode.get(getRequestTimeout(), MILLISECONDS);
;
var unpacked = exitCode == 0;
if (!unpacked) {
throw new UploadFileException("unpack temporary tar " + tarName +
", exit code " + exitCode +
", out '" + out.toString(UTF_8) + "'" +
", errOut '" + err.toString(UTF_8) + "'");
} else {
log.debug("upload tar -> {}", out.toString(UTF_8));
}
}
}

protected void waitUntilPodStarted() {
var startTime = System.currentTimeMillis();
var pod = getPodResource().get();
Expand Down
39 changes: 39 additions & 0 deletions src/main/java/io/github/m4gshm/testcontainers/KubernetesUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.concurrent.atomic.AtomicReference;

import static java.lang.Boolean.TRUE;
import static java.lang.String.format;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toMap;
Expand Down Expand Up @@ -223,6 +224,44 @@ public static void checkSize(PodResource podResource, int requestTimeout, String
}
}

@SneakyThrows
public static void uploadTmpTar(PodResource podResource, int requestTimeout, String tmpTarName, byte[] payload) {
var tmpDir = "/tmp";
var tarName = tmpDir + "/" + tmpTarName + ".tar";
log.debug("tar uploading {}", tarName);

var escapedTarPath = escapeQuotes(tarName);
try (var exec = podResource.terminateOnError().exec("touch", escapedTarPath)) {
waitEmptyQueue(exec);
}

uploadStdIn(podResource, requestTimeout, escapedTarPath, payload);
// uploadBase64(payload, escapedTarPath);

var unpackDir = "/";
var extractTarCmd = format("mkdir -p %1$s; tar -C %1$s -xmf %2$s; e=$?; rm %2$s; exit $e",
shellQuote(unpackDir), tarName);

var out = new ByteArrayOutputStream();
var err = new ByteArrayOutputStream();
try (var exec = podResource.redirectingInput().writingOutput(out).writingError(err).exec("sh", "-c", extractTarCmd)) {
waitEmptyQueue(exec);
var exitedCode = exec.exitCode();
var exitCode = exitedCode.get(requestTimeout, MILLISECONDS);
;
var unpacked = exitCode == 0;
if (!unpacked) {
throw new UploadFileException("unpack temporary tar " + tarName +
", exit code " + exitCode +
", out '" + out.toString(UTF_8) + "'" +
", errOut '" + err.toString(UTF_8) + "'");
} else {
log.debug("upload tar -> {}", out.toString(UTF_8));
}
}
}


public record ExecResult(int exitCode, String output, String error) {
}

Expand Down
Loading

0 comments on commit a7d00bf

Please sign in to comment.