|
47 | 47 | import java.util.Collections;
|
48 | 48 | import java.util.List;
|
49 | 49 | 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; |
50 | 56 | import java.util.function.Consumer;
|
51 | 57 | import java.util.function.Function;
|
52 | 58 |
|
@@ -103,6 +109,12 @@ public List<DescriptorDigest> getDiffIds() throws DigestException {
|
103 | 109 | /** Default path to the docker executable. */
|
104 | 110 | public static final Path DEFAULT_DOCKER_CLIENT = Paths.get("docker");
|
105 | 111 |
|
| 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 | + |
106 | 118 | /**
|
107 | 119 | * Checks if Docker is installed on the user's system by running the `docker` command.
|
108 | 120 | *
|
@@ -188,13 +200,19 @@ public boolean supported(Map<String, String> parameters) {
|
188 | 200 | @Override
|
189 | 201 | public DockerInfoDetails info() throws IOException, InterruptedException {
|
190 | 202 | // 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(); |
196 | 215 | }
|
197 |
| - return JsonTemplateMapper.readJson(inputStream, DockerInfoDetails.class); |
198 | 216 | }
|
199 | 217 |
|
200 | 218 | @Override
|
@@ -270,4 +288,14 @@ public DockerImageDetails inspect(ImageReference imageReference)
|
270 | 288 | private Process docker(String... subCommand) throws IOException {
|
271 | 289 | return processBuilderFactory.apply(Arrays.asList(subCommand)).start();
|
272 | 290 | }
|
| 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 | + } |
273 | 301 | }
|
0 commit comments