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

Set configured file ownership when creating tarballs #2499

Merged
merged 18 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from 15 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
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ subprojects {
// for Build Plan and Jib Plugins Extension API
BUILD_PLAN: '0.2.0',
EXTENSION_COMMON: '0.2.0',
GRADLE_EXTENSION: '0.2.0',
MAVEN_EXTENSION: '0.2.0',
GRADLE_EXTENSION: '0.3.0',
MAVEN_EXTENSION: '0.3.0',

COMMONS_COMPRESS: '1.19',
JACKSON_DATABIND: '2.9.10',
Expand Down
4 changes: 4 additions & 0 deletions jib-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ All notable changes to this project will be documented in this file.

### Added

- Now sets configured file ownership when creating layer tars. ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Changed

- Invalidates Jib's local application layer cache due to changes to caching mechanism. (In other words, the local cache generated by old Jib versions is incompatible with this version.) ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,16 @@
* "extractionPath": "/extraction/path/for/layer/entry/1"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* "permissions": "777",
* "ownership": "0:0"
* },
* {
* "sourceFile": "source/file/for/layer/entry/2",
* "extractionPath": "/extraction/path/for/layer/entry/2"
* "sourceModificationTime": "2018-10-03T15:48:32.416152Z"
* "targetModificationTime": "1970-01-01T00:00:01Z",
* "permissions": "777"
* "permissions": "777",
* "ownership": "alice:1234"
* }
* ]
* }</pre>
Expand All @@ -66,6 +68,7 @@ static class LayerEntryTemplate implements JsonTemplate, Comparable<LayerEntryTe
private final Instant sourceModificationTime;
private final Instant targetModificationTime;
private final String permissions;
private final String ownership;

@VisibleForTesting
LayerEntryTemplate(FileEntry layerEntry) throws IOException {
Expand All @@ -74,6 +77,7 @@ static class LayerEntryTemplate implements JsonTemplate, Comparable<LayerEntryTe
sourceModificationTime = Files.getLastModifiedTime(layerEntry.getSourceFile()).toInstant();
targetModificationTime = layerEntry.getModificationTime();
permissions = layerEntry.getPermissions().toOctalString();
ownership = layerEntry.getOwnership();
}

@Override
Expand All @@ -97,7 +101,11 @@ public int compareTo(LayerEntryTemplate otherLayerEntryTemplate) {
if (targetModificationTimeComparison != 0) {
return targetModificationTimeComparison;
}
return permissions.compareTo(otherLayerEntryTemplate.permissions);
int permissionsComparison = permissions.compareTo(otherLayerEntryTemplate.permissions);
if (permissionsComparison != 0) {
return permissionsComparison;
}
return ownership.compareTo(otherLayerEntryTemplate.ownership);
}

@Override
Expand All @@ -113,13 +121,19 @@ public boolean equals(Object other) {
&& extractionPath.equals(otherLayerEntryTemplate.extractionPath)
&& sourceModificationTime.equals(otherLayerEntryTemplate.sourceModificationTime)
&& targetModificationTime.equals(otherLayerEntryTemplate.targetModificationTime)
&& permissions.equals(otherLayerEntryTemplate.permissions);
&& permissions.equals(otherLayerEntryTemplate.permissions)
&& ownership.equals(otherLayerEntryTemplate.ownership);
}

@Override
public int hashCode() {
return Objects.hash(
sourceFile, extractionPath, sourceModificationTime, targetModificationTime, permissions);
sourceFile,
extractionPath,
sourceModificationTime,
targetModificationTime,
permissions,
ownership);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,34 @@ public Blob build() {
entry.setMode((entry.getMode() & ~0777) | layerEntry.getPermissions().getPermissionBits());
entry.setModTime(layerEntry.getModificationTime().toEpochMilli());

entry.setUserId(0);
entry.setGroupId(0);
entry.setUserName("");
entry.setGroupName("");
if (!layerEntry.getOwnership().isEmpty()) {
chanseokoh marked this conversation as resolved.
Show resolved Hide resolved
String user = layerEntry.getOwnership();
String group = "";
int colonIndex = user.indexOf(':');
if (colonIndex != -1) {
group = user.substring(colonIndex + 1);
user = user.substring(0, colonIndex);
}
if (!user.isEmpty()) {
try {
entry.setUserId(Long.parseLong(user));
} catch (NumberFormatException ignored) {
entry.setUserName(user);
}
}
if (!group.isEmpty()) {
try {
entry.setGroupId(Long.parseLong(group));
} catch (NumberFormatException ignored) {
entry.setGroupName(group);
}
}
}

uniqueTarArchiveEntries.add(entry);
}

