Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add container creation timestamp configuration #1888

Merged
merged 17 commits into from
Aug 9, 2019
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions jib-gradle-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@ All notable changes to this project will be documented in this file.
### Added

- Can now set timestamps (last modified time) of the files in the built image with `jib.container.filesModificationTime`. The value should either be `EPOCH_PLUS_SECOND` to set the timestamps to Epoch + 1 second (default behavior), or an ISO 8601 date time parsable with [`DateTimeFormatter.ISO_DATE_TIME`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/format/DateTimeFormatter.html) such as `2019-07-15T10:15:30+09:00` or `2011-12-03T22:42:05Z` ([#1818](https://github.com/GoogleContainerTools/jib/pull/1818))
- Can now set container creation timestamp with `jib.container.creationTime`. The value should be `EPOCH_PLUS_SECOND`, `USE_CURRENT_TIMESTAMP`, or an ISO 8601 date time ([#1609](https://github.com/GoogleContainerTools/jib/issues/1609))

### Changed

- When building to a registry, Jib now skips downloading and caching base image layers that already exist in the target registry. This feature will be particularly useful in CI/CD environments. However, if you want to force caching base image layers locally, set the system property `-Djib.alwaysCacheBaseImage=true` ([#1840](https://github.com/GoogleContainerTools/jib/pull/1840))
- `jib.container.useCurrentTimestamp` has been deprecated in favor of `jib.container.creationTime` with `USE_CURRENT_TIMESTAMP` ([#1609](https://github.com/GoogleContainerTools/jib/issues/1609))
- Default container creation time is changed from epoch to epoch + 1 second

### Fixed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.google.cloud.tools.jib.api.InvalidImageReferenceException;
import java.io.IOException;
import java.security.DigestException;
import java.time.Instant;
import org.hamcrest.CoreMatchers;
import org.junit.Assert;
import org.junit.ClassRule;
Expand Down Expand Up @@ -67,7 +68,7 @@ public void testBuild_empty() throws IOException, InterruptedException, DigestEx
+ System.nanoTime();
Assert.assertEquals("", JibRunHelper.buildAndRun(emptyTestProject, targetImage));
assertDockerInspect(targetImage);
JibRunHelper.assertCreationTimeEpoch(targetImage);
JibRunHelper.assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), targetImage);
}

@Test
Expand All @@ -87,9 +88,7 @@ public void testDockerDaemon_empty() throws IOException, InterruptedException, D
String targetImage = "emptyimage:gradle" + System.nanoTime();
Assert.assertEquals(
"", JibRunHelper.buildToDockerDaemonAndRun(emptyTestProject, targetImage, "build.gradle"));
Assert.assertEquals(
"1970-01-01T00:00:00Z",
new Command("docker", "inspect", "-f", "{{.Created}}", targetImage).run().trim());
JibRunHelper.assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), targetImage);
assertDockerInspect(targetImage);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ public void testGradleLayerConfiguration_multiModule() throws IOException {
// snapshot dependencies (4)
// dependencies (5)

Path complexServiceRoot = multiTestProject.getProjectRoot().resolve("complex-service");
// verify dependencies
List<String> dependencies = layers.get(5);
List<String> expectedDependencies =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.DigestException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -87,8 +88,8 @@ static void buildAndRunAdditionalTag(

Assert.assertEquals(expectedOutput, pullAndRunBuiltImage(imageReference));
Assert.assertEquals(expectedOutput, pullAndRunBuiltImage(additionalImageReference));
assertCreationTimeEpoch(imageReference);
assertCreationTimeEpoch(additionalImageReference);
assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), imageReference);
assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), additionalImageReference);
}

