Skip to content

Commit aac44d3

Browse files
authored
fix: add timeout for docker info read to prevent Jib from getting stuck indefinitely (#4319)
* fix: address nightly build failure with dockerBuild; add timeout for docker info read
1 parent 68f8947 commit aac44d3

File tree

3 files changed

+46
-6
lines changed

3 files changed

+46
-6
lines changed

jib-core/src/main/java/com/google/cloud/tools/jib/docker/CliDockerClient.java

+34-6
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747
import java.util.Collections;
4848
import java.util.List;
4949
import java.util.Map;
50+
import java.util.concurrent.ExecutionException;
51+
import java.util.concurrent.ExecutorService;
52+
import java.util.concurrent.Executors;
53+
import java.util.concurrent.Future;
54+
import java.util.concurrent.TimeUnit;
55+
import java.util.concurrent.TimeoutException;
5056
import java.util.function.Consumer;
5157
import java.util.function.Function;
5258

@@ -103,6 +109,12 @@ public List<DescriptorDigest> getDiffIds() throws DigestException {
103109
/** Default path to the docker executable. */
104110
public static final Path DEFAULT_DOCKER_CLIENT = Paths.get("docker");
105111

112+
/**
113+
* 10 minute timeout to ensure that Jib doesn't get stuck indefinitely when expecting a docker
114+
* output.
115+
*/
116+
public static final Long DOCKER_OUTPUT_TIMEOUT = (long) 10 * 60 * 1000;
117+
106118
/**
107119
* Checks if Docker is installed on the user's system by running the `docker` command.
108120
*
@@ -188,13 +200,19 @@ public boolean supported(Map<String, String> parameters) {
188200
@Override
189201
public DockerInfoDetails info() throws IOException, InterruptedException {
190202
// Runs 'docker info'.
191-
Process infoProcess = docker("info", "-f", "{{json .}}");
192-
InputStream inputStream = infoProcess.getInputStream();
193-
if (infoProcess.waitFor() != 0) {
194-
throw new IOException(
195-
"'docker info' command failed with error: " + getStderrOutput(infoProcess));
203+
ExecutorService executor = Executors.newSingleThreadExecutor();
204+
Future<DockerInfoDetails> readerFuture = executor.submit(this::fetchInfoDetails);
205+
try {
206+
DockerInfoDetails details = readerFuture.get(DOCKER_OUTPUT_TIMEOUT, TimeUnit.MILLISECONDS);
207+
return details;
208+
} catch (TimeoutException e) {
209+
readerFuture.cancel(true); // Interrupt the reader thread
210+
throw new IOException("Timeout reached while waiting for 'docker info' output");
211+
} catch (ExecutionException e) {
212+
throw new IOException("Failed to read output of 'docker info': " + e.getMessage());
213+
} finally {
214+
executor.shutdownNow();
196215
}
197-
return JsonTemplateMapper.readJson(inputStream, DockerInfoDetails.class);
198216
}
199217

200218
@Override
@@ -270,4 +288,14 @@ public DockerImageDetails inspect(ImageReference imageReference)
270288
private Process docker(String... subCommand) throws IOException {
271289
return processBuilderFactory.apply(Arrays.asList(subCommand)).start();
272290
}
291+
292+
private DockerInfoDetails fetchInfoDetails() throws IOException, InterruptedException {
293+
Process infoProcess = docker("info", "-f", "{{json .}}");
294+
InputStream inputStream = infoProcess.getInputStream();
295+
if (infoProcess.waitFor() != 0) {
296+
throw new IOException(
297+
"'docker info' command failed with error: " + getStderrOutput(infoProcess));
298+
}
299+
return JsonTemplateMapper.readJson(inputStream, DockerInfoDetails.class);
300+
}
273301
}

jib-gradle-plugin/src/integration-test/resources/gradle/projects/simple/mock-docker.sh

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#!/bin/bash
22

3+
if [[ "$1" == "info" ]]; then
4+
# Output the JSON string
5+
echo "{\"OSType\":\"linux\",\"Architecture\":\"x86_64\"}"
6+
exit 0
7+
fi
8+
39
# Read stdin to avoid broken pipe
410
cat > /dev/null
511

jib-maven-plugin/src/test/resources/maven/projects/simple/mock-docker.sh

+6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
#!/bin/bash
22

3+
if [[ "$1" == "info" ]]; then
4+
# Output the JSON string
5+
echo "{\"OSType\":\"linux\",\"Architecture\":\"x86_64\"}"
6+
exit 0
7+
fi
8+
39
# Read stdin to avoid broken pipe
410
cat > /dev/null
511

0 commit comments

Comments
 (0)