-
Notifications
You must be signed in to change notification settings - Fork 2.5k
/
NativeImageBuildContainerRunner.java
134 lines (117 loc) · 6.21 KB
/
NativeImageBuildContainerRunner.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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
package io.quarkus.deployment.pkg.steps;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Stream;
import org.apache.commons.lang3.RandomStringUtils;
import org.jboss.logging.Logger;
import io.quarkus.deployment.pkg.NativeConfig;
import io.quarkus.deployment.pkg.builditem.CompiledJavaVersionBuildItem;
import io.quarkus.deployment.util.ProcessUtil;
import io.quarkus.runtime.util.ContainerRuntimeUtil;
public abstract class NativeImageBuildContainerRunner extends NativeImageBuildRunner {
private static final Logger log = Logger.getLogger(NativeImageBuildContainerRunner.class);
final NativeConfig nativeConfig;
protected final ContainerRuntimeUtil.ContainerRuntime containerRuntime;
String[] baseContainerRuntimeArgs;
protected final String outputPath;
private final String containerName;
private final boolean needJava17Image;
public NativeImageBuildContainerRunner(NativeConfig nativeConfig, Path outputDir,
CompiledJavaVersionBuildItem.JavaVersion javaVersion) {
this.nativeConfig = nativeConfig;
containerRuntime = nativeConfig.containerRuntime.orElseGet(ContainerRuntimeUtil::detectContainerRuntime);
log.infof("Using %s to run the native image builder", containerRuntime.getExecutableName());
this.baseContainerRuntimeArgs = new String[] { "--env", "LANG=C", "--rm" };
outputPath = outputDir == null ? null : outputDir.toAbsolutePath().toString();
containerName = "build-native-" + RandomStringUtils.random(5, true, false);
// Default to using java17 builder images
this.needJava17Image = true;
}
@Override
public void setup(boolean processInheritIODisabled) {
if (containerRuntime == ContainerRuntimeUtil.ContainerRuntime.DOCKER
|| containerRuntime == ContainerRuntimeUtil.ContainerRuntime.PODMAN) {
// we pull the docker image in order to give users an indication of which step the process is at
// it's not strictly necessary we do this, however if we don't the subsequent version command
// will appear to block and no output will be shown
String effectiveBuilderImage = nativeConfig.getEffectiveBuilderImage(needJava17Image);
log.info("Checking image status " + effectiveBuilderImage);
Process pullProcess = null;
try {
final ProcessBuilder pb = new ProcessBuilder(
Arrays.asList(containerRuntime.getExecutableName(), "pull", effectiveBuilderImage));
pullProcess = ProcessUtil.launchProcess(pb, processInheritIODisabled);
pullProcess.waitFor();
} catch (IOException | InterruptedException e) {
throw new RuntimeException("Failed to pull builder image " + effectiveBuilderImage, e);
} finally {
if (pullProcess != null) {
pullProcess.destroy();
}
}
}
}
@Override
protected String[] getGraalVMVersionCommand(List<String> args) {
return buildCommand("run", Collections.singletonList("--rm"), args);
}
@Override
protected String[] getBuildCommand(List<String> args) {
List<String> containerRuntimeBuildArgs = getContainerRuntimeBuildArgs();
List<String> effectiveContainerRuntimeBuildArgs = new ArrayList<>(containerRuntimeBuildArgs.size() + 2);
effectiveContainerRuntimeBuildArgs.addAll(containerRuntimeBuildArgs);
effectiveContainerRuntimeBuildArgs.add("--name");
effectiveContainerRuntimeBuildArgs.add(containerName);
return buildCommand("run", effectiveContainerRuntimeBuildArgs, args);
}
@Override
protected void objcopy(String... args) {
final List<String> containerRuntimeBuildArgs = getContainerRuntimeBuildArgs();
Collections.addAll(containerRuntimeBuildArgs, "--entrypoint", "/bin/bash");
final ArrayList<String> objcopyCommand = new ArrayList<>(2);
objcopyCommand.add("-c");
objcopyCommand.add("objcopy " + String.join(" ", args));
final String[] command = buildCommand("run", containerRuntimeBuildArgs, objcopyCommand);
runCommand(command, null, null);
}
@Override
public void addShutdownHook(Process process) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
if (process.isAlive()) {
try {
Process removeProcess = new ProcessBuilder(
List.of(containerRuntime.getExecutableName(), "rm", "-f", containerName))
.redirectOutput(ProcessBuilder.Redirect.DISCARD)
.redirectError(ProcessBuilder.Redirect.DISCARD)
.start();
removeProcess.waitFor(2, TimeUnit.SECONDS);
} catch (IOException | InterruptedException e) {
log.debug("Unable to stop running container", e);
}
}
}));
}
protected List<String> getContainerRuntimeBuildArgs() {
List<String> containerRuntimeArgs = new ArrayList<>();
nativeConfig.containerRuntimeOptions.ifPresent(containerRuntimeArgs::addAll);
if (nativeConfig.debugBuildProcess && nativeConfig.publishDebugBuildProcessPort) {
// publish the debug port onto the host if asked for
containerRuntimeArgs.add("--publish=" + NativeImageBuildStep.DEBUG_BUILD_PROCESS_PORT + ":"
+ NativeImageBuildStep.DEBUG_BUILD_PROCESS_PORT);
}
return containerRuntimeArgs;
}
protected String[] buildCommand(String dockerCmd, List<String> containerRuntimeArgs, List<String> command) {
return Stream
.of(Stream.of(containerRuntime.getExecutableName()), Stream.of(dockerCmd), Stream.of(baseContainerRuntimeArgs),
containerRuntimeArgs.stream(), Stream.of(nativeConfig.getEffectiveBuilderImage(needJava17Image)),
command.stream())
.flatMap(Function.identity()).toArray(String[]::new);
}
}