static BuildResult buildToDockerDaemon(
Expand Down Expand Up @@ -138,11 +139,20 @@ static void assertBuildSuccess(BuildResult buildResult, String taskName, String
Assert.assertThat(buildResult.getOutput(), CoreMatchers.containsString(successMessage));
}

static void assertCreationTimeEpoch(String imageReference)
static void assertSimpleCreationTimeIsEqual(Instant match, String imageReference)
throws IOException, InterruptedException {
Assert.assertEquals(
"1970-01-01T00:00:00Z",
new Command("docker", "inspect", "-f", "{{.Created}}", imageReference).run().trim());
String inspect =
new Command("docker", "inspect", "-f", "{{.Created}}", imageReference).run().trim();
Instant parsed = Instant.parse(inspect);
Assert.assertEquals(match, parsed);
}

static void assertSimpleCreationTimeIsAfter(Instant before, String imageReference)
throws IOException, InterruptedException {
String inspect =
new Command("docker", "inspect", "-f", "{{.Created}}", imageReference).run().trim();
Instant parsed = Instant.parse(inspect);
Assert.assertTrue(parsed.isAfter(before));
}

static void assertImageDigestAndId(Path projectRoot) throws IOException, DigestException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,6 @@ private static boolean isJava11RuntimeOrHigher() {
return Integer.valueOf(split.iterator().next()) >= 11;
}

/**
* Asserts that the creation time of the simple test project is set. If the time parsed from the
* {@code docker inspect} command occurs before the specified time (i.e. if it is 1970), then the
* assertion will fail.
*
* @param before the specified time to compare the resulting image's creation time to
* @param imageReference the image to test
* @throws IOException if the {@code docker inspect} command fails to run
* @throws InterruptedException if the {@code docker inspect} command is interrupted
*/
private static void assertSimpleCreationTimeIsAfter(Instant before, String imageReference)
throws IOException, InterruptedException {
String inspect =
new Command("docker", "inspect", "-f", "{{.Created}}", imageReference).run().trim();
Instant parsed = Instant.parse(inspect);
Assert.assertTrue(parsed.isAfter(before) || parsed.equals(before));
}

private static void assertWorkingDirectory(String expected, String imageReference)
throws IOException, InterruptedException {
Assert.assertEquals(
Expand Down Expand Up @@ -131,11 +113,11 @@ private static void assertDockerInspect(String imageReference)
+ " }"));
}

private static void assertExtraDirectoryDeprecationWarning(String pomXml)
private static void assertExtraDirectoryDeprecationWarning(String buildFile)
throws DigestException, IOException, InterruptedException {
String targetImage = "localhost:6000/simpleimage:gradle" + System.nanoTime();
BuildResult buildResult =
JibRunHelper.buildToDockerDaemon(simpleTestProject, targetImage, pomXml);
JibRunHelper.buildToDockerDaemon(simpleTestProject, targetImage, buildFile);
Assert.assertEquals(
"Hello, world. \n1970-01-01T00:00:01Z\nrw-r--r--\nrw-r--r--\nfoo\ncat\n"
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
Expand Down Expand Up @@ -209,13 +191,12 @@ public void testBuild_simple() throws IOException, InterruptedException, DigestE
"No classes files were found - did you compile your project?"));
}

Instant beforeBuild = Instant.now();
Assert.assertEquals(
"Hello, world. An argument.\n1970-01-01T00:00:01Z\nrw-r--r--\nrw-r--r--\nfoo\ncat\n"
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
JibRunHelper.buildAndRun(simpleTestProject, targetImage));
assertDockerInspect(targetImage);
assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
JibRunHelper.assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), targetImage);
assertWorkingDirectory("/home", targetImage);
assertEntrypoint(
"[java -cp /d1:/d2:/app/resources:/app/classes:/app/libs/* com.test.HelloWorld]",
Expand Down Expand Up @@ -326,7 +307,7 @@ public void testBuild_complex() throws IOException, InterruptedException {
String targetImage = "localhost:6000/compleximage:gradle" + System.nanoTime();
Instant beforeBuild = Instant.now();
buildAndRunComplex(targetImage, "testuser2", "testpassword2", localRegistry2);
assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
JibRunHelper.assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
assertWorkingDirectory("", targetImage);
}

Expand All @@ -335,19 +316,18 @@ public void testBuild_complex_sameFromAndToRegistry() throws IOException, Interr
String targetImage = "localhost:5000/compleximage:gradle" + System.nanoTime();
Instant beforeBuild = Instant.now();
buildAndRunComplex(targetImage, "testuser", "testpassword", localRegistry1);
assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
JibRunHelper.assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
assertWorkingDirectory("", targetImage);
}

