diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java index 6a1c9b2e1b..08747e45cf 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/builder/steps/BuildImageStep.java @@ -121,6 +121,7 @@ private Image afterCachedLayerSteps() imageBuilder .addEnvironment(baseImage.getEnvironment()) .addLabels(baseImage.getLabels()) + .setHealthCheck(baseImage.getHealthCheck()) .addExposedPorts(baseImage.getExposedPorts()) .addVolumes(baseImage.getVolumes()) .setWorkingDirectory(baseImage.getWorkingDirectory()); diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/DockerHealthCheck.java b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/DockerHealthCheck.java index 40c28ac642..9cb130ba51 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/DockerHealthCheck.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/configuration/DockerHealthCheck.java @@ -19,7 +19,6 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.time.Duration; -import java.util.Arrays; import java.util.List; import java.util.Optional; import javax.annotation.Nullable; @@ -37,7 +36,6 @@ public static class Builder { @Nullable private Integer retries; private Builder(ImmutableList command) { - Preconditions.checkArgument(command.size() > 1, "command must not be empty"); this.command = command; } @@ -92,58 +90,15 @@ public DockerHealthCheck build() { } /** - * Creates a disabled {@link DockerHealthCheck} (corresponds to "NONE" in container config). + * Creates a new {@link DockerHealthCheck.Builder} with the specified command. * - * @return the new {@link DockerHealthCheck} + * @param command the command + * @return a new {@link DockerHealthCheck.Builder} */ - public static DockerHealthCheck disabled() { - return new DockerHealthCheck(ImmutableList.of("NONE"), null, null, null, null); - } - - /** - * Creates a new {@link DockerHealthCheck} with the command set to be inherited from the base - * image. - * - * @return the new {@link DockerHealthCheck} - */ - public static DockerHealthCheck inherited() { - return new DockerHealthCheck(ImmutableList.of(), null, null, null, null); - } - - /** - * Creates a new {@link DockerHealthCheck.Builder} with the specified healthcheck command to be - * directly executed (corresponds to "CMD" in container config). - * - * @param command the healthcheck command to execute - * @return the new {@link DockerHealthCheck.Builder} - */ - public static Builder builderWithExecCommand(List command) { - return new Builder(ImmutableList.builder().add("CMD").addAll(command).build()); - } - - /** - * Creates a new {@link DockerHealthCheck.Builder} with the specified healthcheck command to be - * directly executed (corresponds to "CMD" in container config). - * - * @param command the healthcheck command to execute - * @return the new {@link DockerHealthCheck.Builder} - */ - public static Builder builderWithExecCommand(String... command) { - return new Builder( - ImmutableList.builder().add("CMD").addAll(Arrays.asList(command)).build()); - } - - /** - * Creates a new {@link DockerHealthCheck.Builder} with the specified healthcheck command to be - * run by the container's default shell (corresponds to "CMD-SHELL" in container config). This - * command cannot be run on containers with no default shell. - * - * @param command the shell command to run - * @return the new {@link DockerHealthCheck.Builder} - */ - public static Builder builderWithShellCommand(String command) { - Preconditions.checkArgument(!command.trim().isEmpty(), "command must not be empty/whitespace"); - return new Builder(ImmutableList.of("CMD-SHELL", command)); + public static DockerHealthCheck.Builder fromCommand(List command) { + Preconditions.checkArgument(command.size() > 0, "command must not be empty"); + Preconditions.checkArgument(!command.contains(null), "command must not contain null elements"); + return new Builder(ImmutableList.copyOf(command)); } private final ImmutableList command; diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java index 8cb0bd9cbf..2e5389d906 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/Image.java @@ -52,7 +52,7 @@ public static class Builder { @Nullable private Instant created; @Nullable private ImmutableList entrypoint; @Nullable private ImmutableList programArguments; - private DockerHealthCheck healthCheck = DockerHealthCheck.inherited(); + @Nullable private DockerHealthCheck healthCheck; @Nullable private String workingDirectory; @Nullable private String user; @@ -136,7 +136,7 @@ public Builder setProgramArguments(@Nullable List programArguments) { * @param healthCheck the healthcheck configuration * @return this */ - public Builder setHealthCheck(DockerHealthCheck healthCheck) { + public Builder setHealthCheck(@Nullable DockerHealthCheck healthCheck) { this.healthCheck = healthCheck; return this; } @@ -271,7 +271,7 @@ public static Builder builder( @Nullable private final ImmutableList programArguments; /** Healthcheck configuration. */ - private final DockerHealthCheck healthCheck; + @Nullable private final DockerHealthCheck healthCheck; /** Ports that the container listens on. */ @Nullable private final ImmutableSet exposedPorts; @@ -296,7 +296,7 @@ private Image( @Nullable ImmutableMap environment, @Nullable ImmutableList entrypoint, @Nullable ImmutableList programArguments, - DockerHealthCheck healthCheck, + @Nullable DockerHealthCheck healthCheck, @Nullable ImmutableSet exposedPorts, @Nullable ImmutableSet volumes, @Nullable ImmutableMap labels, @@ -341,6 +341,7 @@ public ImmutableList getProgramArguments() { return programArguments; } + @Nullable public DockerHealthCheck getHealthCheck() { return healthCheck; } diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java index 3be70e2be2..e64fbd86c4 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslator.java @@ -171,8 +171,7 @@ public Blob getContainerConfigurationBlob() { // Ignore healthcheck if not Docker/command is empty DockerHealthCheck healthCheck = image.getHealthCheck(); - if (image.getImageFormat() == V22ManifestTemplate.class - && !healthCheck.getCommand().isEmpty()) { + if (image.getImageFormat() == V22ManifestTemplate.class && healthCheck != null) { template.setContainerHealthCheckTest(healthCheck.getCommand()); healthCheck .getInterval() diff --git a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java index 6575d6064b..5f1a1d2a0c 100644 --- a/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java +++ b/jib-core/src/main/java/com/google/cloud/tools/jib/image/json/JsonToImageTranslator.java @@ -17,6 +17,7 @@ package com.google.cloud.tools.jib.image.json; import com.google.cloud.tools.jib.blob.BlobDescriptor; +import com.google.cloud.tools.jib.configuration.DockerHealthCheck; import com.google.cloud.tools.jib.configuration.Port; import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; import com.google.cloud.tools.jib.image.DescriptorDigest; @@ -29,6 +30,7 @@ import com.google.cloud.tools.jib.image.ReferenceNoDiffIdLayer; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.ImmutableSet; +import java.time.Duration; import java.time.Instant; import java.time.format.DateTimeParseException; import java.util.ArrayList; @@ -146,6 +148,27 @@ public static Image toImage( imageBuilder.setProgramArguments(containerConfigurationTemplate.getContainerCmd()); } + List baseHealthCheckCommand = containerConfigurationTemplate.getContainerHealthTest(); + if (baseHealthCheckCommand != null) { + DockerHealthCheck.Builder builder = DockerHealthCheck.fromCommand(baseHealthCheckCommand); + if (containerConfigurationTemplate.getContainerHealthInterval() != null) { + builder.setInterval( + Duration.ofNanos(containerConfigurationTemplate.getContainerHealthInterval())); + } + if (containerConfigurationTemplate.getContainerHealthTimeout() != null) { + builder.setTimeout( + Duration.ofNanos(containerConfigurationTemplate.getContainerHealthTimeout())); + } + if (containerConfigurationTemplate.getContainerHealthStartPeriod() != null) { + builder.setStartPeriod( + Duration.ofNanos(containerConfigurationTemplate.getContainerHealthStartPeriod())); + } + if (containerConfigurationTemplate.getContainerHealthRetries() != null) { + builder.setRetries(containerConfigurationTemplate.getContainerHealthRetries()); + } + imageBuilder.setHealthCheck(builder.build()); + } + if (containerConfigurationTemplate.getContainerExposedPorts() != null) { imageBuilder.addExposedPorts( portMapToSet(containerConfigurationTemplate.getContainerExposedPorts())); diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java index 65659f3cd6..34f8a2ba66 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/builder/steps/BuildImageStepTest.java @@ -22,6 +22,7 @@ import com.google.cloud.tools.jib.cache.CachedLayer; import com.google.cloud.tools.jib.configuration.BuildConfiguration; import com.google.cloud.tools.jib.configuration.ContainerConfiguration; +import com.google.cloud.tools.jib.configuration.DockerHealthCheck; import com.google.cloud.tools.jib.configuration.Port; import com.google.cloud.tools.jib.event.EventDispatcher; import com.google.cloud.tools.jib.filesystem.AbsoluteUnixPath; @@ -36,6 +37,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.MoreExecutors; import java.security.DigestException; +import java.time.Duration; import java.time.Instant; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; @@ -133,6 +135,13 @@ public BlobDescriptor getBlobDescriptor() { .setWorkingDirectory("/base/working/directory") .setEntrypoint(ImmutableList.of("baseImageEntrypoint")) .setProgramArguments(ImmutableList.of("catalina.sh", "run")) + .setHealthCheck( + DockerHealthCheck.fromCommand(ImmutableList.of("CMD-SHELL", "echo hi")) + .setInterval(Duration.ofSeconds(3)) + .setTimeout(Duration.ofSeconds(2)) + .setStartPeriod(Duration.ofSeconds(1)) + .setRetries(20) + .build()) .addExposedPorts(ImmutableSet.of(Port.tcp(1000), Port.udp(2000))) .addVolumes( ImmutableSet.of( @@ -228,6 +237,17 @@ public void test_propagateBaseImageConfiguration() "base.label.2", "new.value"), image.getLabels()); + Assert.assertNotNull(image.getHealthCheck()); + Assert.assertEquals( + ImmutableList.of("CMD-SHELL", "echo hi"), image.getHealthCheck().getCommand()); + Assert.assertTrue(image.getHealthCheck().getInterval().isPresent()); + Assert.assertEquals(Duration.ofSeconds(3), image.getHealthCheck().getInterval().get()); + Assert.assertTrue(image.getHealthCheck().getTimeout().isPresent()); + Assert.assertEquals(Duration.ofSeconds(2), image.getHealthCheck().getTimeout().get()); + Assert.assertTrue(image.getHealthCheck().getStartPeriod().isPresent()); + Assert.assertEquals(Duration.ofSeconds(1), image.getHealthCheck().getStartPeriod().get()); + Assert.assertTrue(image.getHealthCheck().getRetries().isPresent()); + Assert.assertEquals(20, (int) image.getHealthCheck().getRetries().get()); Assert.assertEquals( ImmutableSet.of(Port.tcp(1000), Port.udp(2000), Port.tcp(3000), Port.udp(4000)), image.getExposedPorts()); diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/DockerHealthCheckTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/DockerHealthCheckTest.java index c03fe5d8a5..9d0a90d592 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/DockerHealthCheckTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/configuration/DockerHealthCheckTest.java @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableList; import java.time.Duration; +import java.util.Arrays; import org.junit.Assert; import org.junit.Test; @@ -25,9 +26,9 @@ public class DockerHealthCheckTest { @Test - public void testBuild_parameters() { + public void testBuild() { DockerHealthCheck healthCheck = - DockerHealthCheck.builderWithShellCommand("echo hi") + DockerHealthCheck.fromCommand(ImmutableList.of("echo", "hi")) .setInterval(Duration.ofNanos(123)) .setTimeout(Duration.ofNanos(456)) .setStartPeriod(Duration.ofNanos(789)) @@ -45,35 +46,19 @@ public void testBuild_parameters() { } @Test - public void testBuild_propagated() { - DockerHealthCheck healthCheck = DockerHealthCheck.inherited(); - Assert.assertTrue(healthCheck.getCommand().isEmpty()); - } - - @Test - public void testBuild_execArray() { - DockerHealthCheck healthCheck = - DockerHealthCheck.builderWithExecCommand("test", "command").build(); - Assert.assertEquals(ImmutableList.of("CMD", "test", "command"), healthCheck.getCommand()); - } - - @Test - public void testBuild_execList() { - DockerHealthCheck healthCheck = - DockerHealthCheck.builderWithExecCommand(ImmutableList.of("test", "command")).build(); - Assert.assertEquals(ImmutableList.of("CMD", "test", "command"), healthCheck.getCommand()); - } + public void testBuild_invalidCommand() { + try { + DockerHealthCheck.fromCommand(ImmutableList.of()); + Assert.fail(); + } catch (IllegalArgumentException ex) { + Assert.assertEquals("command must not be empty", ex.getMessage()); + } - @Test - public void testBuild_shell() { - DockerHealthCheck healthCheck = - DockerHealthCheck.builderWithShellCommand("shell command").build(); - Assert.assertEquals(ImmutableList.of("CMD-SHELL", "shell command"), healthCheck.getCommand()); - } - - @Test - public void testDisabled() { - DockerHealthCheck healthCheck = DockerHealthCheck.disabled(); - Assert.assertEquals(ImmutableList.of("NONE"), healthCheck.getCommand()); + try { + DockerHealthCheck.fromCommand(Arrays.asList("CMD", null)); + Assert.fail(); + } catch (IllegalArgumentException ex) { + Assert.assertEquals("command must not contain null elements", ex.getMessage()); + } } } diff --git a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java index bccc92d371..9a7fe5f093 100644 --- a/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java +++ b/jib-core/src/test/java/com/google/cloud/tools/jib/image/json/ImageToJsonTranslatorTest.java @@ -63,7 +63,7 @@ private void setUp(Class imageFormat) .setEntrypoint(Arrays.asList("some", "entrypoint", "command")) .setProgramArguments(Arrays.asList("arg1", "arg2")) .setHealthCheck( - DockerHealthCheck.builderWithShellCommand("/checkhealth") + DockerHealthCheck.fromCommand(ImmutableList.of("CMD-SHELL", "/checkhealth")) .setInterval(Duration.ofSeconds(3)) .setTimeout(Duration.ofSeconds(1)) .setStartPeriod(Duration.ofSeconds(2)) diff --git a/jib-gradle-plugin/CHANGELOG.md b/jib-gradle-plugin/CHANGELOG.md index 4d08d12772..0ea7785d03 100644 --- a/jib-gradle-plugin/CHANGELOG.md +++ b/jib-gradle-plugin/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - `container.workingDirectory` configuration parameter to set the working directory ([#1225](https://github.com/GoogleContainerTools/jib/issues/1225)) - Adds support for configuring volumes ([#1121](https://github.com/GoogleContainerTools/jib/issues/1121)) - Exposed ports are now propagated from the base image ([#595](https://github.com/GoogleContainerTools/jib/issues/595)) +- Docker health check is now propagated from the base image ([#595](https://github.com/GoogleContainerTools/jib/issues/595)) ### Changed diff --git a/jib-maven-plugin/CHANGELOG.md b/jib-maven-plugin/CHANGELOG.md index 108880677f..04b59f1328 100644 --- a/jib-maven-plugin/CHANGELOG.md +++ b/jib-maven-plugin/CHANGELOG.md @@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file. - `` configuration parameter to set the working directory ([#1225](https://github.com/GoogleContainerTools/jib/issues/1225)) - Adds support for configuring volumes ([#1121](https://github.com/GoogleContainerTools/jib/issues/1121)) - Exposed ports are now propagated from the base image ([#595](https://github.com/GoogleContainerTools/jib/issues/595)) +- Docker health check is now propagated from the base image ([#595](https://github.com/GoogleContainerTools/jib/issues/595)) ### Changed