Expand All @@ -126,13 +154,6 @@ public Blob build() {
// Adds all the files to a tar stream.
TarStreamBuilder tarStreamBuilder = new TarStreamBuilder();
for (TarArchiveEntry entry : sortedFilesystemEntries) {
// Strips out all non-reproducible elements from tar archive entries.
// Modification time is configured per entry
entry.setGroupId(0);
entry.setUserId(0);
entry.setUserName("");
entry.setGroupName("");

Verify.verify(!names.contains(entry.getName()));
names.add(entry.getName());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,4 +187,29 @@ public void testGenerateSelector_permissionsModified() throws IOException {
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry111)),
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry222)));
}

@Test
public void testGenerateSelector_ownersModified() throws IOException {
Path layerFile = temporaryFolder.newFolder("testFolder").toPath().resolve("file");
Files.write(layerFile, "hello".getBytes(StandardCharsets.UTF_8));
FileEntry layerEntry111 =
new FileEntry(
layerFile,
AbsoluteUnixPath.get("/extraction/path"),
FilePermissions.fromOctalString("111"),
FileEntriesLayer.DEFAULT_MODIFICATION_TIME,
"0:0");
FileEntry layerEntry222 =
new FileEntry(
layerFile,
AbsoluteUnixPath.get("/extraction/path"),
FilePermissions.fromOctalString("222"),
FileEntriesLayer.DEFAULT_MODIFICATION_TIME,
"foouser");

// Verify that changing ownership generates a different selector
Assert.assertNotEquals(
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry111)),
LayerEntriesSelector.generateSelector(ImmutableList.of(layerEntry222)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private static FileEntry defaultLayerEntry(Path source, AbsoluteUnixPath destina
FileEntriesLayer.DEFAULT_MODIFICATION_TIME);
}

@Rule public TemporaryFolder temporaryFolder = new TemporaryFolder();
@Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();

@Test
public void testBuild() throws URISyntaxException, IOException {
Expand Down Expand Up @@ -360,9 +360,129 @@ public void testBuild_permissions() throws IOException {
}
}

private Path createFile(Path root, String filename, String content, long modificationTime)
throws IOException {
@Test
public void testBuild_ownership() throws IOException {
Path testRoot = temporaryFolder.getRoot().toPath();
Path someFile = createFile(testRoot, "someFile", "content", 54321);

Blob blob =
new ReproducibleLayerBuilder(
ImmutableList.of(
defaultLayerEntry(someFile, AbsoluteUnixPath.get("/file1")),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file2"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
""),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file3"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file4"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"333:"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file5"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":555"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file6"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"333:555"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file7"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"user:"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file8"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
":group"),
new FileEntry(
someFile,
AbsoluteUnixPath.get("/file9"),
FilePermissions.fromOctalString("123"),
Instant.EPOCH,
"user:group")))
.build();

Path tarFile = temporaryFolder.newFile().toPath();
try (OutputStream out = new BufferedOutputStream(Files.newOutputStream(tarFile))) {
blob.writeTo(out);
}