@Test
public void testDockerDaemon_simple() throws IOException, InterruptedException, DigestException {
String targetImage = "simpleimage:gradle" + System.nanoTime();
Instant beforeBuild = Instant.now();
Assert.assertEquals(
"Hello, world. An argument.\n1970-01-01T00:00:01Z\nrw-r--r--\nrw-r--r--\nfoo\ncat\n"
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
JibRunHelper.buildToDockerDaemonAndRun(simpleTestProject, targetImage, "build.gradle"));
assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
JibRunHelper.assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), targetImage);
assertDockerInspect(targetImage);
assertWorkingDirectory("/home", targetImage);
}
Expand Down Expand Up @@ -379,13 +359,46 @@ public void testBuild_skipDownloadingBaseImageLayers() throws IOException, Inter
}

@Test
public void testDockerDaemon_filesModificationTimeCustom()
public void testDockerDaemon_timestampCustom()
throws DigestException, IOException, InterruptedException {
String targetImage = "simpleimage:gradle" + System.nanoTime();
Assert.assertEquals(
"Hello, world. \n2011-12-03T01:15:30Z\n",
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-files-modification-time-custom.gradle"));
simpleTestProject, targetImage, "build-timestamps-custom.gradle"));
JibRunHelper.assertSimpleCreationTimeIsEqual(
Instant.parse("2013-11-04T21:29:30Z"), targetImage);
}

@Test
public void testDockerDaemon_timestampDeprecated()
throws DigestException, IOException, InterruptedException {
Instant beforeBuild = Instant.now();
String targetImage = "simpleimage:gradle" + System.nanoTime();
BuildResult buildResult =
JibRunHelper.buildToDockerDaemon(
simpleTestProject, targetImage, "build-usecurrent-deprecated.gradle");
JibRunHelper.assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
Assert.assertThat(
buildResult.getOutput(),
CoreMatchers.containsString(
"'jib.container.useCurrentTimestamp' is deprecated; use 'jib.container.creationTime' with the value 'USE_CURRENT_TIMESTAMP' instead"));
}

@Test
public void testDockerDaemon_timestampFail()
throws InterruptedException, IOException, DigestException {
try {
String targetImage = "simpleimage:gradle" + System.nanoTime();
JibRunHelper.buildToDockerDaemonAndRun(
simpleTestProject, targetImage, "build-usecurrent-deprecated2.gradle");
Assert.fail();
} catch (UnexpectedBuildFailure ex) {
Assert.assertThat(
ex.getMessage(),
CoreMatchers.containsString(
"You cannot configure both 'jib.container.useCurrentTimestamp' and 'jib.container.creationTime'"));
}
}