try (TarArchiveInputStream in = new TarArchiveInputStream(Files.newInputStream(tarFile))) {
TarArchiveEntry entry1 = in.getNextTarEntry();
Assert.assertEquals(0, entry1.getLongUserId());
Assert.assertEquals(0, entry1.getLongGroupId());
Assert.assertEquals("", entry1.getUserName());
Assert.assertEquals("", entry1.getGroupName());

TarArchiveEntry entry2 = in.getNextTarEntry();
Assert.assertEquals(0, entry2.getLongUserId());
Assert.assertEquals(0, entry2.getLongGroupId());
Assert.assertEquals("", entry2.getUserName());
Assert.assertEquals("", entry2.getGroupName());

TarArchiveEntry entry3 = in.getNextTarEntry();
Assert.assertEquals(0, entry3.getLongUserId());
Assert.assertEquals(0, entry3.getLongGroupId());
Assert.assertEquals("", entry3.getUserName());
Assert.assertEquals("", entry3.getGroupName());

TarArchiveEntry entry4 = in.getNextTarEntry();
Assert.assertEquals(333, entry4.getLongUserId());
Assert.assertEquals(0, entry4.getLongGroupId());
Assert.assertEquals("", entry4.getUserName());
Assert.assertEquals("", entry4.getGroupName());

TarArchiveEntry entry5 = in.getNextTarEntry();
Assert.assertEquals(0, entry5.getLongUserId());
Assert.assertEquals(555, entry5.getLongGroupId());
Assert.assertEquals("", entry5.getUserName());
Assert.assertEquals("", entry5.getGroupName());

TarArchiveEntry entry6 = in.getNextTarEntry();
Assert.assertEquals(333, entry6.getLongUserId());
Assert.assertEquals(555, entry6.getLongGroupId());
Assert.assertEquals("", entry6.getUserName());
Assert.assertEquals("", entry6.getGroupName());

TarArchiveEntry entry7 = in.getNextTarEntry();
Assert.assertEquals(0, entry7.getLongUserId());
Assert.assertEquals(0, entry7.getLongGroupId());
Assert.assertEquals("user", entry7.getUserName());
Assert.assertEquals("", entry7.getGroupName());

TarArchiveEntry entry8 = in.getNextTarEntry();
Assert.assertEquals(0, entry8.getLongUserId());
Assert.assertEquals(0, entry8.getLongGroupId());
Assert.assertEquals("", entry8.getUserName());
Assert.assertEquals("group", entry8.getGroupName());

TarArchiveEntry entry9 = in.getNextTarEntry();
Assert.assertEquals(0, entry9.getLongUserId());
Assert.assertEquals(0, entry9.getLongGroupId());
Assert.assertEquals("user", entry9.getUserName());
Assert.assertEquals("group", entry9.getGroupName());
}
}

private static Path createFile(Path root, String filename, String content, long modificationTime)
throws IOException {
Path newFile =
Files.write(
root.resolve(filename),
Expand Down
2 changes: 2 additions & 0 deletions jib-gradle-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Invalidates Jib's local application layer cache (`<project root>/build/jib-cache` by default) due to changes to caching mechanism. (In other words, the local cache generated by old Jib versions is incompatible with this version.) ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))
chanseokoh marked this conversation as resolved.
Show resolved Hide resolved

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down
2 changes: 1 addition & 1 deletion jib-gradle-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ Property | Type | Default | Description
`jib.httpTimeout` | `int` | `20000` | HTTP connection/read timeout for registry interactions, in milliseconds. Use a value of `0` for an infinite timeout.
`jib.useOnlyProjectCache` | `boolean` | `false` | If set to true, Jib does not share a cache between different Maven projects.
`jib.baseImageCache` | `File` | *Platform-dependent*\*\*\* | Sets the directory to use for caching base image layers. This cache can (and should) be shared between multiple images.
`jib.applicationCache` | `File` | `[project dir]/target/jib-cache` | Sets the directory to use for caching application layers. This cache can be shared between multiple images.
`jib.applicationCache` | `File` | `[project dir]/build/jib-cache` | Sets the directory to use for caching application layers. This cache can be shared between multiple images.
`jib.console` | `String` | *None* | If set to `plain`, Jib will print plaintext log messages rather than display a progress bar during the build.

*\* If you configure `args` while `entrypoint` is set to `'INHERIT'`, the configured `args` value will take precedence over the CMD propagated from the base image.*
Expand Down
2 changes: 2 additions & 0 deletions jib-maven-plugin/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ All notable changes to this project will be documented in this file.

### Changed

- Invalidates Jib's local application layer cache (`<project root>/target/jib-cache` by default) due to changes to caching mechanism. (In other words, the local cache generated by old Jib versions is incompatible with this version.) ([#2499](https://github.com/GoogleContainerTools/jib/pull/2499))

### Fixed

- Fixed authentication failure with Azure Container Registry when using an identity token defined in the `auths` section of Docker config (`~/.docker/config.json`). ([#2488](https://github.com/GoogleContainerTools/jib/pull/2488))
Expand Down