@Test
Expand Down Expand Up @@ -420,7 +433,6 @@ public void testBuildTar_simple() throws IOException, InterruptedException {

String outputPath =
simpleTestProject.getProjectRoot().resolve("build").resolve("jib-image.tar").toString();
Instant beforeBuild = Instant.now();
BuildResult buildResult =
simpleTestProject.build(
"clean",
Expand All @@ -438,7 +450,7 @@ public void testBuildTar_simple() throws IOException, InterruptedException {
+ "1970-01-01T00:00:01Z\n1970-01-01T00:00:01Z\n",
new Command("docker", "run", "--rm", targetImage).run());
assertDockerInspect(targetImage);
assertSimpleCreationTimeIsAfter(beforeBuild, targetImage);
JibRunHelper.assertSimpleCreationTimeIsEqual(Instant.ofEpochSecond(1), targetImage);
assertWorkingDirectory("/home", targetImage);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ dependencies {
jib {
to.image = System.getProperty("_TARGET_IMAGE")
container.filesModificationTime = '2011-12-03T10:15:30+09:00'
container.creationTime = '2013-11-05T06:29:30+09:00'
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
plugins {
id 'java'
id 'com.google.cloud.tools.jib'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile files('libs/dependency-1.0.0.jar')
}

jib {
to.image = System.getProperty("_TARGET_IMAGE")
container.useCurrentTimestamp = true
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
plugins {
id 'java'
id 'com.google.cloud.tools.jib'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
compile files('libs/dependency-1.0.0.jar')
}

jib {
to.image = System.getProperty("_TARGET_IMAGE")
container.useCurrentTimestamp = true
container.creationTime = 'USE_CURRENT_TIMESTAMP'
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jib {
credHelper = 'gcr'
}
container {
useCurrentTimestamp = true
creationTime = 'EPOCH_PLUS_SECOND'
args = ['An argument.']
ports = ['1000/tcp', '2000-2003/udp']
labels = [key1:'value1', key2:'value2']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jib {
}
}
container {
useCurrentTimestamp = true
creationTime = 'USE_CURRENT_TIMESTAMP'
chanseokoh marked this conversation as resolved.
Show resolved Hide resolved
args = ['An argument.']
mainClass = 'com.test.HelloWorld'
jvmFlags = ['-Xms512m', '-Xdebug']
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import com.google.cloud.tools.jib.plugins.common.InvalidAppRootException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerVolumeException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerizingModeException;
import com.google.cloud.tools.jib.plugins.common.InvalidCreationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidFilesModificationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidWorkingDirectoryException;
import com.google.cloud.tools.jib.plugins.common.JibBuildRunner;
Expand Down Expand Up @@ -172,6 +173,14 @@ public void buildDocker()
+ ex.getInvalidFilesModificationTime(),
ex);

} catch (InvalidCreationTimeException ex) {
throw new GradleException(
"container.creationTime should be an ISO 8601 date-time (see "
+ "DateTimeFormatter.ISO_DATE_TIME) or a special keyword (\"EPOCH_PLUS_SECOND\", "
+ "\"USE_CURRENT_TIMESTAMP\"): "
+ ex.getInvalidCreationTime(),
ex);

} catch (IncompatibleBaseImageJavaVersionException ex) {
throw new GradleException(
HelpfulSuggestions.forIncompatibleBaseImageJavaVesionForGradle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import com.google.cloud.tools.jib.plugins.common.InvalidAppRootException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerVolumeException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerizingModeException;
import com.google.cloud.tools.jib.plugins.common.InvalidCreationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidFilesModificationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidWorkingDirectoryException;
import com.google.cloud.tools.jib.plugins.common.JibBuildRunner;
Expand Down Expand Up @@ -152,6 +153,14 @@ public void buildImage()
+ ex.getInvalidFilesModificationTime(),
ex);

} catch (InvalidCreationTimeException ex) {
throw new GradleException(
"container.creationTime should be an ISO 8601 date-time (see "
+ "DateTimeFormatter.ISO_DATE_TIME) or a special keyword (\"EPOCH_PLUS_SECOND\", "
+ "\"USE_CURRENT_TIMESTAMP\"): "
+ ex.getInvalidCreationTime(),
ex);

} catch (IncompatibleBaseImageJavaVersionException ex) {
throw new GradleException(
HelpfulSuggestions.forIncompatibleBaseImageJavaVesionForGradle(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.cloud.tools.jib.plugins.common.InvalidAppRootException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerVolumeException;
import com.google.cloud.tools.jib.plugins.common.InvalidContainerizingModeException;
import com.google.cloud.tools.jib.plugins.common.InvalidCreationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidFilesModificationTimeException;
import com.google.cloud.tools.jib.plugins.common.InvalidWorkingDirectoryException;
import com.google.cloud.tools.jib.plugins.common.JibBuildRunner;
Expand Down Expand Up @@ -170,6 +171,14 @@ public void buildTar()
+ ex.getInvalidFilesModificationTime(),
ex);

} catch (InvalidCreationTimeException ex) {
throw new GradleException(
"container.creationTime should be an ISO 8601 date-time (see "
+ "DateTimeFormatter.ISO_DATE_TIME) or a special keyword (\"EPOCH_PLUS_SECOND\", "
+ "\"USE_CURRENT_TIMESTAMP\"): "
+ ex.getInvalidCreationTime(),
ex);

} catch (IncompatibleBaseImageJavaVersionException ex) {
throw new GradleException(
HelpfulSuggestions.forIncompatibleBaseImageJavaVesionForGradle(
Expand Down
Loading